首頁 web前端 js教程 NodeJS中利用Promise來封裝非同步函數_node.js

NodeJS中利用Promise來封裝非同步函數_node.js

May 16, 2016 pm 04:13 PM
promise

 在寫Node.js的過程中,連續的IO操作可能會導致“金字塔噩夢”,回調函數的多重嵌套讓代碼變的難以維護,利用CommonJs的Promise來封裝異步函數,使用統一的鏈式API來擺脫多重回呼的惡夢。

  Node.js提供的非阻塞IO模型允許我們利用回調函數的方式處理IO操作,但是當需要連續的IO操作時,你的回調函數會多重嵌套,程式碼很不美觀,而且不易維護,而且可能會有許多錯誤處理的重複程式碼,也就是所謂的「Pyramid of Doom」。

複製程式碼 程式碼如下:

step1(function (value1) {
    step2(value1, function(value2) {
        step3(value2, function(value3) {
            step4(value3, function(value4) {
                // Do something with value4
            });
        });
    });
});

  這其實就是Node.js的Control flow的問題,對於這個問題,解決方案都許多,比如利用async,或者eventProxy等,不過本文的主題是利用CommonJs規範中對Promise來解決這個問題。

什麼是Promise?

  CommonJs的Promise規範有許多種,我們一般討論的是Promise/A 規範,它定義了Promise的基本行為。

  Promise是一個對象,它通常代表一個在未來可能完成的非同步操作。這個操作可能成功也可能失敗,所以一個Promise物件一般有3個狀態:Pending,Fulfilled,Rejected。分別代表未完成、成功完成和操作失敗。一旦Promise物件的狀態從Pending變成Fulfilled或Rejected任一個,它的狀態都沒有辦法再被改變。

  一個Promise物件通常會有一個then方法,這個方法讓我們可以去操作未來可能成功後回傳的值或是失敗的原因。這個then方法是這樣子的:

promise.then(onFulfilled, onRejected)
顯而易見的是,then方法接受兩個參數,它們通常是兩個函數,一個是用來處理操作成功後的結果的,另一個是用來處理操作失敗後的原因的,這兩個函數的第一個參數分別是成功後的結果和失敗的原因。如果傳給then方法的不是一個函數,那麼這個參數就會被忽略。

  then方法的回傳值是一個Promise對象,這一個特點允許我們鍊式呼叫then來達到控制流程的效果。這裡有許多細節上的問題,例如值的傳遞或錯誤處理等。 Promise的規範是這樣定義的:

onFulfilled或onRejected函數的回傳值不是Promise對象,則該值將會作為下一個then方法中onFulfilled的第一個參數,如果傳回值是一個Promise對象,怎麼then方法的回傳值就是該Promise對象
onFulfilled或onRejected函數中如果有異常拋出,則該then方法的回傳的Promise物件狀態轉為Rejected,如果該Promise物件呼叫then,則Error物件會作為onRejected函數的第一個參數
如果Promise狀態變成Fulfilled而在then方法中沒有提供onFulfilled函數,則then方法傳回的Promise物件狀態變成Fulfilled且成功的結果為上一個Promise的結果,Rejected同理。
  補充一句,onFulfilled和onRejected都是非同步執行的。

規範的實作:q

  上面講的是Promise的規範,而我們需要的是它的實現,q是一個對Promise/A 有著較好實現規範的函式庫。

  首先我們需要創建一個Promise對象,關於Promise對象創建的規範在Promise/B中,這裡不做詳細的解釋,直接上代碼。

複製程式碼 程式碼如下:

    function(flag){
        var defer = q.defer();
        fs.readFile("a.txt", function(err, data){
        if(err) defer.reject(err);
            else defer.resolve(data);
            });
            return defer.promise;
    }

  多數Promise的實作在Promise的建立上大同小異,透過建立一個具有promise屬性的defer對象,如果成功取得到值則呼叫defer.resolve(value),如果失敗,則呼叫defer.reject(reason),最後回傳defer的promise屬性即可。這個過程可以理解為呼叫defer.resolve將Promise的狀態變成Fulfilled,呼叫defer.reject將Promise的狀態變成Rejected。

  在面對一系列連續的非同步方法時,怎麼利用Promise寫出漂亮的程式碼呢?看下下面的例子。

複製程式碼 程式碼如下:

    promise0.then(function(result){
        // dosomething
        return result;
    }).then(function(result) {
        // dosomething
        return promise1;   
    }).then(function(result) {
        // dosomething
    }).catch(function(ex) {
        console.log(ex);
    }).finally(function(){
        console.log("final");
    });

  在上面的程式碼中,then方法只接受OnFulfilled,而catch方法實際上就是then(null, OnRejected),這樣的話只要一系列非同步方法只要總是成功回傳值的,那麼程式碼就會瀑布式的向下運行,如果其中任一個非同步方法失敗或發生異常,那麼根據CommonJs的Promise規範,將執行catch中的function。 q也提供了finally方法,從字面上也很好理解,就是不論resolve還是reject,最後都會執行finally中的function。

  看起來似乎不錯,程式碼更以維護且美觀了,那麼如果希望並發呢?

