日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
JavaScriptPromises相當(dāng)酷:一種有趣的方案庫(kù)

“And when I promise something, I never ever break that promise. Never.” ― Rapunzel

許多的語(yǔ)言,為了將異步模式處理得更像平常的順序,都包含一種有趣的方案庫(kù),它們被稱之為promises,deferreds,或者futures。JavaScript的promises ,可以促進(jìn)關(guān)注點(diǎn)分離,以代替緊密耦合的接口。 本文講的是基于Promises/A 標(biāo)準(zhǔn)的JavaScript promises。[http://wiki.commonjs.org/wiki/Promises/A]Promise的用例:

  • 執(zhí)行規(guī)則

  • 多個(gè)遠(yuǎn)程驗(yàn)證

  • 超時(shí)處理

  • 遠(yuǎn)程數(shù)據(jù)請(qǐng)求

  • 動(dòng)畫

  • 將事件邏輯從應(yīng)用邏輯中解耦

  • 消除回調(diào)函數(shù)的恐怖三角

  • 控制并行的異步操作

JavaScript promise是一個(gè)承諾將在未來(lái)返回值的對(duì)象。是具有良好定義的行為的數(shù)據(jù)對(duì)象。promise有三種可能的狀態(tài):

  1. Pending(待定)

  2. Rejected(拒絕)

  3. Resolved(已完成)

一個(gè)已經(jīng)拒絕或者完成的承諾屬于已經(jīng)解決的。一個(gè)承諾只能從待定狀態(tài)變成已經(jīng)解決的狀態(tài)。之后,承諾的狀態(tài)就不變了。承諾可以在它對(duì)應(yīng)的處理完成之后很久還存在。也就是說(shuō),我們可以多次取得處理結(jié)果。我們通過(guò)調(diào)用promise.then()來(lái)取得結(jié)果,這個(gè)函數(shù)一直到承諾對(duì)應(yīng)的處理結(jié)束才會(huì)返回。我們可以靈活的串聯(lián)起一堆承諾。這些串聯(lián)起來(lái)的“then”函數(shù)應(yīng)該返回一個(gè)新的承諾或者最早的那個(gè)承諾。

通過(guò)這個(gè)樣式,我們可以像寫同步代碼一樣來(lái)寫非同步代碼。主要是通過(guò)組合承諾來(lái)實(shí)現(xiàn):

  • 堆棧式任務(wù):多處散落在代碼中的,對(duì)應(yīng)同一個(gè)承諾。
  • 并行任務(wù):多個(gè)承諾返回同一個(gè)承諾。
  • 串行任務(wù):一個(gè)承諾,然后接著執(zhí)行另一個(gè)承諾。
  • 上面幾種的組合。

為什么要這么麻煩?只用基本的回調(diào)函數(shù)不行嗎?

回調(diào)函數(shù)的問(wèn)題

回調(diào)函數(shù)適合簡(jiǎn)單的重復(fù)性事件,例如根據(jù)點(diǎn)擊來(lái)讓一個(gè)表單有效,或者保存一個(gè)REST調(diào)用的結(jié)果?;卣{(diào)函數(shù)還會(huì)使代碼形成一個(gè)鏈,一個(gè)回調(diào)函數(shù)調(diào)用一個(gè)REST函數(shù),并為REST函數(shù)設(shè)置一個(gè)新的回調(diào)函數(shù),這個(gè)新的回調(diào)函數(shù)再調(diào)用另一個(gè)REST函數(shù),依此類推。這就形成了一個(gè)如圖1中的毀滅金字塔。代碼的橫向增長(zhǎng)大于縱向的增長(zhǎng)?;卣{(diào)函數(shù)看起來(lái)很簡(jiǎn)單,直到我們需要一個(gè)結(jié)果,而且是立刻就要,馬上就用在下一行的計(jì)算中。

圖1:毀滅金字塔

 
 
  1. 'use strict'; 
  2. var i = 0; 
  3. function log(data) {console.log('%d %s', ++i, data); }; 
  4.   
  5. function validate() { 
  6.    log("Wait for it ..."); 
  7.    // Sequence of four Long-running async activities 
  8.    setTimeout(function () { 
  9.       log('result first'); 
  10.       setTimeout(function () { 
  11.          log('result second'); 
  12.          setTimeout(function () { 
  13.             log('result third'); 
  14.             setTimeout(function () { 
  15.                log('result fourth') 
  16.             }, 1000); 
  17.          }, 1000); 
  18.       }, 1000); 
  19.    }, 1000); 
  20.   
  21. }; 
  22. validate(); 

在圖1中,我使用timeout來(lái)模擬異步操作。管理異常的方法是痛苦的,很容易玩漏下游行為。當(dāng)我們編寫回調(diào),那么代碼組織變得混亂。圖2顯示了一個(gè)模擬驗(yàn)證流可以運(yùn)行在NodeJS REPL。在下一節(jié),我們將從pyramid-of-doom模式遷移到一個(gè)連續(xù)的promise。

Figure

 
 
  1. 'use strict'; 
  2. var i = 0; 
  3. function log(data) {console.log('%d %s', ++i, data); }; 
  4.   
  5. // Asynchronous fn executes a callback result fn 
  6. function async(arg, callBack) { 
  7.    setTimeout(function(){ 
  8.       log('result ' + arg); 
  9.       callBack(); 
  10.    }, 1000); 
  11. }; 
  12.   
  13. function validate() { 
  14.    log("Wait for it ..."); 
  15.    // Sequence of four Long-running async activities 
  16.    async('first', function () { 
  17.       async('second',function () { 
  18.          async('third', function () { 
  19.             async('fourth', function () {}); 
  20.          }); 
  21.       }); 
  22.    }); 
  23. }; 
  24. validate(); 

在NodeJS REPL執(zhí)行的結(jié)果

 
 
  1. $ node scripts/examp2b.js 
  2. 1 Wait for it ... 
  3. 2 result first 
  4. 3 result second 
  5. 4 result third 
  6. 5 result fourth 

我曾經(jīng)遇到一個(gè)AngularJS動(dòng)態(tài)驗(yàn)證的情況,根據(jù)對(duì)應(yīng)表的值,動(dòng)態(tài)的限制表單項(xiàng)的值。限制項(xiàng)的有效值范圍被定義在REST服務(wù)上。

我寫了一個(gè)調(diào)度器,根據(jù)請(qǐng)求的值,去操作函數(shù)棧,以避免回調(diào)嵌套。調(diào)度器從棧中彈出函數(shù)并執(zhí)行。函數(shù)的回調(diào)會(huì)在結(jié)束時(shí)重新調(diào)用調(diào)度器,直到棧被清空。每次回調(diào)都記錄所有從遠(yuǎn)程驗(yàn)證調(diào)用返回的驗(yàn)證錯(cuò)誤。

我認(rèn)為我寫的玩意兒是一種反模式。如果我用Angular的$http調(diào)用提供的promise,在整個(gè)驗(yàn)證過(guò)程中我的思維會(huì)更近似線性形式,就像同步編程。平展的promise鏈?zhǔn)强勺x的。繼續(xù)...

使用Promises

圖3顯示了我將驗(yàn)證改寫成promise鏈的樣子。其中采用了kew promise庫(kù)。Q庫(kù)同樣適用。要使用該庫(kù),首先使用npm將kew庫(kù)導(dǎo)入到NodeJS,然后加載代碼到NodeJS REPL。

Figure

 
 
  1. 'use strict'; 
  2. var Q = require('kew'); 
  3. var i = 0; 
  4.   
  5. function log(data) {console.log('%d %s', ++i, data); }; 
  6.   
  7. // Asynchronous fn returns a promise 
  8. function async(arg) { 
  9.     var deferred = Q.defer(); 
  10.     setTimeout(function () { 
  11.         deferred.resolve('result ' + arg);\ 
  12.     }, 1000); 
  13.     return deferred.promise; 
  14. }; 
  15.   
  16. // Flattened promise chain 
  17. function validate() { 
  18.     log("Wait for it ..."); 
  19.     async('first').then(function(resp){ 
  20.         log(resp); 
  21.         return async('second'); 
  22.     }) 
  23.     .then(function(resp){ 
  24.         log(resp); 
  25.         return async('third') 
  26.     }) 
  27.     .then(function(resp){ 
  28.         log(resp); 
  29.         return async('fourth'); 
  30.     }) 
  31.     .then(function(resp){ 
  32.         log(resp); 
  33.     }).fail(log); 
  34. }; 
  35. validate(); 

輸出和使用嵌套回調(diào)時(shí)相同:

 
 
  1. $ node scripts/examp2-pflat.js 
  2. 1 Wait for it ... 
  3. 2 result first 
  4. 3 result second 
  5. 4 result third 
  6. 5 result fourth 

該代碼稍微“長(zhǎng)高”了,但我認(rèn)為更易于理解和修改。更易于加上適當(dāng)?shù)腻e(cuò)誤處理。在鏈的末尾調(diào)用fail用于捕獲鏈中錯(cuò)誤,但我也可以在任何一個(gè)then里面提供一個(gè)reject的處理函數(shù)做相應(yīng)的處理。

#p#

服務(wù)器 或 瀏覽器

Promises在瀏覽器中就像在NodeJS服務(wù)器中一樣有效。下面的地址, http://jsfiddle.net/mauget/DnQDx/,指向JSFiddle的一個(gè)展示如何使用一個(gè)promise的web頁(yè)面。 JSFiddle所有的代碼是可修改的。瀏覽器輸出的一個(gè)變化如圖4所示。我故意操作隨意動(dòng)作。你可以試幾次得到相反的結(jié)果。它是可以直接擴(kuò)展到多個(gè)promise鏈, 就像前面NodeJS例子。

圖4.單個(gè)promise

并行 Promises

考慮一個(gè)異步操作喂養(yǎng)另一個(gè)異步操作。讓后者包括三個(gè)并行異步行為,反過(guò)來(lái),喂***一個(gè)行動(dòng)。只有當(dāng)所有平行的子請(qǐng)求通過(guò)才能通過(guò)。如圖5所示。這是靈感來(lái)自偶遇一打MongoDB操作。有些是合格的并行操作。我實(shí)現(xiàn)了promises的流流程圖。

圖5:異步操作的結(jié)構(gòu)

我們?cè)趺磿?huì)模擬那些在該圖中心行的并行promises?關(guān)鍵是,***的promise庫(kù)有一個(gè)全功能,它產(chǎn)生一個(gè)包含一組子promises的父promie。當(dāng)所有的子promises通過(guò),父promise通過(guò)。如果有一個(gè)子promise拒絕,父promise拒絕。

