Promise.resolve(x)与new Promise(r=>r(x))
本文主要关于 Promise.resolve(x) 与 new Promise(r=>r(x)) 传入几种不同类型的参数 x, 二者处理的差异性。 产生差异性的原因是由于PromiseResolveThenableJob的处理机制,同时拓展至async函数的await操作实际原理。
1,Promise.resolve(简单值) 与 new Promise(r=>r(简单值))(非Promise实例与非Thenable对象为简单值)
new Promise(r => r()) // 1
.then(_ => console.log('then1')) // 2
.then(_ => console.log('then2')) // 3
.then(_ => console.log('then3')) // 4
Promise.resolve(1) // 5
.then(_ => console.log('resolve_then1')) // 6
.then(_ => console.log('resolve_then2')) // 7
.then(_ => console.log('resolve_then3')) // 8
// 打印结果:
// then1
// resolve_then1
// then2
// resolve_then2
// then3
// resolve_then3
执行顺序过程:
-
1 , 执行代码,首先执行到第2行出现then回调,于是微任务队列放入then1微任务(此处命名根据其打印数据来,此处打印数据为"then1",所以叫then1微任务),继续执行同步代码。
此时微任务队列[then1微任务]
打印结果: -
2 ,同步代码执行到第5行,此处Promise.resolve(1)返回一个值为1的Promise对象,继续执行第6行发现resolve_then1微任务,放入微任务队列,至此同步代码执行完毕。
此时微任务队列[then1微任务,resolve_then1微任务]
打印结果: -
3,取出微任务队列第一个then1微任务执行,打印then1,then1微任务执行完毕到第3行发现then2微任务,放入微任务队列。
此时微任务队列[resolve_then1微任务,then2微任务]
打印结果:then1 -
4,继续取出微任务队列第一个resolve_then1微任务执行,打印resolve_then1,代码执行到第7行发现resolve_then2微任务,放入微任务队列。
此时微任务队列[then2微任务,resolve_then2微任务] 打印结果:then1,resolve_then1 -
5,继续取出微任务队列第一个then2微任务执行,打印then2,then2微任务执行完毕到第4行发现then3微任务,放入微任务队列。
此时微任务队列[resolve_then2微任务,then3微任务] 打印结果:then1,resolve_then1,then2 -
6,继续取出微任务队列第一个resolve_then2微任务执行,打印resolve_then2,代码执行到第8行发现resolve_then3微任务,放入微任务队列。
此时微任务队列[then3微任务,resolve_then3微任务]
打印结果:then1,resolve_then1,then2,resolve_then2 -
7,继续取出微任务队列第一个then3微任务执行,打印then3,then3微任务执行完毕,无任何微任务加入,取出resolve_then3微任务执行,打印resolve_then3,resolve_then3微任务执行完毕,无任何微任务加入,事件循环结束。
此时微任务队列[]
打印结果:then1,resolve_then1,then2,resolve_then2,then3,resolve_then3
总结:此处的Promise.resolve(简单值)与new Promise(r=>r(简单值))执行顺序相同。
2,Promise.resolve(Promise实例)与new Promise(r=>r(Promise实例))
new Promise(r => r(new Promise(r => r()))) // 1
.then(_ => console.log('then1')) // 2
.then(_ => console.log('then2')) // 3
.then(_ => console.log('then3')) // 4
Promise.resolve(new Promise(r => r())) // 5
.then(_ => console.log('resolve_then1')) // 6
.then(_ => console.log('resolve_then2')) // 7
.then(_ => console.log('resolve_then3')) // 8
// 打印结果:
// resolve_then1
// resolve_then2
// then1
// resolve_then3
// then2
// then3
当传入参数为一个Promise实例的时候,打印顺序与传入简单值的时候出现了差异。我们发现与传入简单值相比,二者区别只在于传入的是个Promise实例,那么问题应该就出在传入Promise实例中。
-
Promise.resolve(简单值): 传入简单值的时候会生成一个Promise对象。并且状态为成功,值为传入的该简单值。
-
new Promise(r => r(简单值)): 传入简单值的时候会生成一个Promise对象。并且状态为成功,值为传入的该简单值。
这个时候 二者对简单值的处理方式没有差异 -
Promise.resolve(Promise实例): 传入Promise实例的时候会原封不动的返回该Promise实例。
-
new Promise(r => r(Promise实例)) : 传入Promise实例的时候,new Promise(r => r(Promise实例)) 将会分成两步异步微任务操作,我们称呼为PromiseResolveThenableJob。见如下代码。
// 原代码
new Promise(r => r(Promise实例)).then(做其他事)
// 转换为进行PromiseResolveThenableJob处理代码
new Promise((resolve,reject)=>{
// Promise实例.then(PromiseResolveThenableJob①): 第一步获取Promise实例最终状态与值,这一步为异步操作(因为使用了Promise的.then,所以进行了异步动作,这一步标注为)
// (resolve_,reject_)(PromiseResolveThenableJob②) : 第二步使用resolve_函数与reject_函数同步Promise实例最终状态与值给外层的Promise,这个过程也是个异步操作
Promise实例.then(resolve_,reject_)
}).then(做其他事)
通过上面的的代码转换,我们可以看到,相较于Promise.resolve(Promise实例),new Promise(r => r(Promise实例)) 实则多进行了两步异步操作,就是代码中标注的PromiseResolveThenableJob①与PromiseResolveThenableJob②,有了这部分的代码转换,我们接下来继续分析二者的事件循环。
执行顺序过程:
- 1 , 执行代码第一行,发现是PromiseResolveThenableJob,于是先将PromiseResolveThenableJob①放入微任务队列。
此时微任务队列[PromiseResolveThenableJob①]
打印结果: - 2 , 继续执行同步代码第5行,第5行无任何异步操作,单纯的返回当前传入的Promise实例,继续执行至第6行,发现resolve_then1微任务,放入微任务队列。
此时微任务队列[PromiseResolveThenableJob①,resolve_then1微任务]
打印结果: - 3 , 当前无任何同步代码需要执行,取出微任务队列第一个微任务PromiseResolveThenableJob①执行,执行完毕发现PromiseResolveThenableJob②,放入任务队列。
此时微任务队列[resolve_then1微任务,PromiseResolveThenableJob②]
打印结果: - 4 ,取出微任务队列第一个微任务resolve_then1执行,打印resolve_then1,继续执行到代码第7行,发现resolve_then2微任务,放入任务队列。
此时微任务队列[PromiseResolveThenableJob②,resolve_then2微任务]
打印结果:resolve_then1 - 5 ,取出微任务队列第一个微任务PromiseResolveThenableJob②执行,将new Promise(r => r(Promise实例))中Promise实例的状态与值同步给外层new Promise,执行完毕,代码执行到第2行,发现then1微任务,放入任务队列。
此时微任务队列[resolve_then2微任务,then1微任务]
打印结果:resolve_then1 - 6 ,取出微任务队列第一个微任务,resolve_then2微任务执行,打印resolve_then2,代码继续执行到第8行,发现resolve_then3微任务,放入微任务队列。
此时微任务队列[then1微任务,resolve_then3微任务]
打印结果:resolve_then1,resolve_then2 - 7 ,取出微任务队列第一个微任务,then1微任务执行,打印then1,代码继续执行到第3行,发现then2微任务,放入微任务队列。
此时微任务队列[resolve_then3微任务,then2微任务]
打印结果:resolve_then1,resolve_then2,then1 - 8 ,取出微任务队列第一个微任务,resolve_then3微任务执行,打印resolve_then3,第8行执行完毕,无任何代码执行。
此时微任务队列[then2微任务]
打印结果:resolve_then1,resolve_then2,then1,resolve_then3 - 9 ,取出微任务队列第一个微任务,then2微任务执行,打印then2,第3行执行完毕,执行到第4行,发现then3微任务,放入微任务队列。
此时微任务队列[then3微任务]
打印结果:resolve_then1,resolve_then2,then1,resolve_then3,then2 - 10 ,取出微任务队列第一个微任务,then3微任务执行,打印then3,第4行执行完毕,无任何代码需要执行,整体代码执行完毕。
此时微任务队列[]
打印结果:resolve_then1,resolve_then2,then1,resolve_then3,then2,then3
总结:此处的Promise.resolve(Promise实例)与new Promise(r=>r(Promise实例))执行顺序不同。
3,Promise.resolve(thenable对象) 与 new Promise(r=>r(thenable对象))
// **thenable对象:** 简而言之,具有then方法的函数或对象,如下thenable_Object。
const thenable_Object = { then(resolve, reject) { console.log('2'); resolve()} } // 0
new Promise(r => { console.log('then0'); r(thenable_Object) }) // 1
.then(_ => console.log('then1')) // 2
.then(_ => console.log('then2')) // 3
.then(_ => console.log('then3')) // 4
Promise.resolve(thenable_Object) // 5
.then(_ => console.log('resolve_then1')) // 6
.then(_ => console.log('resolve_then2')) // 7
.then(_ => console.log('resolve_then3')) // 8
console.log('script_start'); // 9
// 打印结果
// then0
// script_start
// thenable
// thenable
// then1
// resolve_then1
// then2
// resolve_then2
// then3
// resolve_then3
关于thenable对象,我个人理解:
-
当传入参数为Promise实例的时候,Promise.resolve(Promise实例)过程为同步过程返回该Promise实例,无任何异步操作,new Promise(r=>r(Promise实例))会经过两个异步操作去同步状态然后处理下面的其他事情。
-
而当传入thenable对象的时候,根据代码我们发现Promise.resolve(thenable对象)与new Promise(r=>r(thenable对象))都进行了一个异步操作,我直接说结论:
Promise.resolve(thenable对象)与new Promise(r=>r(thenable对象))都会将当前的thenable对象转换为Promise对象,该过程是同步过程,然后执行其自定义的then方法,该过程为异步操作,then方法传入的两个参数为最终要返回的Promise实例的resolve与reject函数,通过这两个函数改变外层的Promise实例的状态,该过程只涉及一个异步操作(执行then回调)。下面是二者对thenable的处理伪代码
// new Promise(r => { console.log('then0'); r(thenable_Object) }),
// Promise.resolve(thenable_Object)
// 最终会进行如下转换
new Promise((resolve, reject) => {
// 将thenable_Object转化成Promise实例(thenable_Object_Promise),该过程为同步过程
let thenable_Object_Promise = thenable转化Promise函数(thenable_Object)
// 执行thenable_Object_Promise的then方法 完成对外层Promise状态的最终改变
thenable_Object_Promise.then(resolve, reject)
})
执行顺序过程:
-
1 同步代码执行至第2行,打印then0,发现resolve的是thenable对象,将thenable对象转化为Promise实例,执行thenable对象对象的then函数(thenable微任务①),此过程为异步,放入任务队列。
此时微任务队列:[thenable微任务①]
打印结果:then0, -
2 同步代码执行至第5行,发现Promise.resolve的是thenable对象,将thenable对象转化为Promise实例,执行thenable对象对象的then函数(thenable微任务②),此过程为异步,放入任务队列。
此时微任务队列:[thenable微任务①,thenable微任务②]
打印结果:then0, -
3 同步代码执行至第9行,打印script_start,同步代码执行完毕。
此时微任务队列:[thenable微任务①,thenable微任务②]
打印结果:then0,script_start -
4 取出任务队列第一个thenable微任务①,执行并打印thenable,完成对外层Promise(new Promise(r => { console.log('then0'); r(thenable_Object) }))状态的最终改变,继续执行代码至第2行发现then1微任务,加入任务队列。
此时微任务队列:[thenable微任务②,then1微任务]
打印结果:then0,script_start,thenable -
5 取出任务队列第一个thenable微任务②,执行并打印thenable,,完成对外层Promise(Promise.resolve(thenable_Object))状态的最终改变,继续执行代码至第6行发现resolve_then1微任务,加入任务队列。
此时微任务队列:[then1微任务,resolve_then1微任务]
打印结果:then0,script_start,thenable,thenable -
6 取出任务队列第一个then1微任务,执行并打印then1,代码执行至第3行,发现then2微任务,加入任务队列。
此时微任务队列:[resolve_then1微任务,then2微任务]
打印结果:then0,script_start,thenable,thenable,then1 -
7 取出任务队列第一个resolve_then1微任务,执行并打印resolve_then1,代码执行至第7行,发现resolve_then2微任务,加入任务队列。
此时微任务队列:[then2微任务,resolve_then2微任务]
打印结果:then0,script_start,thenable,thenable,then1,resolve_then1 -
8 取出任务队列第一个then2微任务,执行并打印then2,代码执行至第4行,发现then3微任务,加入任务队列。
此时微任务队列:[resolve_then2微任务,then3微任务]
打印结果:then0,script_start,thenable,thenable,then1,resolve_then1,then2 -
9 取出任务队列第一个resolve_then2微任务,执行并打印resolve_then2,代码执行至第8行,发现resolve_then3微任务,加入任务队列。
此时微任务队列:[then3微任务,resolve_then3微任务]
打印结果:then0,script_start,thenable,thenable,then1,resolve_then1,then2,resolve_then2 -
10 取出任务队列第一个then3微任务,执行并打印then3。
此时微任务队列:[resolve_then3微任务]
打印结果:then0,script_start,thenable,thenable,then1,resolve_then1,then2,resolve_then2,then3 -
11 取出任务队列最后一个resolve_then3微任务,执行并打印resolve_then3,代码执行完。
此时微任务队列:[]
打印结果:then0,script_start,thenable,thenable,then1,resolve_then1,then2,resolve_then2,then3,resolve_then3
总结:此处的Promise.resolve(thenable对象)与new Promise(r=>r(thenable对象))执行顺序相同。
async函数await原理以及其在node -v10与node -v13差异
await到底做了什么
// 当前node环境 version-13
async function fn1() {
console.log('start');
await fn2()
// do sth
console.log('end');
}
function fn2() {
Promise.resolve()
.then(_ => console.log('1'))
.then(_ => console.log('2'))
.then(_ => console.log('3'))
return undefined
}
fn1()
// 打印结果
// start
// 1
// end
// 2
// 3
为了更好的理解打印顺序,下面直接上对await进行转换之后的代码
// 当前node环境 version-13
async function fn1() {
console.log('start');
// await fn2()
// do sth
// console.log('end');
Promise.resolve(fn2())
.then(res=>{
// do sth
console.log('end');
})
}
function fn2() {
Promise.resolve()
.then(_ => console.log('1'))
.then(_ => console.log('2'))
.then(_ => console.log('3'))
return undefined
}
fn1()
// 打印结果
// start
// 1
// end
// 2
// 3
显而易见,await做的事就是将其后面跟随的东西(fn2())的结果进行Promise.resolve返回一个Promise,同时await下一行往后的代码(// do sth ;console.log('end'); )全放在刚才resolve出来的Promise的then回调中执行,以此达到等待(异步操作返回结果)的功能。
理解事件循环的朋友应该可以根据对await进行转换的代码分析出执行顺序,此处不再赘述,如需要代码分析请留言。
node10 与 node13 await表现形式的差异
node 13中的await
// 当前node环境 version-13
async function fn1() {
console.log('start');
await fn2()
// do sth
console.log('end');
}
// 注意 此处的fn2是个async函数
async function fn2() {
Promise.resolve()
.then(_ => console.log('1'))
.then(_ => console.log('2'))
.then(_ => console.log('3'))
return undefined
}
fn1()
// 打印结果
// start
// 1
// end
// 2
// 3
下面对await进行转换后的代码
// 当前node环境 version-13
async function fn1() {
console.log('start');
Promise.resolve(fn2()) .then(_=>{
// do sth
console.log('end');
})
}
// 注意 此处的fn2是个async函数
async function fn2() {
Promise.resolve()
.then(_ => console.log('1'))
.then(_ => console.log('2'))
.then(_ => console.log('3'))
return undefined
}
fn1()
// 打印结果
// start
// 1
// end
// 2
// 3
此处代码与前面代码唯一差异就是fn2现在是async函数,所以在 Promise.resolve(fn2())的时候,fn2()执行完毕返回的结果是个Promise实例(该实例最终结果为fn2中return的结果,如果没有写return,则相当于return undefined)。依赖于转换await之后的代码很容易知道其执行顺序
node 10中的await
// 当前node环境 version-10
async function fn1() {
console.log('start');
await fn2()
// do sth
console.log('end');
}
// 注意 此处的fn2是个async函数
async function fn2() {
Promise.resolve()
.then(_ => console.log('1'))
.then(_ => console.log('2'))
.then(_ => console.log('3'))
return undefined
}
fn1()
// 打印结果
// start
// 1
// 2
// 3
// end
我们发现node10中输出结果于node13中不一样,我们继续对node10中的await进行转换
// 当前node环境 version-10
async function fn1() {
console.log('start');
new Promise(r=>r(fn2()))
.then(_=>{
// do sth
console.log('end');
})
}
// 注意 此处的fn2是个async函数
async function fn2() {
Promise.resolve()
.then(_ => console.log('1'))
.then(_ => console.log('2'))
.then(_ => console.log('3'))
return undefined
}
fn1()
// 打印结果
// start
// 1
// 2
// 3
// end
我们发现,node10对await的处理与node13不一样,node10采用的是new Promise(r=>r(fn2()))的方式,而node13是Promise.resolve(fn2()) 的方式,继续分析,由于fn2是个async函数,最终返回结果是个Promise实例,所以node10相当于new Promise(r=>r(Promise实例)),node13则为Promise.resolve(Promise实例),回顾之前说的二者的差异性,所以node10在执行上会比node13多两个时序,这就是node10与node13上await表现的差异,但是我们按照最新的版本来,所以正常情况我们按照node13的版本结果为准。
3951