複製程式碼 程式碼如下:

     q.all([promise0, promise1, promise2]).spread(function(val0, val1, val2){
                    console.log(arguments);
                }).then(function(){
                    console.log("done");
                }).catch(function(err){
                    console.log(err);
                });

  q也為並發提供了api,呼叫all方法並傳遞一個Promise數組即可繼續使用then的鍊式風格。還有像q.nfbind等可以將Node.js的原生API轉換成Promise來統一程式碼格式也是挺好的。更多api在這裡就不一一詳述了。

結論

  本文主要介紹透過使用Promise來解決Node.js控制流問題,但Promise也可同樣應用於前端,EMCAScript6已經提供了原生的API支援。需要指出的是Promise並不是唯一的解決方案,async也是一個很好的選擇,並且提供更友好的並發控制API,不過我覺得Promise在封裝具有非同步方法的函數時更具優勢。

好了,本文就先到這裡了,希望對大家能夠有所幫助。

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
4 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

言出必行:兌現承諾的好處和壞處 言出必行:兌現承諾的好處和壞處 Feb 18, 2024 pm 08:06 PM

在日常生活中,我們常常會遇到承諾與兌現之間的問題。無論是在個人關係中,或是在商業交易中,承諾的兌現都是建立信任的關鍵。然而,承諾的利與弊也常常會引起爭議。本文將探討承諾的利與弊,並給予一些建議,如何做到言出必行。承諾的利是顯而易見的。首先,承諾可以建立信任。當一個人信守承諾時,他會讓別人相信自己是個可信賴的人。信任是人與人之間建立的紐帶,它可以讓人們更加

在Vue應用中遇到Uncaught (in promise) TypeError怎麼辦? 在Vue應用中遇到Uncaught (in promise) TypeError怎麼辦? Jun 25, 2023 pm 06:39 PM

Vue是一款受歡迎的前端框架,在開發應用時經常會遇到各種各樣的錯誤和問題。其中,Uncaught(inpromise)TypeError是常見的一種錯誤型別。在本篇文章中,我們將探討它的產生原因和解決方法。什麼是Uncaught(inpromise)TypeError? Uncaught(inpromise)TypeError錯誤通常出現在

深入了解Promise.resolve() 深入了解Promise.resolve() Feb 18, 2024 pm 07:13 PM

Promise.resolve()詳解,需要具體程式碼範例Promise是JavaScript中一種用來處理非同步操作的機制。在實際開發中,常常需要處理一些需要依序執行的非同步任務,而Promise.resolve()方法就是用來傳回一個已經Fulfilled狀態的Promise物件。 Promise.resolve()是Promise類別的靜態方法,它接受一個

實例解析ES6 Promise的原理與使用 實例解析ES6 Promise的原理與使用 Aug 09, 2022 pm 03:49 PM

利用Promise對象,把普通函數改成返回Promise的形式,解決回調地獄的問題。明白Promise的成功失敗呼叫邏輯,可以靈活的進行調整。理解核心知識,先用起來,慢慢整合吸收知識。

promise物件有哪些 promise物件有哪些 Nov 01, 2023 am 10:05 AM

promise物件狀態有:1、pending:初始狀態,既不是成功,也不是失敗狀態;2、fulfilled:意味著操作成功完成;3、rejected:意味著操作失敗。一個Promise物件一旦完成,就會從pending狀態變成fulfilled或rejected狀態,且不能再改變。 Promise物件在JavaScript中被廣泛使用,以處理如AJAX請求、定時操作等非同步操作。

PHP 函數回傳 Promise 物件有什麼優勢? PHP 函數回傳 Promise 物件有什麼優勢? Apr 19, 2024 pm 05:03 PM

優點:非同步和非阻塞,不阻塞主執行緒;提高程式碼可讀性和可維護性;內建錯誤處理機制。

一文帶你輕鬆掌握Promise 一文帶你輕鬆掌握Promise Feb 10, 2023 pm 07:49 PM

前端js學習中,讓大家最難受的就是異步的問題,解決異步、回調地獄等問題時你必須得學會promise,對於多數前端程式設計師來說promise簡直就是噩夢,這篇文章就是從通俗易懂的角度做為切入點,幫助大家輕鬆掌握promise

哪些瀏覽器支援Promise? 哪些瀏覽器支援Promise? Feb 19, 2024 pm 04:41 PM

瀏覽器相容性:哪些瀏覽器能夠支援Promise?隨著Web應用程式的複雜性不斷提高,開發人員迫切需要解決JavaScript中的非同步程式設計問題。過去,開發人員通常使用回調函數來處理非同步操作,但這會導致程式碼複雜且難以維護。為了解決這個問題,ECMAScript6引入了Promise,它提供了一種更直觀、更靈活的處理非同步操作的方式。 Promise是一種用於處理異

See all articles