await原理 js_由 Promise 实现 async await 源码及原理分析

async-await

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 { }

// b

// i catch you 1 error

// 4 123

// Promise { '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 示意图

c1036a550945573dc6639785455da366.png


版权声明:本文为weixin_42510888原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。