一道有意思并对你有帮助的Promise题

一道有意思的题

以下我的学习分析心路历程,以及我自己又多加了几道菜;希望对你有帮助

先上菜

new Promise((resolve, reject) => {
    console.log('promise1');
    resolve();
}).then(() => {
    console.log('then11');
    new Promise((resolve, reject) => {
        console.log('promise2');
        resolve();
    }).then(() => {
        console.log('then21');
    }).then(() => {
        console.log('then23');
    });
}).then(() => {
    console.log('then12');
});

分析第一道菜

  • 第一次看到我做错了,答案是
promise1
then11
promise2
then21
then12
then23
  • 我的疑惑就是then12为什么在then21then23之间,很奇怪。说明什么呢?我对Promise的内部实现还不了解,那只能去看源码了。在学习过程中,自己也尝试改变了几处,也贴上来吧,大家看看

看完后我的理解

先分析下面代码

new Promise((resolve, reject) => {
    console.log('promise1');
    resolve();
})
  • 第一步console.log('promise1'),这是第一个promise实例
  • 第二步resolve(),他是一个异步,放入异步队列中,取名异步1
  • 第三步this.status 状态是pending

接着执行下面代码

.then(() => {
    console.log('then11');
    new Promise((resolve, reject) => {
        console.log('promise2');
        resolve();
    }).then(() => {
        console.log('then21');
    }).then(() => {
        console.log('then23');
    });
})
  • 因为状态是pending,将then方法回调函数加入执行队列(一个数组)等待执行(专用来放then方法的数组),该then方法取名方法1

重点接着执行什么?

并不是执行.then(() => {console.log(then12)}),要记住的是then的参数方法执行时机是当前(属于自己的)promise状态改变才会执行,谁改变resolve或者rejectd的执行,那么这里then的promise哪里来,就是上面的方法1中来看他的return值

所以开始执行异步1(我都有取名的,看),第一个promise实例状态变为FULFILLED

  • 首先resolve()参数为undefind不是一个promise类型,所以执行执行队列(一个数组),即方法1,也就是第一个then`的参数
  • 因为状态改变所以开始执行方法1
() => {
    console.log('then11');
    new Promise((resolve, reject) => {
        console.log('promise2');
        resolve();   //新的resolve 取名异步2
    }).then(() => { 
        console.log('then21');
    }).then(() => {
        console.log('then23');
    });
}
  • 第一步打印console.log('then11');
  • 又新建了一个Promise,打印console.log('promise2');
  • resolve();又一个异步,放入异步队列中,取名异步2
  • 然后因为新的promise它的状态是pengding,所以() => {console.log('then21');}方法放入新的promise的执行队列的数组中(和上面一样专用来放then方法的数组)
  • 同理后面的then并不回执行,它需要等待新的resolve的执行,来改变状态执行then

重点2

  • 因为方法1的没有return,即return 一个undefined,但我们都知道then会默认返回一个return new Promise((resolve, reject) => {})对象,所以这时候他是执行了的一个异步操作resolve()取名异步3,
  • 所以有了这个异步3,这个returnpromise的状态为pending,所以then(() => {console.log(then12)})加入到(专用来放then方法的数组)的执行回调数组中

然后开始执行异步队列的函数,有两个异步2和异步3,先执行异步2,接下来的操作和重点2是一样的又会return new Promise((resolve, reject) => {}) ,又会有一个异步4resolve(),接着讲then方法放入数组中,等待resolve()改变promise状态来执行then方法

  • 所以在等待期间会执行异步3,然后打印console.log(then12)
  • 最后打印console.log(then23)

总结要点

  • then(func)执行时机是等待一个与它相关的promise的状态改变
  • then(func)中的func默认会return new Promise((resolve, reject) => {resolve()})用于下一个then(func)
  • 如果我们手动return 一个promise结果就会不同,看下面例子

再变个花样

new Promise((resolve, reject) => {
    console.log('promise1');
    resolve();      //异步1
}).then(() => {
    console.log('then11');
    return new Promise((resolve, reject) => {
        console.log('promise2');
        resolve();  //异步2  
    }).then(() => {
        
        console.log('then21');
        //默认resolve()  异步3
    }).then(() => {
        console.log('then23');
        //默认resolve()  异步4
    });
}).then(() => {
    console.log('then12');
});

分析

  • 看到一个then(func)中我们直接返回了一个promise,所以先加入第一异步2,并且要等待它相关的promise状态改变,但是它状态改变了,那就是等异步2的执行,一旦执行,接着就是() =>{console.log('then23'); //默认resolve() 异步4}的执行了,所以异步4先一步比异步5加入,也就先执行了,
  • 所以结果就是
promise1
then11
promise2
then21
then23
then12

我再来变个样

new Promise((resolve, reject) => {
    console.log('promise1');
    resolve();  //异步1
}).then(() => {
    console.log('then11');
    new Promise((resolve, reject) => {
        console.log('promise2');
        resolve();  //异步2
    }).then(() => {
        console.log('then21'); 
        //异步3
    }).then(() => {
        console.log('then23');
        //异步4
    });
    return Promise.resolve(1)  //异步5
}).then(() => {
    console.log('then12');
});

分析一下这几个异步就要能知道答案了

  • console.log('promise1');
  • 先加入异步1, 执行后输出console.log('then11'); console.log('promise2');
  • 在加入异步2, 再加入异步5
  • 先执行异步2, console.log('then21'); 并将加入异步4
  • 再执行异步5, 但这个异步和下面的then不相关,因为这边隐藏的会再下加入一个resolve()(即异步6)
  • 接着先执行异步4, 输出console.log('then23');
  • 接着先执行异步6, 输出console.log('then12');

你可能感兴趣的:(promise,javascript)