圖6顯示了一個(gè)代碼片段,讓十個(gè)并行的promises每個(gè)都包含一個(gè)文字promise。只有當(dāng)十個(gè)子類通過(guò)或如果任何子類拒絕,***的then方法才能完成。

 
 
  1. var promiseVals = ['To ', 'be, ', 'or ', 
  2.     'not ', 'to ', 'be, ', 'that ', 
  3.     'is ', 'the ', 'question.']; 
  4.   
  5. var startParallelActions = function (){ 
  6.     var promises = []; 
  7.   
  8.     // Make an asynchronous action from each literal 
  9.     promiseVals.forEach(function(value){ 
  10.         promises.push(makeAPromise(value)); 
  11.     }); 
  12.   
  13.     // Consolidate all promises into a promise of promises 
  14.     return Q.all(promises); 
  15. }; 
  16.   
  17. startParallelActions ().then( . . . 

下面的地址, http://jsfiddle.net/mauget/XKCy2/,針對(duì)JSFiddle在瀏覽器中運(yùn)行十個(gè)并行promises,隨機(jī)的拒絕或通過(guò)。這里有完整的代碼用于檢查和變化if條件。重新運(yùn)行,直到你得到一個(gè)相反的完成。圖7顯示了積極的結(jié)果。

圖7:JSFiddle并行promises樣例

孕育 Promise

許多api返回的promise都有一個(gè)then函數(shù)——他們是thenable。通常我只是通過(guò)then處理thenable函數(shù)的結(jié)果。然而,$q,mpromise,和kew庫(kù)擁有同樣的API用于創(chuàng)建,拒絕,或者通過(guò)promise。這里有API文檔鏈接到每個(gè)庫(kù)的引用部分。我通常不需要構(gòu)造一個(gè)promise,除了本文中的包裝promise的未知描述和timeout函數(shù)。請(qǐng)參考哪些我創(chuàng)建的promises。

Promise庫(kù)互操作

大多數(shù)JavaScript promise庫(kù)在then級(jí)別進(jìn)行互操作。你可以從一個(gè)外部的promise創(chuàng)建一個(gè)promise,因?yàn)閜romise可以包裝任何類型的值。then可以支持跨庫(kù)工作。除了then,其他的promise函數(shù)則可能不同。如果你需要一個(gè)你的庫(kù)不包含的函數(shù),你可以將一個(gè)基于你的庫(kù)的promise包裝到一個(gè)新的,基于含有你所需函數(shù)的庫(kù)創(chuàng)建的promise里面。例如,JQuery的promise有時(shí)為人所詬病。那么你可以將其包裝到Q,$q,mpromise,或者kew庫(kù)的promise中進(jìn)行操作。

