瀏覽器端Event loop簡介

瞭解過javascript的都知道其最大的特色就是單線程,也就是說同一時間只能幹一件事情。那麼爲何不能是多線程呢?緣由很簡單,多線程太複雜了,假設javascript有2個線程,一個去添加dom,一個去刪除dom,那麼瀏覽器就懵逼了,這到底要我選擇哪一個?因此爲了不沒必要要的麻煩,javascript一開始就選擇了單線程。可是單線程也有問題,假設有個任務是要向服務器去請求一個文件,若是這個文件很大,那麼就不能當即執行下一語句(要等到文件回來),這樣就形成了瀏覽器假死的現象。因此html5提出了web worker標準,容許javascript建立子線程,可是規定很嚴格,子線程要受到主線程控制,而且不能操做dom,這種折中方法使得javascript更加靈活了。javascript

到目前爲止javascript能夠有子線程了,這時候再遇到像以前提到的若是一個io操做很費時間,那麼就能夠把這個任務掛起來,等返回結果了再來執行這個任務。因而全部的任務都變成了2種,一種是同步任務(從上到下一步一步執行),另一種就是異步任務(等有結果了再執行,即所謂的消息隊列)。這2種任務進入到線程也不同,同步的從上到下依次直接進入主線程造成執行棧,異步的等有返回結果了,好比ajax請求成功了,就把成功的回調放到子線程裏面去(失敗就把失敗的回調放到子線程裏面去)。如今瀏覽器開始執行主線程裏面的執行棧了,等主線程裏面的執行棧都執行完畢了,主線程就會到子線程裏面去看以前掛起到任務哪些有回調了,若是有回調了,那就把該回調內容放到主線程裏面去執行,等執行完畢了再去子線程看有沒有新的回調了(這裏要注意的是主線程所有執行完畢,纔會去子線程去看),主線程不斷的重複這個步驟,這就是所謂的Event loop,也就是javascript的運行機制。比較特殊的是setTimeout,setinterval這2個方法,它們也會被放倒子線程裏面去,好比我使用setTimeout(fn,3000),有時候不必定是3s以後會執行fn這個事件,還要看主線程裏面的任務是否完成。html

案例1:html5

function f() {
  console.log("foo");
  setTimeout(g, 0);
  console.log("baz");
  h();
}

function g() {
  console.log("bar");
}

function h() {
  console.log("blix");
}

f();
輸出的結果爲:foo 、baz 、 blix 、bar

案例2 :java

var req = new XMLHttpRequest();
req.open('GET', url);    
req.onload = function (){};    
req.onerror = function (){};    
req.send();
var req = new XMLHttpRequest();
req.open('GET', url);
req.send();
req.onload = function (){};    
req.onerror = function (){};

這2個的執行結果都是同樣的,都會先執行onload事件,由於javascript要等主線程空了纔會去查看子線程有沒有回調內容。web

注意點:ajax

異步的任務執行的順序是不固定的,主要看返回的速度,假設a任務寫在b任務以前,可是a任務比較大,耗時比較長,而b任務耗時短,那麼b任務有了回調先會進入到子線程裏面,這樣會被主線程先輪詢到,可是也有可能b任務網絡很差,a任務先返回了,那麼a任務的回調先被註冊到子線程了,致使a先執行了。瀏覽器

相關文章
相關標籤/搜索