一道有意思並對你有幫助的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的內部實現還不瞭解,那隻能去看源碼了。在學習過程當中,本身也嘗試改變了幾處,也貼上來吧,你們看看

看完後個人理解

先分析下面代碼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方法this

  • 因此在等待期間會執行異步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');
相關文章
相關標籤/搜索