Promise.resolve(x)与new Promise(res=>res(x))区别及async/await代码转换

1,374 阅读21分钟

下面的内容建议了解nodejs事件循环promise.then原理后再看效果更好,推荐

Promise.resolve(x)与new Promise(resove=>resolve(x))

本文主要关于 Promise.resolve(x) 与 new Promise(r=>r(x)) 传入几种不同类型的参数, 二者处理的差异性。 产生差异性的原因是由于PromiseResolveThenableJob的处理机制,同时拓展至async函数的await操作实际原理。

1. Promise.resolve(简单值) 与 new Promise(r=>r(简单值))(非Promise实例与非Thenable对象为简单值)

代码1

new Promise(resolve => resolve())               // 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

学习过nodejs事件循环的小伙伴应该知道,结果为交替执行,这里面没有体现出差异,简单写执行过程

  1. 将new Promise做为同步代码执行,并执行内部函数resolve(),resolve参数为普通值时,可以认为只是将promise的状态改为fulfilled,然后执行到第2行then,then是异步函数,将then里面的回调函数 _ => console.log('then1') 放入微任务队列中,我们称为then1,此时微任务队列为 【then1】
  2. 执行第5行Promise.resolve(1),当作同步代码,只是将1改为promise并将状态改为fulfilled,然后执行到第6行then,then是异步函数,将then里面的回调函数 _ => console.log('resolve_then1') 放入微任务队列中,我们称为resolve_then1,此时微任务队列为 【then1,resolve_then1】
  3. 同步代码执行完毕,执行微任务队列中的微任务,取出微任务then1,执行,打印then1,然后执行到第3行then,then是异步函数,将then里面的回调函数 _ => console.log('then2') 放入微任务队列中,我们称为then2,此时微任务队列为 【resolve_then1,then2】
  4. 取出微任务resolve_then1,执行,打印resolve_then1,然后执行到第7行then,then是异步函数,将then里面的回调函数 _ => console.log('resolve_then2') 放入微任务队列中,我们称为resolve_then2,此时微任务队列为 【then2,resolve_then2】
  5. 取出微任务then2,执行,打印then2,然后执行到第4行then,then是异步函数,将then里面的回调函数 _ => console.log('then3') 放入微任务队列中,我们称为then3,此时微任务队列为 【resolve_then2,then3】
  6. 取出微任务resolve_then2,执行,打印resolve_then2,然后执行到第8行then,then是异步函数,将then里面的回调函数 _ => console.log('resolve_then3') 放入微任务队列中,我们称为resolve_then3,此时微任务队列为 【then3,resolve_then3】
  7. 取出微任务then3,执行,打印then3,上面函数执行完毕,此时微任务队列为 【resolve_then3】
  8. 取出微任务resolve_then3,执行,打印resolve_then3,下面函数也执行完毕,此时微任务队列为空 【】 ,执行完毕

结论:参数为普通值时,Promise.resolve(x)与new Promise(res=>res(x))没有差异

2. Promise.resolve(Promise实例)与new Promise(r=>r(Promise实例))

代码2

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.resolve在最外层就相当于修改返回值为promise,如果放在resolve中或者then中的return返回Promise.resolve,就会按照两个时序多出,效果同new Promise(r => r())。代码如下

new Promise(r => r(new Promise(r => r())))      // 1
    .then(_ => console.log('then1'))             // 2
    .then(_ => console.log('then2'))             // 3
    .then(_ => console.log('then3'))             // 4
new Promise(r => r(Promise.resolve()))
    .then(_ => console.log('resolve_then1'))	// 6
    .then(_ => console.log('resolve_then2'))	// 7
    .then(_ => console.log('resolve_then3'))
// then1 resolve_then1 then2 resolve_then2 then3 resolve_then3

言归正传: 当传入参数为一个Promise实例的时候,打印顺序和传入简单值时候出现了差异

  • Promise.resolve(Promise实例): 传入Promise实例的时候会原封不动的返回该Promise实例,无异步微任务。
  • new Promise(r=>r(Promise实例)): 传入Promise实例的时候,new Promise(r => r(Promise实例)) 将会分成两个异步微任务操作,执行的过程与promise.then原理类似,我们称这两个微任务为1.promiseResolveThenableJobTask;2.Promise2.fulfilled(Promise2指的是里面的promise实例)。从容易理解的角度来说,我将这两个异步操作当成是一个then和一个将值传递到外面的过程,这样改写代码执行顺序也是一样的。代码如下
