由 Promise 实现 async await 源码及原理分析
Promise 参考上一篇博文 https://www.cnblogs.com/usmile/p/13347651.html
async-await
源码 https://github.com/lifaith/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 示意图