單線程- 只有一個線程,只能作一件事
緣由-避免DOM渲染的衝突
解決方案-異步
1) 單線程- 只有一個線程,只能作一件事
基礎事例
// 循環運行期間,JS執行和DOM 渲染暫時卡頓javascript
var i, sum = 0; for (i = 0; i<100000000000; i++) { sum += i; } console.log(sum); // alert不處理,JS執行和DOM 渲染暫時卡頓 console.log(1); alert('hello'); console.log(2)
2) 緣由 - 避免DOM渲染的衝突
瀏覽器須要渲染DOM
JS能夠修改DOM結構
因此JS執行的時候,瀏覽器 DOM 渲染會暫停
兩段JS也不能同時執行(都修改 DOM 就衝突了)
webworker支持多線程,可是不能修改訪問 DOM
3) 解決方案 - 異步
基礎事例java
console.log(100) setTimeout(function () { console.log(200); // 反正1000ms以後執行 }, 1000); // 先無論他,先讓其它 JS 代碼運行 console.log(300); console.log(400);
4) 異步 - 存在的問題
問題一:沒有按照書寫方式執行,可讀性差
問題二:callback中不容易模塊化web
文字解釋
事件輪詢,JS實現異步的具體解決方案
同步代碼,直接執行
異步函數先放在異步隊列中
待同步函數執行完畢,輪詢執行異步隊列函數
例子分析
例子一:ajax
先看左下角,是咱們要執行的代碼,第一個是延遲100毫秒打印1,第二個是延遲0,打印2,按照上面講的,同步代碼先執行,異步代碼放在異步隊列中,最後執行完同步在執行異步隊列的函數,執行第一個函數的時候,setTimeout是個異步函數,那咱們是否是應該當即放在右側的隊列中呢?答案是否認的,由於它有一個延時,咱們須要100毫秒以後才能放進去,執行第二個setTimeout函數,因爲沒有延時,因此會被放進異步隊列中,最後一個是直接 在主進程,因此 直接執行打印,等同步執行完以後,馬上看異步隊列中,這時候只有第二個setTimeout,執行完以後,在去看異步隊列有沒有,由於100這毫秒對於計算機來講,是一個至關長的時間,因此js引擎會一直輪詢異步隊列中有沒有可執行函數,直接100毫秒以後第一個setTimeout被放進異隊列中,而後才執行。數組
例子一:promise
上圖流程跟例子一同樣,這邊咱們疑惑的是,當咱們執行 ajax 的時候,裏面的success 是異步函數,它要何時被放進異步隊列中呢?
固然是請求成功的時候被放進異步隊列中,但咱們不知道是 大於100毫秒仍是小於,因此打印結果有兩種狀況,先打印d c b a,或者打印 d c a b。瀏覽器
3、是否用過jQuery的Deferred
jQuery 1.5的變化 -1.5以前服務器
jQuery 1.5的變化 -1.5以後多線程
jQuery 1.5的變化
沒法改變JS異步和單線程的本質
只能從寫法上杜絕 callback 這種形式
它是一種語法糖形式,可是解藕了代碼
很好的體現:開放封裝原則異步
1) 什麼是deferred對象?
開發網站的過程當中,咱們常常遇到某些耗時很長的javascript操做。其中,既有異步的操做(好比ajax讀取服務器數據),也有同步的操做(好比遍歷一個大型數組),它們都不是當即能獲得結果的。
一般的作法是,爲它們指定回調函數(callback)。即事先規定,一旦它們運行結束,應該調用哪些函數。
可是,在回調函數方面,jQuery的功能很是弱。爲了改變這一點,jQuery開發團隊就設計了deferred對象。
簡單說,deferred對象就是jQuery的回調函數解決方案。
2) deferred應用
咱們來看一個具體的例子。假定有一個很耗時的操做wait:
var wait = function() {
var tasks = function() {
alert('執行完畢');
};
setTimeout(tasks,5000);
}
咱們爲它指定回調函數,應該怎麼作呢?
你可能會使用$when()
$.when(wait()) .done(function(){ alert('成功!') }) .fail(function() { alert('出錯!'); })
可是,這樣寫的話,done()方法會當即執行,起不到回調函數的做用。緣由在於$.when()的參數只能是deferred對象,因此必須對wait()進行改寫:
var dtd = $.Deferred(); //新建一個deferred var wait = function (dtd) { var tasks = function () { console.log('執行完畢'); dtd.resolve(); //改變deferred對象執行狀態 }; setTimeout(tasks, 5000); return dtd; }
如今,wait()函數返回的是deferred對象,這就能夠加上鍊式操做了。
$.when(wait(dtd)) .done(function(){ alert("成功!"); }) .fail(function(){ alert("出錯!"); });
更多內容可參考這裏
4、Promise 的基本使用和原理
1) 什麼是 Promise
一人Promise 對象表明一個目前還不可用,可是在將來的某個時間點能夠被解析的值。它容許你以一種同步的方式編寫異步代碼。Promise的出現,本來是爲了解決回調地獄的問題。全部人在講解Promise時,都會以一個ajax請求爲例,此處咱們也用一個簡單的ajax的例子來帶你們看一下Promise是如何使用的。
ajax請求的傳統寫法:
getData(method, url, successFun, failFun){ var xmlHttp = new XMLHttpRequest(); xmlHttp.open(method, url); xmlHttp.send(); xmlHttp.onload = function () { if (this.status == 200 ) { successFun(this.response); } else { failFun(this.statusText); } }; xmlHttp.onerror = function () { failFun(this.statusText); }; }
改成promise後的寫法:
getData(method, url){
var promise = new Promise(function(resolve, reject){
var xmlHttp = new XMLHttpRequest(); xmlHttp.open(method, url); xmlHttp.send(); xmlHttp.onload = function () { if (this.status == 200 ) { resolve(this.response); } else { reject(this.statusText); } }; xmlHttp.onerror = function () { reject(this.statusText); };
})
return promise;
}
getData('get','www.xxx.com').then(successFun, failFun)
很顯然,咱們把異步中使用回調函數的場景改成了.then()、.catch()等函數鏈式調用的方式。基於promise咱們能夠把複雜的異步回調處理方式進行模塊化。
2)Promise的原理分析
其實 promise 原理提及來並不難,它內部有三個狀態,分別是 pending, fulfilled 和 rejected。
peding 是對象建立後的初始狀態,當對象fulfill(成功)時變爲 fulfilled, 當對象 reject(失敗)時變爲 rejected。且只能從 pending 變爲 fulfilled 或 rejected,而不能逆向或或從 fulfilled 變爲rejected,從 rejected變爲 fulfilled。如圖所示:
本文爲雲棲社區原創內容,未經容許不得轉載