// 原代码
let p1 = new Promise(resolve => resolve(new Promise(res=>{res()})))
.then(()=>{console.log('原')})
// 改写后代码
let p2 = new Promise((resolve)=>{
    resolve(new Promise(res=>{
        res()
    }).then((data)=>{
        console.log(data)
    }))
}).then(()=>{
    console.log('改')
})

其实改写后的代码执行效果和原代码一样,相当于将隐藏的异步函数展示出来,其实这个原理我在promise.then原理中说过,这里一共两个then,源代码只写了一个then,最里面的then没有写,但是最里面的then不管写不写都默认是有的,所以会多两个异步操作(一个里面的then,一个向外传值),如果再嵌套一层new Promise且还是只写最外层then,那就少了两个then,这种情况下,默认两个then,传值合并为一个,所以第二层多一个异步操作

下面我们来解释一下代码2

  1. 原理角度讲解
  2. 修改代码,个人总结角度讲解
原理角度讲解

注意:

  • Promise2.fulfilled:Promise2指的是里面的promise实例
  • 微任务命名:由then+打印值

1) 执行第一个new Promise(r => r(new Promise(r => r())))发现外层是new Promise(r=>r(Promise实例))的形式,会存在两个隐形的异步事件(一个最内层then,一个向外传值),将第一个异步事件promiseResolveThenableJobTask放入微任务队列,此时微任务队列为 【promiseResolveThenableJobTask】

2)执行到第五行Promise.resolve(new Promise(r => r())),Promise.resolve作用:情况1:将非promise参数,转为promise并将状态转为fulfilled;情况2:如果参数就是promise,保持不变,换句话说,有没有Promise.resolve都可以,第五行显然是第二种情况。这个转换状态的操作可以看成是同步代码,这里可以去掉外层Promise.resolve()理解,然后执行到第6行,遇到then是异步代码,放入微任务队列中我们称为resolve_then1,此时微任务队列为 【promiseResolveThenableJobTask,resolve_then1】

3)同步任务执行完毕,取出第一个微任务队列promiseResolveThenableJobTask执行,又遇到了Promise2.fulfilled异步函数,将Promise2.fulfilled放入微任务队列,此时微任务队列为 【resolve_then1,Promise2.fulfilled】

4)取出一个微任务队列resolve_then1执行,打印resolve_then1又遇到了下一个then是异步代码,放入微任务队列中我们称为resolve_then2,此时微任务队列为 【Promise2.fulfilled,resolve_then2】

5)取出一个微任务队列Promise2.fulfilled执行,然后又遇到了下一个then是异步代码,放入微任务队列中我们称为then1,此时微任务队列为 【resolve_then2,then1】

6)取出一个微任务队列resolve_then2执行,打印resolve_then2,然后又遇到了下一个then是异步代码,放入微任务队列中我们称为resolve_then3,此时微任务队列为 【then1,resolve_then3】

7)取出一个微任务队列then1执行,打印then1,然后又遇到了下一个then是异步代码,放入微任务队列中我们称为then2,此时微任务队列为 【resolve_then3,then2】

8)取出一个微任务队列resolve_then3执行,打印resolve_then3,下面函数整体执行完成,此时微任务队列为 【then2】

9)取出一个微任务队列then2执行,打印then2,然后又遇到了下一个then是异步代码,放入微任务队列中我们称为then3,此时微任务队列为 【then3】

10)取出一个微任务队列then3执行,打印then3,全部代码执行完毕,此时微任务队列为 【】

修改代码,个人总结角度讲解

代码修改为下面形式

new Promise(r => r(new Promise(r => {
    console.log('---')    // 为了证明是同步代码
                r()
            })        // 1步
        .then((data)=>{                         // 3步
            console.log('隐藏异步任务1')
            return data                         // 5步
        })))      
   .then(_ => console.log('then1'))             // 7步
   .then(_ => console.log('then2'))             // 9步
   .then(_ => console.log('then3'))             // 10步

Promise.resolve(new Promise(r => {
    console.log('===')   // 为了证明是同步代码
                r()
            }))		// 2步
   .then(_ => console.log('resolve_then1'))	// 4步
   .then(_ => console.log('resolve_then2'))	// 6步
   .then(_ => console.log('resolve_then3'))	// 8步
   console.log('+++')    // 同步代码

注意:

  • 微任务命名:由then+打印值,两个异常异步用汉字代表
  • 第几步:解释中提到的第几步根据后面注释来说,代表正在说这一行