結(jié)語(yǔ)

現(xiàn)在我寫了這篇文章,而一年前我卻是猶豫要不要擁抱promise的那個(gè)。我只是單純地想完成一項(xiàng)工作。 我不想學(xué)習(xí)新的API,或是打破我原來(lái)的代碼(因?yàn)檎`解了promise)。我曾經(jīng)如此錯(cuò)誤地認(rèn)為!當(dāng)我下了一點(diǎn)注時(shí),就輕易就贏得了可喜的成果。

在這篇文章中,我已經(jīng)簡(jiǎn)單給出了一個(gè)單一的promise,promise鏈,和一個(gè)并行的promise的promise的的例子。 Promises不難使用。如果我可以使用它們,任何人都可以。 要查看完整的概念,我支持你點(diǎn)擊專家寫的參考指南。從Promises/A 的參考開始,從事實(shí)上的標(biāo)準(zhǔn)JavaScript的Promise 開始。

如果你還沒(méi)有直接使用的promise,試一下。下定決心:你會(huì)有一個(gè)不錯(cuò)的體驗(yàn)。我保證!

– Lou Mauget, asktheteam@keyholesoftware.com

參考鏈接

  • http://wiki.commonjs.org/wiki/Promises/A

  • https://github.com/bellbind/using-promise-q/

  • https://github.com/Medium/kew

  • https://docs.angularjs.org/api/ng/service/$q

  • https://github.com/aheckmann/mpromise

  • http://blog.mediumequalsmessage.com/promise-deferred-objects-in-javascript-pt2-practical-use

  • https://gist.github.com/domenic/3889970

  • http://sitr.us/2012/07/31/promise-pipelines-in-javascript.html

  • http://dailyjs.com/2014/02/20/promises-in-detail/

  • https://www.promisejs.org/

  • http://solutionoptimist.com/2013/12/27/javascript-promise-chains-2/

  • http://www.erights.org/elib/distrib/pipeline.html

  • http://zeroturnaround.com/rebellabs/monadic-futures-in-java8/


當(dāng)前文章:JavaScriptPromises相當(dāng)酷:一種有趣的方案庫(kù)
新聞來(lái)源:http://www.5511xx.com/article/dphoego.html