JS是單線程執行了,經過event loop實現了非阻塞的I/O。編程中常常用異步回調函數的方式處理I/O的反饋結果(網絡請求,用戶交互事件)。如分別發送兩個請求:html
function xhrRequest(url, callback) { setTimeout(function(){ // 用setTimeout模擬異步請求 callback(); }, 0) } xhrRequest('/index', function(){ console.log('request /index done'); }) xhrRequest('/list', function(){ console.log('request /list done'); })
但若是想在請求index後再請求list怎麼辦呢?,可能會這樣寫:es6
xhrRequest('/index', function(){ console.log('request /index done'); xhrRequest('/list', function(){ // 回調函數裏,再次回調 console.log('request /list done'); }) })
可是若是有3個或4個異步請求有前後依賴怎麼呢?回調函數會一直嵌套回調函數(callback hell),代碼看起來亂糟糟的,而且很差維護。事件模式也不能很好處理這些,急需其餘能下降異步編程複雜性的方式。編程
Promise已是個標準了,最新的是Promise A+標準。標準中給Promise的定義是:"A promise represents the eventual result of an asynchronous operation"。即Promise表示一個異步操做的最終結果。主要經過Promise對象的then方法和Promise對象進行交互:註冊失敗,成功回調函數,而且失敗回調函數接收一個失敗緣由(reason)參數,成功回調函數接收一個值(value)參數。Promise A+標準主要是定義then方法的規範。segmentfault
Promise對象有三種狀態:Pending(待定),Fullfilled(已完成),Rejected(已拒絕)。
A:Pending的Promise對象能夠轉成Fullfilled或者Rejected
B:Fullfilled的Promise對象不能轉成其餘狀態,而且必須含有一個值(value),該值不能變。
C:Rejected的Promise對象不能轉成其餘狀態,而且必須含有一個緣由對象(reason)表示失敗的緣由,該值不能變。promise
then方法的規範不少,認真讀讀標準。但要主要下面幾點:
A:每一個回調函數只能執行一次。
B:屢次調用then方法,能夠註冊多個回調函數,回調函數的調用順序取決於調用then方法的順序。若是Promise對象已經處於fullfilled/ rejected狀態,調用then方法會當即執行onfullfilled/onRejected回調函數。
C:then方法必須返回個Promise對象: Promise2 = Promse1.then(onFullfilled, onRejected)。但沒規定Promise1和Promise2是否相等,這個要看具體的實現了。網絡
then方法返回一個Promise對象,這樣就構成一個then鏈。前面的Promise對象的狀態變化對後面的Promise對象的狀態的影響稱爲Promise解決程序(The Promise Resolution Procedure)。框架
實現Promise標準的庫和框架有不少了,jQuery,Zeptojs,ES6等。好多庫中Promise實現叫Deferred,Deferred對象是用來操做Promise對象(修改Promise對象狀態),而Promise對象自己只提供then方法添加回調函數(以及其餘添加回調函數的方法),不提供操做Promise對象的方法,這樣設計使得Promise對象對外不可修改,詳細參考ZeptoJS Deferred實現。異步
Promise是把相似的異步處理對象和處理規則進行規範化, 並按照採用統一的接口來編寫,而採起規定方法以外的寫法都會出錯。這樣更有利理解,維護。將複雜的異步處理輕鬆地進行模式化。async