1)new Promise本身可以看作同步代码,到第1步可以看为同步,所以首先打印---,然后遇到第3步的then,then是异步代码,放入微任务队列,此时微任务队列为:【隐藏异步任务1】

2)运行到第二步,Promise.resolve(new Promise(r => r())),Promise.resolve()参数是promise,不做任何处理,可以看作同步代码,所以打印===,然后遇到第4步的then,then是异步代码,放入微任务队列,此时微任务队列为:【隐藏异步任务1,resolve_then1】

3)执行同步代码打印+++,同步代码执行完毕,取出微任务事件隐藏异步任务1执行 打印隐藏异步任务1,然后将内部数据传递到then外部,这是个异步事件,我们称它为传递数据到外部,此时微任务队列为:【resolve_then1,传递数据到外部】

4)取出微任务事件resolve_then1执行 resolve_then1,然后遇到第6步的then,then是异步代码,放入微任务队列,此时微任务队列为:【传递数据到外部, resolve_then2】

5)取出微任务事件传递数据到外部执行,然后遇到第7步的then,then是异步代码,放入微任务队列,此时微任务队列为:【resolve_then2, then1】

6)取出微任务事件resolve_then2执行,打印resolve_then2,然后遇到第8步的then,then是异步代码,放入微任务队列,此时微任务队列为:【then1,resolve_then3】

7)取出微任务事件then1执行,打印then1,然后遇到第9步的then,then是异步代码,放入微任务队列,此时微任务队列为:【resolve_then3,then2】

8)取出微任务事件resolve_then3执行,打印resolve_then3 下面的函数执行完成,此时微任务队列为:【then2】

9)取出微任务事件then2执行,打印then2,然后遇到第10步的then,then是异步代码,放入微任务队列,此时微任务队列为:【then3】

9)取出微任务事件then3执行,打印then3,全部代码执行完毕,此时微任务队列为:【】

3. Promise.resolve(thenable对象) 与 new Promise(r=>r(thenable对象))

这里可能会有疑惑,为什么new Promise(r => r(new Promise(r =>r().then()))加了里面的then,而Promise.resolve(new Promise(r => {r()}))里面r()后面没有加then呢,这里可以理解为Promise.resolve包裹promise实例,没有发挥它转换普通值为promise值的作用,这里将Promise.resolve去掉的效果一样,这里小编也不是很清楚了,Promise.resolve内部的处理机制

// **thenable对象:** 简而言之,具有then方法的函数或对象,如下thenable_Object。
const thenable_Object1 = { then(resolve, reject) { console.log('2'); resolve()} }  // -1
const thenable_Object = { then(resolve, reject) { console.log('22'); resolve()} }  // 0

new Promise(r => { console.log('then0'); r(thenable_Object1) })  // 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
new Promise(r=>{
    console.log('---')     //9
    r()
}).then(()=>{  
    console.log('===')//10
}).then(()=>{
    console.log('+++')//11
})
console.log('script_start');//12

关于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回调)。

下面我们来解释执行过程:

1)thenable_Object1和thenable_Object是两个对象定义,不执行,向下执行到1行,执行同步代码,打印then0,遇到thenable_Object1的then,异步函数,放入微任务队列,此时微任务队列为:【thenable_Object1的then】

2)执行到5行,Promise.resolve为同步任务,遇到thenable_Object的then,异步函数,放入微任务队列,此时微任务队列为:【thenable_Object1的then,thenable_Object的then】

3)执行到9行,new Promise本身为同步任务,向下执行打印---,然后向下遇到了then,异步函数,放入微任务队列,此时微任务队列为:【thenable_Object1的then,thenable_Object的then,===】

4)执行到12行,同步任务,打印script_start,这一行的作用就是为了说明,上面1行的new Promise(r=>r())和5行的Promise.resolve()是同步任务,以后的都是异步任务了

5)取微任务thenable_Object1的then,执行打印2,将数据传出,遇到2行then,异步任务,放入微任务队列,此时微任务队列为:【thenable_Object的then,===,then1】

6)取微任务thenable_Object的then,执行打印22,将数据传出,遇到6行then,异步任务,放入微任务队列,此时微任务队列为:【===,then1,resolve_then1】

7)取微任务 ===,执行打印===,向下执行,遇到11行then,异步任务,放入微任务队列,此时微任务队列为:【then1,resolve_then1,+++】

8)取微任务 then1,执行打印then1,向下执行,遇到3行then,异步任务,放入微任务队列,此时微任务队列为:【resolve_then1,+++,then2】

