摘要:今天對于處理異步調用已經有了很多成熟的方案,在我看來這些方案都無外乎在解決一個問題如何能看似順序地傳遞異步調用的結果,本文要說的就是原生提供的一個解決方案。在對進行敘述之前,依舊引用阮大的入門一書中的章節便于大家更嚴謹和全面的學習和參考。
異步回調的泥潭
異步回調是最直接的異步結果處理模式,將一個回調函數callback扔進異步處理函數中,當異步處理獲得結果之后再調用這個回調函數就可以繼續之后的處理,但是如果這個callback又是一個異步調用呢?眾所周知的,在JavaScript中異步回調的層層嵌套幾乎是反人性的,代碼編寫、修改和閱讀對我等有代碼潔癖的人而言是一種煎熬,這便是異步回調泥潭了。
今天對于處理異步調用已經有了很多成熟的方案,在我看來這些方案都無外乎在解決一個問題:“如何能看似順序地傳遞異步調用的結果?”,本文要說的Promise就是ES6原生提供的一個解決方案。
Promise在對Promise進行敘述之前,依舊引用阮大的《ECMAScript 6入門》一書中的Promise章節便于大家更嚴謹和全面的學習和參考。
承諾,即對未來的許諾,如果諾言實現,然后(then)就如何如何……Promise極其生動的講述了一個言出必行的故事。
new Promise(function(resolve, reject){ //開始實現承諾 .... .... if(承諾兌現時) { resolve(dollars); //兌現承諾的結果是得到"一大筆美金" } else { reject("絕交"); //沒兌現承諾就絕交 } }).then(function(dollars){ //然后有錢了,買房買車娶妻生子 let d1 = buyHouse(dollars); //把每次消費剩余的錢傳給下一個函數 let d2 = buyCar(d1); let d3 = marry(d2); makeBaby(d3); }).catch(function(result){//然后如果絕交了,還是繼續吃土 //繼續吃土 }); console.log("故事開始....");
看過上面的這個俗不可耐的故事之后需要理解幾件事情:
言出必行:一個Promise構造出來之后,構造時傳入的異步函數就立即執行;*
注:因大凡使用promise都是在異步調用場景,下文所說的異步函數都是指構造promise時傳入的函數*
Promise實例內部維護了一個狀態機,狀態變化只可能是pending到resolved或者pending到rejected;
執行resolve:pending變化到resolved
執行reject:pending變化到rejected
拋出錯誤:pending變化到rejected
then的第一個回調函數只會在發生了resolve之后執行,本質上是在Promise到達resolved狀態執行;
then的第二個回調函數或者catch的回調函數會在發生reject之后或者異步函數執行拋出錯誤時執行,本質上是在promise到達rejected狀態時執行;
異步函數執行得到結果可以通過resolve或者reject將結果傳出;
調用resolve傳入的值會作為then第一個回調函數的入參
調用reject傳入的值作為then第二個回調函數或者catch的回調函數的入參
如果異步函數拋出了異常,異常會作為then第二個回調函數或者catch的回調函數的入參
"故事開始...."會先輸出,而不是等到then的回調函數執行完畢才輸出,說明傳入then的回調函數是異步執行,同理catch也是一樣;
異步函數調用鏈then和catch都是Promise的實例方法,都返回一個新的Promise,因此可以輕而易舉地實現鏈式編程,比如上面的例子中“把每次消費剩余的錢”傳給下一個函數可以改寫成這樣:
....//前面省略 .then(function(dollars){ return buyHouse(dollars); }).then(function(d1){ return buyCar(d1); }).then(function(d2){ return marry(d2); }).then(function(d3){ return makeBaby(d3); }).catch(function(result){ //繼續吃土 });
看到這里你可能認為前一個then回調函數的返回值是后一個then的回調函數的入參,但這是不準確的,因為當then回調函數返回的是個Promise對象時,這個Promise對象到終態時后一個then才會執行,并且該Promise對象執行resolve時的入參才是后一個then的回調函數入參;
此時有必要對Promise的一個類方法resolve做以下說明,它的特性兩句話:
如果傳入的是個Promise對象,則直接返回這個Promise;
如果是其他任何一個值(包括Error對象和undefined)則直接轉換為一個resolved狀態的Promise對象;
比如說下面的代碼:
//以下的p1和p2邏輯上等同 let p1 = Promise.resolve(1); let p2 = new Promise(function(resolve, reject) { resolve(1); }); //以下的p3和p4等同 let p3 = new Promise(function(r, j) {}); let p4 = Promise.resolve(p3); console.log(p3 == p4); //true console.log(p3 === p4); //true //以下三者邏輯上等同 Promise.resolve().then(function(dollars) { return 1 + 1; }).then(function(v) { console.log(v); }); Promise.resolve().then(function(dollars) { return new Promise(function(r, j) { r(1 + 1) }); }).then(function(v) { console.log(v); }); Promise.resolve().then(function(dollars) { return Promise.resolve(1 + 1); }).then(function(v) { console.log(v); });
我們可以利用Promise異步執行結果傳出的機制和then的鏈式調用,將層層嵌套的函數調用變為通過then順序連接的鏈式調用
從寫法和形式上看是不是人性很多呢?
通過Promise實現的鏈式異步函數調用,以斐波那契數列舉例如下:
//一個異步的斐波那契計算 function fibonacci(v) { return new Promise(function(resolve, reject) { //每一個異步調用都返回了一個Promise setTimeout(function() { console.log(`${v.a}`); [v.a, v.b] = [v.b, v.a + v.b]; resolve(v); }, 500); }); } //以下兩者邏輯等同,每個then都等待上一個promise的結果形成一條鏈。 // fibonacci({ a: 0, b: 1 }) // .then(fibonacci) // .then(fibonacci) // .then(fibonacci) // .then(fibonacci) // .then(fibonacci) // .then(fibonacci); Promise.resolve() .then(() => fibonacci({ a: 0, b: 1 })) .then(fibonacci) .then(fibonacci) .then(fibonacci) .then(fibonacci) .then(fibonacci) .then(fibonacci);
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/86780.html
摘要:本文參考了以下文章之前的文章新特性印象之一新語法面對對象關鍵字看上面例子就能明白。定義類的,配合創建新對象。繼承非構造器對象的原型是。錯誤檢查繼承的目標一定要是個對象或者。的構造器是可改寫,但不可枚舉。引入了一個標簽,負責載入模塊。 本文參考了以下文章/PPT: Use ECMAScript 6 today Ecmascript 6 Whats next for Javascrip...
摘要:的翻譯文檔由的維護很多人說,阮老師已經有一本關于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。 JavaScript Promise 迷你書(中文版) 超詳細介紹promise的gitbook,看完再不會promise...... 本書的目的是以目前還在制定中的ECMASc...
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。寫一個符合規范并可配合使用的寫一個符合規范并可配合使用的理解的工作原理采用回調函數來處理異步編程。 JavaScript怎么使用循環代替(異步)遞歸 問題描述 在開發過程中,遇到一個需求:在系統初始化時通過http獲取一個第三方服務器端的列表,第三方服務器提供了一個接口,可通過...
摘要:回調函數這是異步編程最基本的方法。對象對象是工作組提出的一種規范,目的是為異步編程提供統一接口。誕生后,出現了函數,它將異步編程帶入了一個全新的階段。 更多詳情點擊http://blog.zhangbing.club/Ja... Javascript 語言的執行環境是單線程的,如果沒有異步編程,根本沒法用,非卡死不可。 為了解決這個問題,Javascript語言將任務的執行模式分成兩種...
摘要:所謂異步編程中的異步是相對于同步的概念的。是一系列異步編程規范的統稱。如果中的回調函數返回一個值,那么返回的將會成為接受狀態,并且將返回的值作為接受狀態的回調函數的參數值。參考介紹基礎篇深入理解與異步編程。 es6 promise與異步編程 對于一些還不具備大量編程經驗的朋友來說,promise可能是es6比較難以掌握的點。首先是很多名詞,比如Promises,es6 Promise,...
閱讀 3152·2021-11-22 12:01
閱讀 3772·2021-08-30 09:46
閱讀 788·2019-08-30 13:48
閱讀 3217·2019-08-29 16:43
閱讀 1663·2019-08-29 16:33
閱讀 1854·2019-08-29 13:44
閱讀 1416·2019-08-26 13:45
閱讀 2234·2019-08-26 11:44