轉自:http://palmer.arkstack.cn/201...
一:平時簡單使用web
1.setTimeout延遲一段時間執行一次(only one)瀏覽器
setTimeout(function, milliseconds, param1, param2, ...) clearTimeout() // 阻止定時器運行 setTimeout(function(){ alert("Hello"); }, 3000); // 3s後彈出
2.setInterval 每隔一段時間執行一次 (Many times)多線程
setInterval(function, milliseconds, param1, param2, ...) e.g. setInterval(function(){ alert("Hello"); }, 3000); // 每隔3s彈出
3.setTimeout和setInterval的延時最小間隔是4ms;在JavaScript中沒有任何代碼是馬上執行的,但一旦進程空閒就儘快執行。因此 setTimeout 仍是setInterval,設置的時間都是n毫秒被添加到隊列中,而不是過n毫秒後當即執行。
二:進程與線程異步
1.模擬一個場景
那麼:async
在深刻一點:函數
再深刻:oop
三:JavaScript單線程spa
JavaScript這門語言的核心特徵,就是單線程(是指在JS引擎中負責解釋和執行JavaScript代碼的線程只有一個)。這和JavaScript最初設計是做爲一門GUI變成語言有關,最初用於瀏覽器端,單一線程控制GUI是很廣泛的作法。雖然JavaScript是單線程,當瀏覽器是多線程的!!!!!!!例如webkit或是Gecko引擎,可能有JavaScript引擎線程,界面渲染線程,瀏覽器事件觸發線程,Http請求線程,讀寫文件的線程。線程
四:同步異步
1.同步(synchronous):假如一個函數返回時,調用者就可以獲得預期結果(即拿到了預期的返回值或者看到了預期的效果)這就是同步函數設計
e.g. alert('立刻能看到我拉'); console.log('也能立刻看到我哦');
2.異步(asynchronous):假如一個函數返回時,調用者不能獲得預期結果,須要經過必定手段才能得到,這就是異步函數。
e.g. setTimeout(function() { // 過一段時間才能執行我哦 }, 1000);
五:異步構成要素
一個異步過程一般是這樣的:主線程發起一個異步請求,相應的工做線程(好比瀏覽器的其餘線程)接受請求並告知主線程已收到(異步函數返回);主線程能夠繼續執行 後面代碼,同時工做線程執行異步任務,工做線程完成工做號,告知主線程;主線程收到通知後,執行必定的動做(調用回調函數)
六:通訊機制
異步過程的通訊機制:工做線程將消息放到消息隊列,主線程經過事件循環過程去取消息
七:事件循環Event Loop
主線程(js線程)只會作一件事,就是從消息隊列裏面取消息,執行消息,再取消息,再執行。消息隊列爲空時,就會等待直到消息隊列變成非空。只有當前的消息執行結束,纔會去取下一個消息。這種機制就叫作事件循環機制Event Loop,取一個消息並執行的過程叫作一次循環
工做線程是生產者,主線程是消費者。工做線程執行異步任務,執行完成後把對應額回調函數封裝成一條消息放到消息隊列中;主線程不斷地從消息隊列中取消息並執行。當消息隊列爲空時,主線程阻塞,直到消息隊列再次非空。
八:setTimeOut(function,0)發生了什麼
setTimeOut的function的任務異步執行,0不表明當即執行,而是將任務推到消息隊列的最後,再由主線程的事件循環調用。
setTimeOut的最小時間不是0ms而是4ms
九:setInterval缺點
定時器指定的時間間隔,表示的是什麼時候將定時器的代碼添加到消息隊列,而不是什麼時候執行代碼,因此真正什麼時候執行代碼的時間是不能保證的。取決於什麼時候被主線程的事件循環取到,並執行。
setInterval(function, N)
上面代碼意味着,每隔N秒把function事件推到消息隊列中,何時執行,就不知道了
上圖可見,setInterval每隔100ms往隊列中添加一個事件;100ms後,添加T1定時器代碼至隊列中,主線程中還有任務在執行,因此等待,some event執行結束後執行T1定時器代碼;又過了100ms,T2定時器被添加到隊列中,主線程還在執行T1代碼,因此等待;又過了100ms,理論上又要往隊列裏推一個定時器代碼,但因爲此時T2還在隊列中,因此T3不會被添加,結果就是此時被跳過;這裏咱們能夠看到,T1定時器執行結束後立刻執行了T2代碼,因此並無達到定時器的效果。
setInterval兩個缺點:
十:鏈式setTimeOut
setTimeout(function () { // 任務 setTimeout(arguments.callee, interval); }, interval)
在嚴格模式下,第5版ECMAScript(ES5)禁止使用arguments.callee()。當一個函數必須調用自身的時候,避免使用arguments.callee(),經過要麼給函數表達式一個名字,要麼使用一個函數聲明
上述函數每次執行的時候都會建立一個新的定時器,第二個setTimeOut使用了arguments.callee()獲取當前函數的引用,而且爲其設置另外一個定時器。在一個定時器執行完前,不會向隊列插入新的定時器(解決缺點一),保證定時器間隔(解決缺點二)