Promise介紹--異步篇

這部份內容源於知乎上的一個提問javascript

setTimeout(function(){console.log(4)},0);
new Promise(function(resolve){
    console.log(1)
    for( var i=0 ; i<10000 ; i++ ){
        i==9999 && resolve()
    }
    console.log(2)
}).then(function(){
    console.log(5)
});
console.log(3);

// 1
// 2
// 3
// 5
// 4

以前咱們說過then方法添加的回調函數都是異步執行的,因此按照咱們正常的認知,結果應該是12345,由於4是先添加到異步隊列,而5在以後添加到異步隊列。java

知乎的問題也有何幻大神詳細的講解。這裏我就簡單的說一下吧。ajax

咱們都知道javascript是單線程的,也就是說,一個時間只能作一件事。因此,全部的任務都要按照必定的順序排隊,而後一個一個執行。若是全部的任務都是同步的,那就沒有什麼問題,代碼按照從前到後的順序依次執行就能夠了,但咱們實際工做過程當中,不免會有一些操做須要異步執行——好比事件,好比ajax,好比setTimeoutchrome

因此,瀏覽器會維護一個任務隊列(task queue),任務隊列是先進先出的,也就是說,先進入任務隊列的會先執行。當主線程任務執行完畢,就會查看任務隊列中有沒有新任務,若是有,則把第一個任務放到主線程中執行,以此循環往復,這個過程也就是Event loopspromise

我以前也一直都覺得瀏覽器中只有一個任務隊列,看到這個問題後才知道。原來瀏覽器中的任務隊列不止一個,且優先級也不一樣。基本上能夠分爲以下兩種:瀏覽器

macro-task: script(總體代碼), setTimeout, setInterval, setImmediate, I/O, UI rendering
micro-task: process.nextTick, 原生Promise, Object.observe, MutationObserver異步

咱們看到原生PromisesetTimeout分別屬於micro-taskmacro-task。咱們以前說的異步任務隊列,指的是macro-task。而micro-task的執行順序,與之不一樣。函數

在執行完主線程上的全部任務時,會先去查看micro-task隊列中有沒有任務,若是有,則依次執行micro-task隊列中的全部任務,以後纔去查看macro-task隊列。每次拿到macro-task隊列上任務並執行以後,都會去檢查micro-task隊列,以此循環。因此上面題目中結果是12354就很明瞭了。oop

咱們看一個例子,並詳細解釋它的執行流程。測試

console.log('script1');

setTimeout(function() {
  console.log('setTimeout1');
}, 300);

Promise.resolve().then(function() {
  console.log('promise1');
}).then(function() {
  console.log('promise2');
});

console.log('script2');

setTimeout(function() {
  console.log('setTimeout2');
  Promise.resolve().then(function() {
    console.log('promise3');
  })
}, 0);

// script1
// script2
// promise1
// promise2
// setTimeout2
// promise3
// setTimeout1

結果如代碼中註釋所示。具體執行步驟以下:

①代碼從上到下執行,先打印出script1

②執行到第一個setTimeout時,發現300ms後把函數添加到macro-task隊列中。

③執行Promise時,依次把輸出promise1promise2的任務添加到micro-task隊列。

④打印script2

⑤執行第二個setTimeout時由於設置的是0ms,因此當即(其實瀏覽器有最少4ms的限制)添加到macro-task隊列中。

⑥主線程執行完畢則檢查micro-task隊列並執行,輸出promise1promise2

⑦而後檢查macro-task隊列,輸出setTimeout2,並把輸出promise3的任務添加到micro-task隊列。

⑧再次檢查micro-task隊列並執行,輸出promise3

⑨最後檢查macro-task隊列,輸出setTimeout1,由於它是300ms後添加到macro-task隊列,因此後輸出。

規範中的流程是這個樣子,可是不一樣的瀏覽器中,實際輸出的結果可能會不相同。以上是最新版本的chrome中測試結果。

最後,推薦一篇外國友人的博客,我就是看了這篇文章才徹底弄清楚的,裏面內容講的特別詳細。

相關文章
相關標籤/搜索