Promise 參考上一篇博文 https://www.cnblogs.com/usmile/p/13347651.html
async-await
源碼 https://github.com/lfp1024/promise
async-await
const _async = (func) => {
const p = new Promise((resolve, reject) => {
try {
const value = func()
if (((typeof value === 'object' && value !== null) || typeof value === 'function') &&
typeof value.then === 'function') {
Promise.resolve(value).then(resolve, reject)
} else {
resolve(value)
}
} catch (error) {
reject(error)
}
})
return p
}
const _await = (arg) => (onResolved, onRejected) => {
const innerPromise = onRejected ? Promise.resolve(arg).catch(onRejected).then(onResolved, onRejected)
: Promise.resolve(arg).then(onResolved, onRejected)
return innerPromise
}
module.exports = {
_async,
_await
}
async-await-comment
/*
async await 是promise的語法糖,優化promise的then鏈寫法,用同步的方式編寫異步代碼
async 異步函數(包含函數聲明、函數表達式、Lambda表達式[箭頭函數]等使用形式)
1. 返回一個 Promise 對象
1. 直接返回成功或失敗狀態的promise
1.1 函數體沒有await,return 一個普通值(非promise和thenable對象,默認undefined),async立刻返回一個成功狀態的promise,值為該普通值
1.2 函數體中沒有await或在await之前,拋出異常,async立即返回失敗的promise,值為失敗原因,異常不會拋到函數體外面影響外面代碼的執行
2. 先返回PENDING狀態的promise,然后再異步修改狀態
2.1 函數體中有await,在await獲取到值之前,async先返回 PENDING 狀態的promise,然后再根據await后面表達式返回promise的狀態而改變
2.2 如果await后面表達式返回的promise失敗且未捕獲異常,則async返回的promise失敗,失敗原因是表達式返回promise的失敗原因
2. 最外層async無法用 await 獲取其返回值,應該用原來的方式:then() 鏈來處理async返回的 promise 對象
await 表達式(包含promise對象,普通函數調用、基本值類型)
1. 【等待】表達式的【返回值】
1.1 如果表達式的值是promise對象,則等待promise返回(調用其then方法,異步獲取),並將其返回值作為await表達式的值
1.2 如果表達式的值不是promise對象,則通過 Promise.resolve 轉換為 promise對象,等待其返回,並將其返回值作為await表達式的值
2. await相當於調用后面表達式返回promise的then方法,異步(等待)獲取其返回值。即 await<==>promise.then
2.1 不管代碼中是否用到await表達式返回值,await都會去獲取(調用其then方法),在獲取到之前,async會返回一個 PENDING 狀態的promise。
2.2 函數體中await表達式后面的代碼相當於promise.then方法的第一個回調(onResolved),可以拿到表達式返回promise的返回值(即await表達式返回值)
因此await會阻塞函數體中后面代碼的執行(異步執行then的回調),但是表達式是同步執行的【因此await操作符只能出現在async異步函數中】
如果await表達式后面沒有代碼,則相當於then的第一個回調不傳,使用默認回調函數(v=>v)
2.3 調用promise.then方法的第二個回調默認不傳,使用默認回調函數(err=>{throw err})
因此當表達式報錯或返回失敗的promise,await會將該異常拋出到函數體中,可以(需要)通過try-catch捕獲異常
如果await promise調用了其catch方法,則不會拋出,因為catch也返回一個promise,相當於await調用catch返回promise的then方法
第二個回調傳遞方式:
1. 當表達式返回值是promise且調用其catch方法時,相當於傳遞了第二個回調(即catch方法中的回調)
2. 當await表達式放在try-catch中時,相當於傳遞了第二個回調(即catch方法中的回調)
*/
//===================自己實現async、await=====================
const u = require("../utils")
const log = u.debugGenerator(__filename)
/**
*@param func: 異步函數
*/
const _async = (func) => {
const p = new Promise((resolve, reject) => {
try {
const value = func()
if (((typeof value === 'object' && value !== null) || typeof value === 'function') &&
typeof value.then === 'function') {
log.debug("===value is a thenable obj===")
// promise 或 thenable
// 1. 如果返回一個thenable對象,這里需要用Promise.resolve轉為promise,以達到異步調用thenable.then的效果
// 2. 如果返回一個promise,Promise.resolve原樣返回,無影響。因此統一用Promise.resolve轉為promise
// 2.1 如果函數體有await,則這里相當於_await返回的 innerPromise.then(resolve,reject)
Promise.resolve(value).then(resolve, reject)
setTimeout(() => {
log.info("異步 async 的 p =", p)
}, 0);
} else {
// 普通值(undefined、123、"123"、{then:123}) 立即返回成功的promise
resolve(value)
}
log.debug("========async return==========")
} catch (error) {
log.debug("===value is not a thenable obj===")
// 3. 如果函數體中同步代碼報錯,則返回失敗的promise,值為失敗原因
log.error("========async catch===========\n", error)
reject(error)
}
})
log.info("同步 async 的 p =", p)
return p
}
/**
* @param arg: await后面的表達式
* @param onResolved: 函數體中await表達式下面的代碼
* @param onRejected: 函數體中的catch回調函數
*/
// 注意變形之后需要加 return _await ...
// 多個await,變形后會嵌套調用_await,這里用計數器n區分
// await promise自帶catch或被try-catch包裹,相當於將catch的回調函數作為 onRejected 傳入
const _await = (() => {
let n = 0
return (arg) => {
n++
return (onResolved, onRejected) => {
// Promise.resolve(arg) 返回失敗,執行 onRejected (如果沒有傳遞則執行then的默認失敗回調,innerPromise失敗)
// Promise.resolve(arg) 返回成功,執行 onResolved
// onResolved 的執行結果決定then返回innerPromise的狀態,從而決定async返回promise的狀態
// onResolved 拋異常,then內部會捕獲,返回innerPromise失敗,async返回promise失敗
let innerPromise = onRejected ? Promise.resolve(arg).catch(onRejected).then(onResolved, onRejected)
: Promise.resolve(arg).then(onResolved, onRejected)
setTimeout(((n) => {
return () => {
log.info('異步 then-' + n + ' 的 p =', innerPromise)
}
})(n), 0);
log.info('同步 then-' + n + ' 的 p =', innerPromise)
return innerPromise
}
}
})()
module.exports = {
_async,
_await
}
/*
// 傳統promise和async-await編輯器自動轉換
//catch方法轉換為try-catch
function f() {
return new Promise((res, rej) => {
setTimeout(() => {
rej('err')
}, 1000);
}).then(data => {
console.log(data)
}).catch(err => {
console.log(err)
})
}
async function f() {
try {
const data = await new Promise((res, rej) => {
setTimeout(() => {
rej('err');
}, 1000);
});
console.log(data);
}
catch (err) {
console.log(err);
}
}
//then的第二個回調和catch方法都轉換為try-catch
function f() {
return new Promise((res, rej) => {
setTimeout(() => {
rej('err')
}, 1000);
}).then(data => {
console.log(data)
}, e => {
console.log(e)
}).catch(err => {
console.log(err)
})
}
async function f() {
try {
try {
const data = await new Promise((res, rej) => {
setTimeout(() => {
rej('err')
}, 1000)
})
console.log(data)
}
catch (e) {
console.log(e)
}
}
catch (err) {
console.log(err)
}
}
//多個await
function f() {
return new Promise((res, rej) => {
setTimeout(() => {
rej('err')
}, 1000);
}).then(data => {
return new Promise((res, rej) => {
res("suc")
}).then(data => {
console.log(data)
})
}).catch(err => {
console.log(err)
})
}
async function f() {
try {
const data = await new Promise((res, rej) => {
setTimeout(() => {
rej('err')
}, 1000)
})
const data_1 = await new Promise((res, rej) => {
res("suc")
})
console.log(data_1)
}
catch (err) {
console.log(err)
}
}
*/
測試
await promise.catch
- await 后面promise自帶catch方法,則失敗或拋異常會被自己的catch捕獲,不影響async函數體中后面代碼的執行
async function f() {
console.log("1")
// await 異步獲取返回值
const r = await new Promise((res, rej) => {
console.log("2")
rej("1 error")
console.log("3")
}).catch(err => {
console.log('i catch you', err)
return 123 // catch 捕獲異常,await不拋出,await表達式的值由catch的返回值決定
})
await new Promise((res, rej) => {
console.log("4",r)
rej("2 error")
})
console.log("res = ", r)
}
console.log("a")
let p = f()
console.log(p)
console.log("b")
setTimeout(() => {
console.log(p)
}, 0);
// 輸出
// a
// 1
// 2
// 3
// Promise { <pending> }
// b
// i catch you 1 error
// 4 123
// Promise { <rejected> '2 error' }
// 變形
console.log("a")
let p = _async(function f() {
console.log("1")
return _await(new Promise((res, rej) => {
console.log("2")
rej("1 error")
console.log("3")
}))((r) => {
return _await(new Promise((res, rej) => {
console.log("4", r)
rej("2 error")
}))(() => {
console.log("res = ", r)
})
// catch 回調作為 onRejected 傳入
}, (err) => {
console.log('i catch you', err)
return 123
})
})
console.log(p)
console.log("b")
setTimeout(() => {
console.log(p)
}, 0);
轉變為自己實現的 _async 和 _await 示意圖