• <fieldset id="8imwq"><menu id="8imwq"></menu></fieldset>
  • <bdo id="8imwq"><input id="8imwq"></input></bdo>
    最新文章專題視頻專題問答1問答10問答100問答1000問答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
    問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
    當(dāng)前位置: 首頁 - 科技 - 知識(shí)百科 - 正文

    node使用promise替代回調(diào)函數(shù)

    來源:懂視網(wǎng) 責(zé)編:小采 時(shí)間:2020-11-27 22:15:16
    文檔

    node使用promise替代回調(diào)函數(shù)

    node使用promise替代回調(diào)函數(shù):在學(xué)習(xí) Node.js 過程中接觸到了如何使用 async 來控制并發(fā)(使用 async 控制并發(fā)) async 的本質(zhì)是一個(gè)流程控制。其實(shí)在異步編程中,還有一個(gè)更為經(jīng)典的模型,叫做 Promise/Deferred 模型(當(dāng)然還有更多相關(guān)解決方法,比如 eventproxy,co 等,
    推薦度:
    導(dǎo)讀node使用promise替代回調(diào)函數(shù):在學(xué)習(xí) Node.js 過程中接觸到了如何使用 async 來控制并發(fā)(使用 async 控制并發(fā)) async 的本質(zhì)是一個(gè)流程控制。其實(shí)在異步編程中,還有一個(gè)更為經(jīng)典的模型,叫做 Promise/Deferred 模型(當(dāng)然還有更多相關(guān)解決方法,比如 eventproxy,co 等,

    在學(xué)習(xí) Node.js 過程中接觸到了如何使用 async 來控制并發(fā)(使用 async 控制并發(fā))

    async 的本質(zhì)是一個(gè)流程控制。其實(shí)在異步編程中,還有一個(gè)更為經(jīng)典的模型,叫做 Promise/Deferred 模型(當(dāng)然還有更多相關(guān)解決方法,比如 eventproxy,co 等,到時(shí)候遇到在挖坑)

    首先,我們思考一個(gè)典型的異步編程模型,考慮這樣一個(gè)題目:讀取一個(gè)文件,在控制臺(tái)輸出這個(gè)文件內(nèi)容

    var fs = require('fs');
    fs.readFile('1.txt', 'utf8', function (err, data) {
     console.log(data);
    });
    

    看起來很簡(jiǎn)單,再進(jìn)一步: 讀取兩個(gè)文件,在控制臺(tái)輸出這兩個(gè)文件內(nèi)容

    var fs = require('fs');
    fs.readFile('1.txt', 'utf8', function (err, data) {
     console.log(data);
     fs.readFile('2.txt', 'utf8', function (err, data) {
     console.log(data);
     });
    });
    

    要是讀取更多的文件呢

    var fs = require('fs');
    fs.readFile('1.txt', 'utf8', function (err, data) {
     fs.readFile('2.txt', 'utf8', function (err, data) {
     fs.readFile('3.txt', 'utf8', function (err, data) {
     fs.readFile('4.txt', 'utf8', function (err, data) {
     // ...
     });
     });
     });
    });
    

    這就是傳說中的 callback hell,可以使用 async 來改善這段代碼,但是在本例中我們要用 promise/defer 來改善它

    promise 基本概念

    首先它是一個(gè)對(duì)象,它和 javascript 普通的對(duì)象沒什么區(qū)別,同時(shí),它也是一種規(guī)范,跟異步操作約定了統(tǒng)一的接口,表示一個(gè)異步操作的最終結(jié)果,以同步的方式來寫代碼,執(zhí)行的操作是異步的,但又保證程序執(zhí)行的順序是同步的

    1. promise 只有三種狀態(tài),未完成,完成 (fulfilled) 和失敗 (rejected)

    2. promise 的狀態(tài)可以由未完成轉(zhuǎn)換成完成,或者未完成轉(zhuǎn)換成失敗

    3. promise 的狀態(tài)轉(zhuǎn)換只發(fā)生一次

    promise 有一個(gè) then 方法,then 方法可以接受 3 個(gè)函數(shù)作為參數(shù)。前兩個(gè)函數(shù)對(duì)應(yīng) promise 的兩種狀態(tài) fulfilled, rejected 的回調(diào)函數(shù)。第三個(gè)函數(shù)用于處理進(jìn)度信息

    為了理解它,一些重要原理必須記牢:.then() 總是返回一個(gè)新的 promise,如下面代碼:

    var promise = readFile()
    var promise2 = promise.then(readAnotherFile, console.error)

    這里 then 的參數(shù) readAnotherFile, console.error 是代表異步操作成功后的動(dòng)作 onFulfilled 或失敗后的動(dòng)作 OnRejected,也就是說,讀取文件成功后執(zhí)行 readAnotherFile 函數(shù),否則失敗打印記錄錯(cuò)誤。這種實(shí)現(xiàn)是兩個(gè)中只有一種可能

    也可以理解為:

    promiseSomething().then(function (fulfilled) {
     // 當(dāng) promise 狀態(tài)變成 fulfilled 時(shí),調(diào)用此函數(shù)
    }, function (rejected) {
     // 當(dāng) promise 狀態(tài)變成 rejected 時(shí),調(diào)用此函數(shù)
    }, function (progress) {
     // 當(dāng)返回進(jìn)度信息時(shí),調(diào)用此函數(shù)
    });
    

    Promise 法則有兩部分必須分離:

    1. then() 總是返回一個(gè)新的 promise,每次你調(diào)用它,它不管回調(diào)做什么,因?yàn)?.then() 在回調(diào)被調(diào)用之前已經(jīng)給了你一個(gè)承諾 promise,回調(diào)的行為只影響承諾 promise 的實(shí)施,如果回調(diào)返回一個(gè)值,那么 promise 將使用那個(gè)值,如果這個(gè)值是一個(gè) promise,返回這個(gè) promise 實(shí)施后的值給這個(gè)值,如果回調(diào)拋出錯(cuò)誤,promise 將拒絕錯(cuò)誤

    2. 被 .then() 返回的 promise 是一個(gè)新的 promise ,它不同于那些 .then() 被調(diào)用的 promise,promise 長長的鏈條有時(shí)會(huì)好些隱藏這個(gè)事實(shí),不管如何,每次 .then() 調(diào)用都會(huì)產(chǎn)生一個(gè)新的 promise,這里必須注意的是你真正需要考慮的是你最后調(diào)用 .then() 可能代表失敗,那么如果你不捕獲這種失敗,那么容易導(dǎo)致你的錯(cuò)誤 exception 消失

    來看一個(gè)利用 q 來處理這種問題的簡(jiǎn)單例子:

    var Q = require('q');
    var defer = Q.defer();
    /**
     * 獲取初始 promise
     * @private
     */
    function getInitialPromise() {
     return defer.promise;
    }
     
    /**
     * 為 promise 設(shè)置三種狀態(tài)的回調(diào)函數(shù)
     */
    getInitialPromise().then(function (success) {
     console.log(success);
    }, function (error) {
     console.log(error);
    }, function (progress) {
     console.log(progress);
    });
    defer.notify('in progress'); // 控制臺(tái)打印 in progress
    defer.resolve('resolve'); // 控制臺(tái)打印 resolve
    defer.reject('reject'); // 沒有
    輸出。promise 的狀態(tài)只能改變一次

    promise 的傳遞

    then 方法會(huì)返回一個(gè) promise,在下面這個(gè)例子中,我們用 outputPromise 指向 then 返回的 promise。

    var outputPromise = getInputPromise().then(function (fulfilled) {
     
     }, function (rejected) {
     
     });
    

    現(xiàn)在 outputPromise 就變成了受 function(fulfilled) 或者 function(rejected) 控制狀態(tài)的 promise 了。直白的意思就是:當(dāng) function(fulfilled) 或者 function(rejected) 返回一個(gè)值,比如一個(gè)字符串,數(shù)組,對(duì)象等等,那么 outputPromise 的狀態(tài)就會(huì)變成 fulfilled。

    在下面這個(gè)例子中,我們可以看到,當(dāng)我們把 inputPromise 的狀態(tài)通過 defer.resovle() 變成 fulfilled 時(shí),控制臺(tái)輸出 fulfilled.

    當(dāng)我們把 inputPromise 的狀態(tài)通過 defer.reject() 變成 rejected,控制臺(tái)輸出 rejected

    var Q = require('q');
    var defer = Q.defer();
    /**
     * 通過 defer 獲得 promise
     * @private
     */
    function getInputPromise() {
     return defer.promise;
    }
     
    /**
     * 當(dāng) inputPromise 狀態(tài)由未完成變成 fulfil 時(shí),調(diào)用 function(fulfilled)
     * 當(dāng) inputPromise 狀態(tài)由未完成變成 rejected 時(shí),調(diào)用 function(rejected)
     * 將 then 返回的 promise 賦給 outputPromise
     * function(fulfilled) 和 function(rejected) 通過返回字符串將 outputPromise 的狀態(tài)由
     * 未完成改變?yōu)?fulfilled
     * @private
     */
    var outputPromise = getInputPromise().then(function (fulfilled) {
     return 'fulfilled';
    }, function (rejected) {
     return 'rejected';
    });
     
    /**
     * 當(dāng) outputPromise 狀態(tài)由未完成變成 fulfil 時(shí),調(diào)用 function(fulfilled),控制臺(tái)打印 'fulfilled: fulfilled'。
     * 當(dāng) outputPromise 狀態(tài)由未完成變成 rejected, 調(diào)用 function(rejected), 控制臺(tái)打印 'rejected: rejected'。
     */
    outputPromise.then(function (fulfilled) {
     console.log('fulfilled: ' + fulfilled);
    }, function (rejected) {
     console.log('rejected: ' + rejected);
    });
     
    /**
     * 將 inputPromise 的狀態(tài)由未完成變成 rejected
     */
    defer.reject(); // 
    輸出 fulfilled: rejected /** * 將 inputPromise 的狀態(tài)由未完成變成 fulfilled */ //defer.resolve(); // 輸出 fulfilled: fulfilled

    當(dāng) function(fulfilled) 或者 function(rejected) 拋出異常時(shí),那么 outputPromise 的狀態(tài)就會(huì)變成 rejected

    var Q = require('q');
    var fs = require('fs');
    var defer = Q.defer();
     
    /**
     * 通過 defer 獲得 promise
     * @private
     */
    function getInputPromise() {
     return defer.promise;
    }
     
    /**
     * 當(dāng) inputPromise 狀態(tài)由未完成變成 fulfil 時(shí),調(diào)用 function(fulfilled)
     * 當(dāng) inputPromise 狀態(tài)由未完成變成 rejected 時(shí),調(diào)用 function(rejected)
     * 將 then 返回的 promise 賦給 outputPromise
     * function(fulfilled) 和 function(rejected) 通過拋出異常將 outputPromise 的狀態(tài)由
     * 未完成改變?yōu)?reject
     * @private
     */
    var outputPromise = getInputPromise().then(function (fulfilled) {
     throw new Error('fulfilled');
    }, function (rejected) {
     throw new Error('rejected');
    });
     
    /**
     * 當(dāng) outputPromise 狀態(tài)由未完成變成 fulfil 時(shí),調(diào)用 function(fulfilled)。
     * 當(dāng) outputPromise 狀態(tài)由未完成變成 rejected, 調(diào)用 function(rejected)。
     */
    outputPromise.then(function (fulfilled) {
     console.log('fulfilled: ' + fulfilled);
    }, function (rejected) {
     console.log('rejected: ' + rejected);
    });
     
    /**
     * 將 inputPromise 的狀態(tài)由未完成變成 rejected
     */
    defer.reject(); // 控制臺(tái)打印 rejected [Error:rejected]
     
    /**
     * 將 inputPromise 的狀態(tài)由未完成變成 fulfilled
     */
    //defer.resolve(); // 控制臺(tái)打印 rejected [Error:fulfilled]
    

    當(dāng) function(fulfilled) 或者 function(rejected) 返回一個(gè) promise 時(shí),outputPromise 就會(huì)成為這個(gè)新的 promise.

    這樣做的意義在于聚合結(jié)果 (Q.all),管理延時(shí),異?;謴?fù)等等

    比如說我們想要讀取一個(gè)文件的內(nèi)容,然后把這些內(nèi)容打印出來??赡軙?huì)寫出這樣的代碼:

    // 錯(cuò)誤的寫法
    var outputPromise = getInputPromise().then(function (fulfilled) {
     fs.readFile('test.txt', 'utf8', function (err, data) {
     return data;
     });
    });
    

    然而這樣寫是錯(cuò)誤的,因?yàn)?function(fulfilled) 并沒有返回任何值。需要下面的方式:

    var Q = require('q');
    var fs = require('fs');
    var defer = Q.defer();
     
    /**
     * 通過 defer 獲得promise
     * @private
     */
    function getInputPromise() {
     return defer.promise;
    }
     
    /**
     * 當(dāng) inputPromise 狀態(tài)由未完成變成 fulfil時(shí),調(diào)用 function(fulfilled)
     * 當(dāng) inputPromise 狀態(tài)由未完成變成 rejected時(shí),調(diào)用 function(rejected)
     * 將 then 返回的 promise 賦給 outputPromise
     * function(fulfilled) 將新的 promise 賦給 outputPromise
     * 未完成改變?yōu)?reject
     * @private
     */
    var outputPromise = getInputPromise().then(function (fulfilled) {
     var myDefer = Q.defer();
     fs.readFile('test.txt', 'utf8', function (err, data) {
     if (!err && data) {
     myDefer.resolve(data);
     }
     });
     return myDefer.promise;
    }, function (rejected) {
     throw new Error('rejected');
    });
     
    /**
     * 當(dāng) outputPromise 狀態(tài)由未完成變成 fulfil 時(shí),調(diào)用 function(fulfilled),控制臺(tái)打印 test.txt 文件內(nèi)容。
     *
     */
    outputPromise.then(function (fulfilled) {
     console.log(fulfilled);
    }, function (rejected) {
     console.log(rejected);
    });
     
    /**
     * 將 inputPromise 的狀態(tài)由未完成變成 rejected
     */
    //defer.reject();
     
    /**
     * 將 inputPromise 的狀態(tài)由未完成變成 fulfilled
     */
    defer.resolve(); // 控制臺(tái)打印出 test.txt 的內(nèi)容
    

    方法傳遞

    方法傳遞有些類似于 Java 中的 try 和 catch。當(dāng)一個(gè)異常沒有響應(yīng)的捕獲時(shí),這個(gè)異常會(huì)接著往下傳遞

    方法傳遞的含義是當(dāng)一個(gè)狀態(tài)沒有響應(yīng)的回調(diào)函數(shù),就會(huì)沿著 then 往下找

    沒有提供 function(rejected)

    var outputPromise = getInputPromise().then(function (fulfilled) { })

    如果 inputPromise 的狀態(tài)由未完成變成 rejected, 此時(shí)對(duì) rejected 的處理會(huì)由 outputPromise 來完成

    var Q = require('q');
    var fs = require('fs');
    var defer = Q.defer();
    /**
     * 通過defer獲得promise
     * @private
     */
    function getInputPromise() {
     return defer.promise;
    }
     
    /**
     * 當(dāng) inputPromise 狀態(tài)由未完成變成 fulfil 時(shí),調(diào)用 function(fulfilled)
     * 當(dāng) inputPromise 狀態(tài)由未完成變成 rejected 時(shí),這個(gè) rejected 會(huì)傳向 outputPromise
     */
    var outputPromise = getInputPromise().then(function (fulfilled) {
     return 'fulfilled'
    });
    outputPromise.then(function (fulfilled) {
     console.log('fulfilled: ' + fulfilled);
    }, function (rejected) {
     console.log('rejected: ' + rejected);
    });
     
    /**
     * 將 inputPromise 的狀態(tài)由未完成變成 rejected
     */
    defer.reject('inputpromise rejected'); // 控制臺(tái)打印 rejected: inputpromise rejected
     
    /**
     * 將 inputPromise的狀態(tài)由未完成變成fulfilled
     */
    //defer.resolve();
    

    沒有提供 function(fulfilled)

    var outputPromise = getInputPromise().then(null, function (rejected) { })

    如果 inputPromise 的狀態(tài)由未完成變成 fulfilled, 此時(shí)對(duì) fulfil 的處理會(huì)由 outputPromise 來完成

    var Q = require('q');
    var fs = require('fs');
    var defer = Q.defer();
     
    /**
     * 通過defer獲得promise
     * @private
     */
    function getInputPromise() {
     return defer.promise;
    }
     
    /**
     * 當(dāng) inputPromise 狀態(tài)由未完成變成 fulfil時(shí),傳遞給 outputPromise
     * 當(dāng) inputPromise 狀態(tài)由未完成變成 rejected時(shí),調(diào)用 function(rejected)
     * function(fulfilled) 將新的 promise 賦給 outputPromise
     * 未完成改變?yōu)?reject
     * @private
     */
    var outputPromise = getInputPromise().then(null, function (rejected) {
     return 'rejected';
    });
     
    outputPromise.then(function (fulfilled) {
     console.log('fulfilled: ' + fulfilled);
    }, function (rejected) {
     console.log('rejected: ' + rejected);
    });
     
    /**
     * 將 inputPromise 的狀態(tài)由未完成變成 rejected
     */
    // defer.reject('inputpromise rejected');
     
    /**
     * 將 inputPromise 的狀態(tài)由未完成變成fulfilled
     */
    defer.resolve('inputpromise fulfilled'); // 控制臺(tái)打印fulfilled: inputpromise fulfilled
    

    可以使用 fail(function(error)) 來專門針對(duì)錯(cuò)誤處理,而不是使用 then(null,function(error))

    var outputPromise = getInputPromise().fail(function (error) { })

    看這個(gè)例子:

    var Q = require('q');
    var fs = require('fs');
    var defer = Q.defer();
    /**
     * 通過defer獲得promise
     * @private
     */
    function getInputPromise() {
     return defer.promise;
    }
     
    /**
     * 當(dāng) inputPromise 狀態(tài)由未完成變成 fulfil 時(shí),調(diào)用 then(function(fulfilled))
     * 當(dāng) inputPromise 狀態(tài)由未完成變成 rejected 時(shí),調(diào)用 fail(function(error))
     * function(fulfilled) 將新的 promise 賦給 outputPromise
     * 未完成改變?yōu)閞eject
     * @private
     */
    var outputPromise = getInputPromise().then(function (fulfilled) {
     return fulfilled;
    }).fail(function (error) {
     console.log('fail: ' + error);
    });
    /**
     * 將 inputPromise 的狀態(tài)由未完成變成 rejected
     */
    defer.reject('inputpromise rejected');// 控制臺(tái)打印 fail: inputpromise rejected
     
    /**
     * 將 inputPromise 的狀態(tài)由未完成變成 fulfilled
     */
    //defer.resolve('inputpromise fulfilled');
    

    可以使用 progress(function (progress)) 來專門針對(duì)進(jìn)度信息進(jìn)行處理,而不是使用 then(function (success) { }, function (error) { }, function (progress) { })

    var Q = require('q');
    var defer = Q.defer();
    /**
     * 獲取初始 promise
     * @private
     */
    function getInitialPromise() {
     return defer.promise;
    }
    /**
     * 為 promise 設(shè)置 progress 信息處理函數(shù)
     */
    var outputPromise = getInitialPromise().then(function (success) {
     
    }).progress(function (progress) {
     console.log(progress);
    });
     
    defer.notify(1);
    defer.notify(2); // 控制臺(tái)打印 1,2
    

    promise 鏈

    promise 鏈提供了一種讓函數(shù)順序執(zhí)行的方法

    函數(shù)順序執(zhí)行是很重要的一個(gè)功能。比如知道用戶名,需要根據(jù)用戶名從數(shù)據(jù)庫中找到相應(yīng)的用戶,然后將用戶信息傳給下一個(gè)函數(shù)進(jìn)行處理

    var Q = require('q');
    var defer = Q.defer();
    // 一個(gè)模擬數(shù)據(jù)庫
    var users = [{ 'name': 'andrew', 'passwd': 'password' }];
    function getUsername() {
     return defer.promise;
    }
     
    function getUser(username) {
     var user;
     users.forEach(function (element) {
     if (element.name === username) {
     user = element;
     }
     });
     return user;
    }
     
    // promise 鏈
    getUsername().then(function (username) {
     return getUser(username);
    }).then(function (user) {
     console.log(user);
    });
     
    defer.resolve('andrew');

    我們通過兩個(gè) then 達(dá)到讓函數(shù)順序執(zhí)行的目的。

    then 的數(shù)量其實(shí)是沒有限制的。當(dāng)然,then 的數(shù)量過多,要手動(dòng)把他們鏈接起來是很麻煩的。比如

    foo(initialVal).then(bar).then(baz).then(qux)

    這時(shí)我們需要用代碼來動(dòng)態(tài)制造 promise 鏈

    var funcs = [foo, bar, baz, qux]
    var result = Q(initialVal) 
    funcs.forEach(function (func) {
     result = result.then(func)
    })
    return result
    

    當(dāng)然,我們可以再簡(jiǎn)潔一點(diǎn)

    var funcs = [foo, bar, baz, qux]
    funcs.reduce(function (pre, current),Q(initialVal){
     return pre.then(current)
    })
    

    看一個(gè)具體的例子

    function foo(result) {
     console.log(result);
     return result + result;
    }
     
    // 手動(dòng)鏈接
    Q('hello').then(foo).then(foo).then(foo);
     
    // 控制臺(tái)
    輸出: hello // hellohello // hellohellohello // 動(dòng)態(tài)鏈接 var funcs = [foo, foo, foo]; var result = Q('hello'); funcs.forEach(function (func) { result = result.then(func); }); // 精簡(jiǎn)后的動(dòng)態(tài)鏈接 funcs.reduce(function (prev, current) { return prev.then(current); }, Q('hello'));

    對(duì)于 promise 鏈,最重要的是需要理解為什么這個(gè)鏈能夠順序執(zhí)行。如果能夠理解這點(diǎn),那么以后自己寫 promise 鏈可以說是輕車熟路啊

    promise 組合

    回到我們一開始讀取文件內(nèi)容的例子。如果現(xiàn)在讓我們把它改寫成 promise 鏈,是不是很簡(jiǎn)單呢?

    var Q = require('q'),
     fs = require('fs');
     
    function printFileContent(fileName) {
     return function () {
     var defer = Q.defer();
     fs.readFile(fileName, 'utf8', function (err, data) {
     if (!err && data) {
     console.log(data);
     defer.resolve();
     }
     })
     return defer.promise;
     }
    }
     
    // 手動(dòng)鏈接
    printFileContent('sample01.txt')()
     .then(printFileContent('sample02.txt'))
     .then(printFileContent('sample03.txt'))
     .then(printFileContent('sample04.txt')); // 控制臺(tái)順序打印 sample01 到 sample04 的內(nèi)容
    

    很有成就感是不是。然而如果仔細(xì)分析,我們會(huì)發(fā)現(xiàn)為什么要他們順序執(zhí)行呢,如果他們能夠并行執(zhí)行不是更好嗎? 我們只需要在他們都執(zhí)行完成之后,得到他們的執(zhí)行結(jié)果就可以了

    我們可以通過 Q.all([promise1,promise2...]) 將多個(gè) promise 組合成一個(gè) promise 返回。 注意:

    1. 當(dāng) all 里面所有的 promise 都 fulfil 時(shí),Q.all 返回的 promise 狀態(tài)變成 fulfil

    2. 當(dāng)任意一個(gè) promise 被 reject 時(shí),Q.all 返回的 promise 狀態(tài)立即變成 reject

    我們來把上面讀取文件內(nèi)容的例子改成并行執(zhí)行吧

    var Q = require('q');
    var fs = require('fs');
    /**
     *讀取文件內(nèi)容
     *@private
     */
    function printFileContent(fileName) {
     // Todo: 這段代碼不夠簡(jiǎn)潔??梢允褂?Q.denodeify 來簡(jiǎn)化
     var defer = Q.defer();
     
     fs.readFile(fileName, 'utf8', function (err, data) {
     if (!err && data) {
     console.log(data);
     defer.resolve(fileName + ' success ');
     } else {
     defer.reject(fileName + ' fail ');
     }
     })
     
     return defer.promise;
     
    }
     
    Q.all([printFileContent('sample01.txt'), printFileContent('sample02.txt'), printFileContent('sample03.txt'), printFileContent('sample04.txt')])
     .then(function (success) {
     console.log(success);
     }); // 控制臺(tái)打印各個(gè)文件內(nèi)容 順序不一定
    

    現(xiàn)在知道 Q.all 會(huì)在任意一個(gè) promise 進(jìn)入 reject 狀態(tài)后立即進(jìn)入 reject 狀態(tài)。如果我們需要等到所有的 promise 都發(fā)生狀態(tài)后(有的 fulfil, 有的 reject),再轉(zhuǎn)換 Q.all 的狀態(tài), 這時(shí)我們可以使用 Q.allSettled

    var Q = require('q'),
     fs = require('fs');
    /**
     *讀取文件內(nèi)容
     *@private
     */
     
    function printFileContent(fileName) {
     
     // Todo: 這段代碼不夠簡(jiǎn)潔??梢允褂肣.denodeify來簡(jiǎn)化
     var defer = Q.defer();
     
     fs.readFile(fileName, 'utf8', function (err, data) {
     if (!err && data) {
     console.log(data);
     defer.resolve(fileName + ' success ');
     } else {
     defer.reject(fileName + ' fail ');
     }
     })
     
     return defer.promise;
     
    }
     
    Q.allSettled([printFileContent('nosuchfile.txt'), printFileContent('sample02.txt'), printFileContent('sample03.txt'), printFileContent('sample04.txt')])
     .then(function (results) {
     results.forEach(
     function (result) {
     console.log(result.state);
     }
     );
     });
    

    結(jié)束 promise 鏈

    通常,對(duì)于一個(gè) promise 鏈,有兩種結(jié)束的方式。第一種方式是返回最后一個(gè) promise

    如 return foo().then(bar);

    第二種方式就是通過 done 來結(jié)束 promise 鏈

    如 foo().then(bar).done()

    為什么需要通過 done 來結(jié)束一個(gè) promise 鏈呢? 如果在我們的鏈中有錯(cuò)誤沒有被處理,那么在一個(gè)正確結(jié)束的 promise 鏈中,這個(gè)沒被處理的錯(cuò)誤會(huì)通過異常拋出

    var Q = require('q'); 
    function getPromise(msg, timeout, opt) { 
     var defer = Q.defer(); 
     setTimeout(function () {
     console.log(msg);
     if (opt)
     defer.reject(msg);
     else
     defer.resolve(msg);
     }, timeout); 
     return defer.promise; 
    }
     
    /**
     * 沒有用 done() 結(jié)束的 promise 鏈
     * 由于 getPromse('2',2000,'opt') 返回 rejected, getPromise('3',1000) 就沒有執(zhí)行
     * 然后這個(gè)異常并沒有任何提醒,是一個(gè)潛在的 bug
     */
    getPromise('1', 3000)
     .then(function () { return getPromise('2', 2000, 'opt') })
     .then(function () { return getPromise('3', 1000) });
     
    /**
     * 用 done() 結(jié)束的 promise 鏈
     * 有異常拋出
     */
    getPromise('1', 3000)
     .then(function () { return getPromise('2', 2000, 'opt') })
     .then(function () { return getPromise('3', 1000) })
     .done();
    

    附錄:一個(gè) Promise 簡(jiǎn)單的應(yīng)用(Node.js筆記(5)promise)

    附:Promises/A+ 規(guī)范

    promise 代表一個(gè)異步操作的最終結(jié)果。主要通過 promise 的 then 方法訂閱其最終結(jié)果的處理回調(diào)函數(shù),和訂閱因某原因無法成功獲取最終結(jié)果的處理回調(diào)函數(shù)。

    更對(duì)詳細(xì)見:Promises/A+

    A 與 A+ 的不同點(diǎn)

    1. A+ 規(guī)范通過術(shù)語 thenable 來區(qū)分 promise 對(duì)象
    2. A+ 定義 onFulfilled/onRejectd 必須是作為函數(shù)來調(diào)用,而且調(diào)用過程必須是異步的
    3. A+ 嚴(yán)格定義了 then 方法鏈?zhǔn)秸{(diào)用時(shí),onFulfilled/onRejectd 的調(diào)用順序

    聲明:本網(wǎng)頁內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

    文檔

    node使用promise替代回調(diào)函數(shù)

    node使用promise替代回調(diào)函數(shù):在學(xué)習(xí) Node.js 過程中接觸到了如何使用 async 來控制并發(fā)(使用 async 控制并發(fā)) async 的本質(zhì)是一個(gè)流程控制。其實(shí)在異步編程中,還有一個(gè)更為經(jīng)典的模型,叫做 Promise/Deferred 模型(當(dāng)然還有更多相關(guān)解決方法,比如 eventproxy,co 等,
    推薦度:
    標(biāo)簽: 回調(diào) promise node
    • 熱門焦點(diǎn)

    最新推薦

    猜你喜歡

    熱門推薦

    專題
    Top
    主站蜘蛛池模板: 亚洲精品成人久久久| 久久精品亚洲中文字幕无码麻豆 | 国产精品日日摸夜夜添夜夜添1国产精品va欧美精 | 婷婷久久精品国产| 久久精品男人影院| 国语自产精品视频在线区| 亚洲av无码成人精品区在线播放| 成人午夜精品亚洲日韩| 国产精品成人在线| 国产精品无码一区二区三级| 婷婷五月深深久久精品| 亚洲精品美女久久久久99小说| 精品国产一区二区22| 国产精品国产三级在线高清观看 | 久久99精品国产自在现线小黄鸭| 久久精品无码免费不卡| 国产精品无码不卡一区二区三区| 久久青青草原精品影院| 久久96国产精品久久久| xxx国产精品视频| 在线精品亚洲一区二区小说| 欧美 日韩 精品 另类视频| 国产亚洲精品国看不卡| 国产精品成人99久久久久| 女人香蕉久久**毛片精品| 精品免费视在线观看| 国产欧美国产精品第一区| 国产精品毛片一区二区三区| 精品一区二区三区免费毛片爱| 嫖妓丰满肥熟妇在线精品| 欧美精品v国产精品v日韩精品| 亚洲av永久无码精品秋霞电影影院| 中文字幕日韩精品在线| 亚洲精品视频在线观看你懂的| 无码人妻精品一区二区蜜桃百度| 男人的天堂精品国产一区| 男女男精品网站免费观看| 亚洲婷婷国产精品电影人久久| 无码日韩精品一区二区免费 | 久久久精品视频免费观看| 日韩精品无码久久一区二区三|