/// 轮询
// promise version
function fetchProtocol_promise(token) {
let counter = 0;
return new Promise((resolve, reject) => {
polling();
function polling() {
fetch().then(() => {
if (data.status === 200) {
switch (data.result.state) {
case 2:
resolve(getPreviewURL(data.result.url))
break
case 1:
if (counter++ > 20) {
reject("合同创建超时,请重新再试")
}
// fetch again
setTimeout(polling, 300)
break
case 3:
reject("合同创建失败")
break
}
}
})
}
});
}
/// async version
// 对比promise方式,会多了一个变量来管理状态成功
// 利用了promise里面的resolve接收的是一个promise,则会等待此promise的完成
async function fetch(token) {
let counter = 0;
return await polling();
async function polling() {
if (counter++ > 20) {
return [false, "合同创建超时,请重新再试"]
}
let data = await fetch()
if (data.status === 200) {
switch (data.result.state) {
case 2:
return [true, getPreviewURL(data.result.url)]
case 1:
// fetch again
return new Promise(resolve =>
setTimeout(function () {
// waiting for polling state change
resolve(polling());
}, 300)
);
case 3:
return [false, "合同创建失败"]
}
}
}
}
复制代码
/**
* timeout promise
*
* promise没有原生的超时的方法,得借用其他方法去处理
*
* 1. promise的两个最终状态, fulfilled、 rejected
*
* 2.下面借用Promise.race来处理超时
*
* Promise.race(iterable),当iterable参数里的任意一个子promise被成功或失败后,
* 父promise马上也会用子promise的成功返回值或失败详情作为参数调用父promise绑定的相应句柄,
* 并返回该promise对象。
*/
/// https://italonascimento.github.io/applying-a-timeout-to-your-promises/
const http = require('http')
let get = function (url) {
return new Promise((resolve, reject) => {
// 假装这里不支持timeout参数
http.get({
url,
}, res => {
res.on('data', d => {
resolve(d.toString())
})
})
})
}
/// promise timeout + promise.race
function promiseTimeout(promise, ms) {
let timeout = new Promise((resolve, reject) => {
setTimeout(function () {
reject('timeout')
}, ms)
})
return Promise.race([promise, timeout])
}
promiseTimeout(get('http://github.com'), 5).then(text => {
console.log({
text
})
}).catch(err => {
console.log({
err
})
})
复制代码
/**
* ======解决回调地狱的=========
*
* 常用的回调套回调,容易出现回调地狱,造成代码的可读性、维护性差
*
* 现借助promise来解决
*/
class Form {
constructor(num, errMsg) {
this.num = num
this.errMsg = errMsg
}
validator(callback) {
callback(this.num < .4)
}
}
let form1 = new Form(.3, 'im .3')
let form2 = new Form(.7, 'im .7')
let form3 = new Form(.6, 'im .6')
// 1. 回调地狱写法
// 回调之后还是回调,无穷无尽
form1.validator(valid => {
if (valid) {
form2.validator(valid => {
if (valid) {
form3.validator(valid => {
if (valid) {
console.log({
valid
})
} else {
console.log({
err: form3.errMsg
})
}
})
} else {
console.log({
err: form2.errMsg
})
}
})
} else {
console.log({
err: form1.errMsg
})
}
})
// 2. use async/await
// 把callback包装成promise,结合await同步写法
// 提高代码的可读性
let formSerialValidator = async function (forms) {
let valid = true
let errMsg = ''
// 用for来模拟表单的线性调用
for (let form of forms) {
// 利用await的同步写法
// 接收promise的resolve传值,或reject的传值
// 保持 resolve/reject 传值结构是一样的: tuple [boolean, string]
[valid, errMsg] = await promiseFactory(form)
// .catch(errMsg => {
// // 保持与resolve返回结果一致
// return [false, errMsg]
// })
if (!valid) {
break
}
}
return [valid, errMsg]
// 将回调包装成promise
function promiseFactory(form) {
return new Promise((resolve, reject) => {
form.validator(valid => {
// if (valid) {
resolve([valid, form.errMsg])
// }
// reject(form.errMsg)
})
})
}
}
formSerialValidator([form1, form2, form3]).then(([valid, errMsg]) => {
console.log({
valid,
errMsg
})
})
// 3. promise + reduce
// 利用then的链式调用
// a().then(() => new Promise()).then(() => new Promise()) 第一个then为reject时,整个链的状态就是reject
let reduceValidator = function (forms) {
// 用reduce生成校验的Promise chain
// reduce的初始initValue得注意下,是Promise.resolve()
// Promise.resolve()传递的是一个具体的值(undefined),所以状态为fulfilled,可直接使用then调用
// Promise then方法返回的promise,则等待该promise的返回
return forms.reduce((promise, form) => {
return promise.then($ => {
return new Promise((resolve, reject) => {
form.validator(valid => {
console.log(valid)
// resolve 只能有一个参数
if (valid) {
resolve(true)
}
reject(form.errMsg)
})
})
})
}, Promise.resolve())
}
reduceValidator([form1, form2, form3]).then(valid => {
console.log({
valid,
})
}).catch(errMsg => {
console.log({
errMsg
})
})
// Promise then方法返回的promise,则等待该promise的返回
Promise.resolve(new Promise((resolve, reject) => {
resolve(1)
})).then(res => {
console.log(res)
})
复制代码
/// 传统表单的校验
// 一般人的写法
// this.$message.error重复调用,不利于维护
function validator1() {
let msg = ''
if (fd.displayPosition === null) {
this.$message.error('请选择发送端')
// return false
} else if (fd.type === null) {
this.$message.error('请选择通知方式')
// return false
} else if (fd.peroid === undefined || JSON.stringify(fd.peroid) === '[null,null]') {
this.$message.error('请选择有效日期')
// return false
} else if (self.isShowNum && fd.showNum === null) {
msg = '请选择弹出次数'
// return false
}
this.$message.error(msg)
return true
}
// 二般人的写法
// 利用yield给暂停一下
// generator函数调用后生成一个Iterator对象,返回的done为true时结束
// Iterator: {
// next() {
// return {
// value: any,
// done: boolean
// }
// }
// }
//
// for..of 实现了Iterator接口,可以调用generator函数的生成对象
function validator2() {
function* check() {
if (fd.displayPosition === null) {
yield '请选择发送端'
}
if (fd.type === null) {
yield '请选择通知方式'
}
if (fd.peroid === undefined || JSON.stringify(fd.peroid) === '[null,null]') {
yield '请选择有效日期'
}
if (self.isShowNum && fd.showNum === null) {
yield '请选择弹出次数'
}
}
let iterator = check()
for (let msg of iterator) {
// if (msg !== undefined) {
this.$message.error(msg)
return false
// }
}
return true
}
复制代码
如下面的代码所示,执行Success
代码条件有两处,在上面的写法里,这两处分开书写,代码没有复用 利用promise的resolve就可以复用了,如第二个例子所示
if (condition1) {
promise().then(() => {
// do Success code here
}).catch(() => {
// do Fail code here
})
} else {
// do Success code here
}
复制代码
new Promise((resolve, reject) => {
if (condition1) {
promise().then(resolve).catch(reject)
} else {
resolve()
}
}).then(() => {
// do Success code here
}).catch(() => {
// do Fail code here
})
复制代码
/// 1. promise内部的错误,不会中断外部的执行
new Promise((resolve, reject) => {
throw Error('promise')
console.log(1)
})
console.log('after promise error')
// 可使用try-catch或Promise.prototype.catch处理
new Promise((resolve, reject) => {
try {
throw Error('promise')
} catch (err) {
console.log(err)
}
})
console.log('after promise error')
// 与上面的捕获错误的方法对比,throw Error后面的代码将无法执行
new Promise((resolve, reject) => {
throw Error('promise')
console.log('after inner error')
})
.catch(err => {
console.log(err)
// return 'form catch'
throw Error('from catch')
})
.catch(res => {
console.log(res)
})
console.log('after promise error')
/// 2. async函数的错误处理
// 处理await返回的错误,promise不捕获,则留给async函数处理
// promise前面加await与不加的区别
// 观察下面3种情况:
// 1. 内部promise错误不处理
// 2. 内部promise加上catch
// 3. 内部promise接上await
async function usePromiseCatch() {
new Promise((resolve, reject) => {
throw Error('throw')
console.log(330)
})
// .catch(err => {
// console.log(err)
// })
console.log('continue')
}
usePromiseCatch().catch(err => {
console.log('in async catch', err)
})
复制代码