摘要:目前高級瀏覽器如Chrome、Firefox都已經內置了Promise對象,提供更多的操作接口,如此優雅的Promise具備哪些特性呢?作者TAT.dmyang就JavaScript中的Promise規范給出了一些見解,一起來看下。
【編者按】JavaScript是一種基于對象和事件驅動并具有相對安全性的客戶端腳本語言。自推出后就大受開發者的青睞,基于JavaScript的開發工具也不計其數,開發者們可以靈活選擇,輕松構建應用。原文作者TAT.dmyang就JavaScript中的Promise規范給出了一些見解,目前高級瀏覽器如Chrome、Firefox都已經內置了Promise對象,提供更多的操作接口,如此優雅的Promise具備哪些特性呢?且看下文:
一直以來,JavaScript處理異步都是以callback的方式,在前端開發領域callback機制幾乎深入人心。在設計API的時候,不管是瀏覽器廠商還是SDK開發商亦或是各種類庫的作者,基本上都已經遵循著callback的套路。
近幾年隨著JavaScript開發模式的逐漸成熟,CommonJS規范順勢而生,其中就包括提出了Promise規范,Promise完全改變了js異步編程的寫法,讓異步編程變得十分的易于理解。
在callback的模型里邊,我們假設需要執行一個異步隊列,代碼看起來可能像這樣:
[js] view plaincopy
loadImg('a.jpg', function() {
loadImg('b.jpg', function() {
loadImg('c.jpg', function() {
console.log('all done!');
});
});
});
這也就是我們常說的回調金字塔,當異步的任務很多的時候,維護大量的callback將是一場災難。當今Node.js大熱,好像很多團隊都要用它來做點東西以沾沾“洋氣”,曾經跟一個運維的同學聊天,他們也是打算使用Node.js做一些事情,可是一想到js的層層回調就望而卻步。
Promise可能大家都不陌生,因為Promise規范已經出來好一段時間了,同時Promise也已經納入了ES6,而且高版本的chrome、firefox瀏覽器都已經原生實現了Promise,只不過和現如今流行的類Promise類庫相比少些API。
所謂Promise,字面上可以理解為“承諾”,就是說A調用B,B返回一個“承諾”給A,然后A就可以在寫計劃的時候這么寫:當B返回結果給我的時候,A執行方案S1,反之如果B因為什么原因沒有給到A想要的結果,那么A執行應急方案S2,這樣一來,所有的潛在風險都在A的可控范圍之內了。
在這里,當每一個被詢問者做出不符合預期的應答時都用了不同的處理機制。事實上,Promise規范沒有要求這樣做,你甚至可以不做任何的處理(即不傳入then的第二個參數)或者統一處理。
Promise/A+規范:
一個promise可能有三種狀態:等待(pending)、已完成(fulfilled)、已拒絕(rejected)
一個promise的狀態只可能從“等待”轉到“完成”態或者“拒絕”態,不能逆向轉換,同時“完成”態和“拒絕”態不能相互轉換
promise必須實現then方法(可以說,then就是promise的核心),而且then必須返回一個promise,同一個promise的then可以調用多次,并且回調的執行順序跟它們被定義時的順序一致
then方法接受兩個參數,個參數是成功時的回調,在promise由“等待”態轉換到“完成”態時調用,另一個是失敗時的回調,在promise由“等待”態轉換到“拒絕”態時調用。同時,then可以接受另一個promise傳入,也接受一個“類then”的對象或方法,即thenable對象。
可以看到,Promise規范的內容并不算多,大家可以試著自己實現以下Promise。
以下是筆者自己在參考許多類Promise庫之后簡單實現的一個Promise,代碼請移步promiseA。
簡單分析下思路:
構造函數Promise接受一個函數resolver,可以理解為傳入一個異步任務,resolver接受兩個參數,一個是成功時的回調,一個是失敗時的回調,這兩參數和通過then傳入的參數是對等的。
其次是then的實現,由于Promise要求then必須返回一個promise,所以在then調用的時候會新生成一個promise,掛在當前promise的_next上,同一個promise多次調用都只會返回之前生成的_next。
由于then方法接受的兩個參數都是可選的,而且類型也沒限制,可以是函數,也可以是一個具體的值,還可以是另一個promise。
這里,then做了簡化,其他promise類庫的實現比這個要復雜得多,同時功能也更多,比如還有第三個參數——notify,表示promise當前的進度,這在設計文件上傳等時很有用。對then的各種參數的處理是復雜的部分,有興趣的同學可以參看其他類Promise庫的實現。
在then的基礎上,應該還需要至少兩個方法,分別是完成promise的狀態從pending到resolved或rejected的轉換,同時執行相應的回調隊列,即resolve()和reject()方法。
到此,一個簡單的promise就設計完成了
標準的Promise
可參考html5rocks的這篇文章JavaScript Promises,目前高級瀏覽器如Chrome、Firefox都已經內置了Promise對象,提供更多的操作接口,比如Promise.all(),支持傳入一個promises數組,當所有promises都完成時執行then,還有就是更加友好強大的異常捕獲,應對日常的異步編程,應該足夠了。
第三方庫的Promise
現今流行的各大js庫,幾乎都不同程度的實現了Promise,如dojo,jQuery、Zepto、when.js、Q等,只是暴露出來的大都是Deferred對象,以jQuery(Zepto類似)為例,實現上面的getImg()。
當然,jQuery中,很多的操作都返回的是Deferred或promise,如animate、ajax:
jQuery還實現了done()和fail()方法,其實都是then方法的shortcut。
處理promises隊列,jQuery實現的是$.when()方法,用法和Promise.all()類似。
其他類庫,這里值得一提的是when.js,本身代碼不多,完整實現Promise,同時支持browser和Node.js,而且提供更加豐富的API,是個不錯的選擇。
本站文章版權歸原作者及原出處所有 。內容為作者個人觀點, 并不代表本站贊同其觀點和對其真實性負責,本站只提供參考并不構成任何投資及應用建議。本站是一個個人學習交流的平臺,網站上部分文章為轉載,并不用于任何商業目的,我們已經盡可能的對作者和來源進行了通告,但是能力有限或疏忽,造成漏登,請及時聯系我們,我們將根據著作權人的要求,立即更正或者刪除有關內容。本站擁有對此聲明的最終解釋權。