九句話輕鬆理解執行緒與非同步以及回撥函式

weixin_33670713發表於2016-05-23

js非同步

九句話輕鬆理解執行緒與非同步以及回撥函式。

  1. 在js中沒有多執行緒,也就是說,在同一個時間只執行一個任務
  2. 但是如果真是這樣,那麼像一些事件(如使用者點選),如果永遠不點選,那麼後面的程式碼就永遠都要一直等待,這個等待是無意義的,並且cpu也是空閒的
  3. 所以把任務分成兩種:同步任務和非同步任務
  4. 所謂『同步任務』,就是一般任務,在js中一個一個的按續執行
  5. 所有同步任務都在主執行緒上執行,形成『執行棧』
  6. 『非同步任務』就是如(dom event, timer),他們並不先執行,而且先將它們放到『任務佇列』中(task queue),先進先出的執行。
  7. 『非同步任務』中必須指定『回撥函式』,『回撥函式』就是被主執行緒掛起來的程式碼,當主執行緒要執行『非同步任務』時,實際上就是執行回撥函式
  8. 佇列任務總是等執行棧中同步任務全部完成之後才執行
  9. 當執行棧的任務執行完後,開始讀取佇列任務中可以執行的任務(回撥函式),這時就將回撥函式加入到執行棧中執行,然後如此迴圈

分解來講就是

問題

在JavaScript中大部分程式碼都是同步一個一個執行的,如果此時你寫了一個click事件,那使用者沒有觸發這個click,那按照同步的思想,click事件後面的程式碼都不會執行,直到你觸發該事件為止,這就丟擲了一個問題,我們如何來處理這些事件?要知道JavaScript是沒有多執行緒的。(關於多執行緒可以看我的這篇文章)

方法

這時就是非同步出場的時候了。對於非同步任務,JavaScript並不直接執行,而是將它推入一個佇列(關於佇列可以看棧與佇列),佇列中儲存的函式就是一個個的回撥函式。等當前執行環境執行完畢後,再執行佇列中的回撥函式。

例子

例子就比如說setTimeout()函式。

function a(num) {
    for (var i = 0; i < num; i++) {
        (function(i) {
            setTimeout(function() {
                console.log("b:" + i);
            }, 10);
        })(i);
        console.log("a:" + i);
    }
}
a(5);

最後的輸出為:

eventUtil.js:42 a:0
eventUtil.js:42 a:1
eventUtil.js:42 a:2
eventUtil.js:42 a:3
eventUtil.js:42 a:4
eventUtil.js:38 b:0
eventUtil.js:38 b:1
eventUtil.js:38 b:2
eventUtil.js:38 b:3
eventUtil.js:38 b:4

例子解釋

可以看出先執行的是第42行的程式碼,後執行的是第38行程式碼,這很明顯是因為第38行的程式碼是非同步程式碼;而從b的輸出是從0-4可以看出,這個非同步程式碼被存放在是佇列,因為這是先進先出載入的。

相關文章