9)取微任务 resolve_then1,执行打印resolve_then1,向下执行,遇到7行then,异步任务,放入微任务队列,此时微任务队列为:【+++,then2,resolve_then2】

10)取微任务 +++,执行打印+++,这个promise执行完毕,这里的打印是为了验证thenable对象作为参数时,只经历了1个异步任务,此时微任务队列为:【then2,resolve_then2】

11)取微任务 then2,执行打印then2,向下执行,遇到4行then,异步任务,放入微任务队列,此时微任务队列为:【resolve_then2,then3】

12)取微任务 resolve_then2,执行打印resolve_then2,向下执行,遇到8行then,异步任务,放入微任务队列,此时微任务队列为:【then3,resolve_then3】

13)取微任务 then3,执行打印then3,所在函数执行完毕,此时微任务队列为:【resolve_then3】

14)取微任务 resolve_then3,执行打印resolve_then3,所在函数执行完毕,此时微任务队列为:【】

Promise.resolve()做了什么

console.log(
    Promise.resolve(1)
)
// 执行结果:Promise { 1 }
console.log(
    Promise.resolve(new Promise((resolve, reject) => {
        resolve();
}))
)
// 执行结果:Promise { undefined }
console.log(
    Promise.resolve(new Promise((resolve, reject) => {
        // resolve();
}))
)
// 执行结果:Promise { <pending> }
const thenable_Object = { then(resolve, reject) { console.log('22'); resolve()} }  // 0
console.log(
    Promise.resolve(thenable_Object)
)
// 执行结果:22

不考虑reject情况

通过上面代码,我们可以总结出:

  1. 如果Promise.resolve(简单值):Promise.resolve作用就是将简单值转换为promise值,并将状态改为fulfilled
  2. 如果Promise.resolve(promise):Promise.resolve作用就是保持不动,即有没有Promise.resolve包裹作用一样。状态也是取决于里面的promise的状态
  3. 如果Promise.resolve(thenable对象):Promise.resolve作用就是将thenable对象转换为promise值,并将状态改为fulfilled,然后自动执行then方法

new Promise状态

console.log(
    new Promise(r=>r(1))
)
// 执行结果:Promise { 1 }
console.log(
    new Promise(r=>r()).then(()=>{
        return 1   // 虽然then返回的是简单值,但是会转换为promise,这才是then可以继续then的原因
    })
)
// 执行结果:Promise { <pending> }
console.log(
    new Promise(r=>r(new Promise(r=>r()).then()))
)
// 执行结果:Promise { <pending> }
console.log(
    new Promise(r=>r(Promise.resolve()))
)

通过上面代码,我们可以总结出:只有new Promise(r=>r(1)) r(简单值),整个new 的状态才是fulfilled,当r(promise)时,整个new 的状态是padding的

async函数await原理以及其在node -v10与node -v13差异

await到底做了什么

// 当前node环境 version-13
async function fn1() {      		
    console.log('start');	
    await fn2()
    console.log('end');	
 }
 function fn2() {            	
    Promise.resolve()	
        .then(_ => console.log('1'))    
        .then(_ => console.log('2'))    
        .then(_ => console.log('3'))     
    return undefined     
 }
 fn1()

async/await就是对Promise的改写,是为了让代码可读性更好,所以我们对上面的代码进行改写

改写后的代码如下:

// 当前node环境 version-13
async function fn1() {      		
    console.log('start');	
    // await fn2()
    // console.log('end');	
    Promise.resolve(fn2()).then(()=>{
        console.log('end');
    })
 }
function fn2() {            	
    Promise.resolve()	
        .then(_ => console.log('1'))    
        .then(_ => console.log('2'))    
        .then(_ => console.log('3'))     
    return undefined     
 }
 fn1()

理解事件循环的朋友应该可以根据对await进行转换的代码分析出执行顺序,此处不再赘述,如需要代码分析请留言。

显而易见,await做的事就是将其后面跟随的东西(fn2())的结果进行Promise.resolve返回一个Promise,同时await下一行往后的代码(// do sth ;console.log('end'); )全放在刚才resolve出来的Promise的then回调中执行,以此达到等待(异步操作返回结果)的功能。

node10 与 node13 await表现形式的差异

node 13中的await

注意:此处代码与前面代码唯一差异就是fn2现在是async函数

// 当前node环境 version-13
async function fn1() {      		
    console.log('start');	
    await fn2()
    console.log('end');	
 }
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');	
    // await fn2()
    // console.log('end');	
    Promise.resolve(fn2()).then(()=>{
        console.log('end');
    })
 }
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 

