/// 輪詢
// 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
}
複製代碼
/// 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)
})
複製代碼