上面这种转换适用于node13以上版本的任何代码,不管fun2方法返回什么,比如返回嵌套了很多new promise实例,代码如下

async function fn2() {
    console.log("fun2")
    return new Promise(res=>{
        res(new Promise(res=>{
            res(new Promise((res)=>{
                res('fun2 微任务')
            }))
        }))
    })
}

但是,如果在fun1函数中展开写,改写为下面代码是不行的,下面代码和Promise.resolve(fn2()).then(()=>{ console.log('end'); })是不能对等的,虽然看上去好像没区别,具体原因小编还不清楚,

Promise.resolve(new Promise(res=>{
        res(new Promise(res=>{
            res(new Promise((res)=>{
                res('fun2 微任务')
            }))
        }))
    })) .then(()=>{
        console.log('end');
    })

所以说,这种改写对于fun2嵌套多层promise返回时,在代码读取时没有可取之处,其实10版本也存在类似的问题,下面会说

node 10中的await

// 当前node环境 version-10
async function fn1() {
    console.log('start');
    await fn2()
    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(_=>{
          	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版本的任何代码,不管fun2方法返回什么,比如返回嵌套了很多new promise实例,代码如下

async function fn2() {
    console.log("fun2")
    return new Promise(res=>{
        res(new Promise(res=>{
            res(new Promise((res)=>{
                res('fun2 微任务')
            }))
        }))
    })
}

但是,如果在fun1函数中展开写,改写为下面代码是不行的,下面代码和 new Promise(r=>r(fn2())) .then(_=>{ console.log('end'); })
})是不能对等的,虽然看上去好像没区别,具体原因小编还不清楚,

new Promise(r => r(
    new Promise(res => {
        res(new Promise(res => {
            res(new Promise((res) => {
                res('fun2 微任务')
            }))
        }))
    })
))
    .then(_ => {
        console.log('end');
    })   

所以说,这种改写对于fun2嵌套多层promise返回时,在代码读取时没有可取之处,虽然上述情况小编说不清楚但是,小编整理了调用async 方法返回不同值在node不同版本的区别和代码改写

举例说明不同

例子1:async 方法返回 非promise值 在node10/13的改写方式

console.log("script start")
new Promise((resolve) => {
    console.log("promise1")
    resolve('微任务1')
}).then((data) => { //第一个Promise加入微任务列表
    console.log(data)
})
async function fun1() {
    console.log("fun1")
    // let data = await fun2() //关键的地方,await后面的代码会阻塞 ,fun2执行完毕后,后面的代码类似于传入then()中的回调
    // console.log(data)
    // console.log("await堵塞")
    // 上面【三行】相当于下面代码
    // v13版本
    // 代码改写方式1
    // Promise.resolve(fun2())
    // .then((data)=>{
    //     console.log(data)
    //     console.log("await堵塞")
    // })
    // 代码改写方式2
    // new Promise(res=>{
    //     res('fun2 微任务')
    // }).then(data => {
    //             console.log(data)
    //             console.log("await堵塞")
    //         })
    // v10版本
    // 代码改写方式1
    // new Promise(r => r(fun2()))
    //     .then(data => {
    //         console.log(data)
    //         console.log("await堵塞")
    //     })
    // 代码改写方式2
    // new Promise(res=>{
    //     res(new Promise(res=>{
    //         res('fun2 微任务')
    //     }))
    // }).then(data => {
    //             console.log(data)
    //             console.log("await堵塞")
    //         })
}
setTimeout(() => {
    console.log("setTimeout 宏任务") //一个宏任务,加入宏任务队列
}, 0)
async function fun2() {
    console.log("fun2")
    return 'fun2 微任务'
}
fun1() //代码开始执行
new Promise((resolve) => {
    console.log("promise2")
    resolve("微任务2")
}).then((data) => { //promise状态已经fulfilled,直接加入微任务队列
    console.log(data)
}).then(() => { //promise状态已经fulfilled,直接加入微任务队列
    console.log(1)
}).then(() => { //promise状态已经fulfilled,直接加入微任务队列
    console.log(2)
}).then(() => { //promise状态已经fulfilled,直接加入微任务队列
    console.log(3)
}).then(() => { //promise状态已经fulfilled,直接加入微任务队列
    console.log(4)
}).then(() => { //promise状态已经fulfilled,直接加入微任务队列
    console.log(5)
})
console.log("同步end")

例子2:async 方法返回一层new promise在node10/13的改写方式

console.log("script start")
new Promise((resolve) => {
    console.log("promise1")
    resolve('微任务1')
}).then((data) => { //第一个Promise加入微任务列表
    console.log(data)
})
async function fun1() {
    console.log("fun1")
    // let data = await fun2() //关键的地方,await后面的代码会阻塞 ,fun2执行完毕后,后面的代码类似于传入then()中的回调
    // console.log(data)
    // console.log("await堵塞")
    // 上面【三行】相当于下面代码
    // v10 版本
    // 代码改写方式1
    // new Promise(r => r(fun2()))
    //     .then(data => {
    //         console.log(data)
    //         console.log("await堵塞")
    //     })
    // 代码改写方式2
    // new Promise(res=>{
    //     res(new Promise(res=>{
    //         res(new Promise(res=>{
    //             res('fun2 微任务')
    //         }))
    //     }))
    // }).then(data => {
    //             console.log(data)
    //             console.log("await堵塞")
    //         })
    // v13版本
    // 代码改写方式1
    // Promise.resolve(fun2())
    // .then((data)=>{
    //     console.log(data)
    //     console.log("await堵塞")
    // })
    // 代码改写方式2
    // Promise.resolve(new Promise((res)=>{
    //     res(new Promise((res)=>{
    //         res('fun2 微任务')
    //     }))
    // })).then((data)=>{
    //     console.log(data)
    //     console.log("await堵塞")
    // })
    // 代码改写方式3
    // new Promise((res)=>{
    //     res(new Promise((res)=>{
    //         res('fun2 微任务')
    //     }))
    // }).then((data)=>{
    //     console.log(data)
    //     console.log("await堵塞")
    // })
}
setTimeout(() => {
    console.log("setTimeout 宏任务") //一个宏任务,加入宏任务队列
}, 0)
async function fun2() {
    console.log("fun2")
    return new Promise((res)=>{
        res('fun2 微任务')
    })
}
fun1() //代码开始执行
new Promise((resolve) => {
    console.log("promise2")
    resolve("微任务2")
}).then((data) => { //promise状态已经fulfilled,直接加入微任务队列
    console.log(data)
}).then(() => { //promise状态已经fulfilled,直接加入微任务队列
    console.log(1)
}).then(() => { //promise状态已经fulfilled,直接加入微任务队列
    console.log(2)
}).then(() => { //promise状态已经fulfilled,直接加入微任务队列
    console.log(3)
}).then(() => { //promise状态已经fulfilled,直接加入微任务队列
    console.log(4)
}).then(() => { //promise状态已经fulfilled,直接加入微任务队列
    console.log(5)
})
console.log("同步end")

对于1层以上的嵌套和1层结果一样

下面用表格说明

标题node13node10
return 非promise(参考例子1)多0个异步任务;'fun2 微任务'在微任务2之前输出多2个异步任务;'fun2 微任务'在1之后输出
return 一层new promise(参考例子2)多2个异步任务;'fun2 微任务'在1之后输出3个不是4个异步任务;'fun2 微任务'在2之后输出
return 一层以上new promise(参考例子2)多2个异步任务;'fun2 微任务'在1之后输出3个不是4个异步任务;'fun2 微任务'在2之后输出

总结

对于node13以上的版本 改写时,我们只要用下面两种即可

// async返回非promise时的改写
 new Promise(res=>{
        res('fun2 微任务')
    }).then(data => {
        console.log(data)
        console.log("await堵塞")
    })
// async返回1层或多层promise时的改写
new Promise((res)=>{
        res(new Promise((res)=>{
            res('fun2 微任务')
        }))
    }).then((data)=>{
        console.log(data)
        console.log("await堵塞")
    })

对于node10的版本 改写时,我们用下面两种即可

// async返回非promise时的改写
new Promise((res)=>{
        res(new Promise((res)=>{
            res('fun2 微任务')
        }))
    }).then((data)=>{
        console.log(data)
        console.log("await堵塞")
    })
// async返回1层或多层promise时的改写 ***注意多了3个异步任务,不是4个哦
new Promise(res => {
        res(new Promise(res => {
            res(new Promise(res => {
                res('fun2 微任务')
            }))
        }))
    }).then(data => {
        console.log(data)
        console.log("await堵塞")
    })

参考文章:juejin.cn/post/690489…