Bluebird

Bluebird

相關(guān)鏈接

用bluebird實(shí)現(xiàn)更加強(qiáng)大的Promise
bluebird中常用的Promise API
官方API
bluebird與原生Promise對(duì)象及bluebird模塊的中文API文檔

Promise API

NodeJs中fs.readFile方法的基本使用方式:

const fs = require('fs'),
path = require('path');

fs.readFile(path.join(__dirname, 'sample.txt'), 'utf-8', (err, data) => {
    if(err){
        console.error(err);
    }else{
        console.log(data);
    }
});

1. Promise.promisifyAll

函數(shù)Promise化是指將一個(gè)不符合promise規(guī)范的API改造成返回promise的API。Bluebird 的 Promise.promisifyAll 方法可以為一個(gè)對(duì)象的屬性中的所有方法創(chuàng)建一個(gè)對(duì)應(yīng)的使用Promise的版本。這些新創(chuàng)建方法的名稱(chēng)在已有方法的名稱(chēng)后加上"Async"后綴。
使用 BluebirdPromise.promisifyAll來(lái)轉(zhuǎn)換上面的方法:

const Promise = require('bluebird')
fs = require('fs')
path = require('path')
Promise.promisifyAll(fs);
//新方法名后面加了‘Async’后綴, 返回一個(gè)Promise對(duì)象
fs.readFileAsync(path.join(__dirname, 'sample.txt'), 'utf-8')
  .then(data => console.log(data))
  .catch(err => console.error(err));

2. Promise.promisify

如果不希望把一個(gè)對(duì)象的所有方法都轉(zhuǎn)換成使用Promise方式,可以使用Promise.promisify來(lái)轉(zhuǎn)換單個(gè)方法,比如:

Promise.promisify(require("fs").readFile)

3. Promise.fromCallback

對(duì)于一個(gè) NodeJS 格式的回調(diào)方法,可以使用 Promise.fromCallback 將其轉(zhuǎn)換成一個(gè) Promise?;卣{(diào)方法的結(jié)果決定了 Promise 的狀態(tài)。

4. .spread

spread方法與then方法類(lèi)似,當(dāng)Promise的結(jié)果為數(shù)組時(shí),可以使用spread方法把數(shù)組的元素打平(flatten)為回調(diào)方法的不同參數(shù):

Promise.resolve([1,2,3])
  .spread((v1, v2, v3) => console.log(v1 + v2 + v3));

5. .catch

catch 方法用來(lái)添加已回絕狀態(tài)時(shí)的回調(diào)方法,從.then()調(diào)用鏈中產(chǎn)生的任何異常都會(huì)被傳送到最近的.catch()函數(shù)中。
兩種使用方式:
捕獲所有異常
只添加回調(diào)方法,會(huì)捕獲所有的錯(cuò)誤情況

.catch(e => {

})

捕獲部分異常
使用錯(cuò)誤對(duì)象類(lèi)型或斷言來(lái)對(duì)錯(cuò)誤進(jìn)行過(guò)濾

.then(() => {
    ...
}).catch(TypeError, e => {

}).catch(ReferenceError, e => {

}).catch(e => {

})

6. .error

error方法和catch類(lèi)似,但是error只會(huì)處理真正的Error對(duì)象。Js中throw語(yǔ)句會(huì)拋出任何值,不一定是Error對(duì)象。throw拋出的任何值都會(huì)被catch處理,但是只有Error對(duì)象才會(huì)被error處理。

Promise.reject('not an error')
  .error(err => conosle.log('wrong la'))

7. .finally

無(wú)論promise調(diào)用鏈的情況如何,.finally都會(huì)在最后被調(diào)用。最后的返回值不能在句柄中被改變。

Promise.reject(new TypeError('type error'))
  .catch(TypeError, console.error)
  .finally(() => console.log('done'));

catch 只會(huì)捕獲 TypeError,而 finally 中的邏輯始終會(huì)被調(diào)用

8. .bind

創(chuàng)建一個(gè)promise對(duì)象,這個(gè)對(duì)象與給定的thisArg綁定,對(duì)象內(nèi)部的this將會(huì)指向被綁定的值。這個(gè)被綁定對(duì)象所產(chǎn)生的promise對(duì)象也會(huì)被綁定到thisArg。Example

9. 狀態(tài)相關(guān)

對(duì)于一個(gè)Promise對(duì)象,可以使用如下方法查看其內(nèi)部狀態(tài):

API Promise狀態(tài)
isPending 進(jìn)行中
isFulfilled 已滿(mǎn)足
isPending 已拒絕
isPending 已取消
value 獲取Promise滿(mǎn)足后的結(jié)果
reason 獲取Promise被拒后的結(jié)果

可以使用 cancel 方法來(lái)取消一個(gè) Promise,取消 Promise 只是表示 Promise 的回調(diào)方法不被調(diào)用,并不會(huì)自動(dòng)取消正在進(jìn)行的異步操作,取消功能默認(rèn)是禁用的,需要使用 Promise.config 來(lái)啟用該功能;如要添加自定義取消邏輯,Promise構(gòu)造方法參數(shù)中可以添加onCancel參數(shù),用來(lái)注冊(cè)Promise取消時(shí)的回調(diào)方法:

Promise.config({
    cancellation: true
});
new Promise((resolve, reject, onCancel) => {
    //
    onCancel(() => {
        //
    });

}).then(console.log).cancel();

10. Promise.join

用于協(xié)調(diào)多個(gè)并行的promise。當(dāng)需要處理一個(gè)不定數(shù)量但是規(guī)格一致的多個(gè)promise時(shí),.all()是較好的選擇。但是當(dāng)我們需要協(xié)調(diào)固定數(shù)量的離散的promise實(shí)例時(shí),Promise.join()是一種更加簡(jiǎn)單(以及更加優(yōu)雅)的方法。

let Promise = require('bluebird');
Promise.join(getPic(), getComment(), getTweets(), function(pics, comments, tweets){

});

11. Promise.try

通過(guò)Promise.try啟動(dòng)一個(gè)promise鏈,并將所有同步異常封裝到promise的reject處理中。
Example

12. Promise.method

Promise.method 用來(lái)封裝一個(gè)方法,使其返回 Promise。

13. 定時(shí)器

Promise.delay 返回的 Promise 會(huì)在指定的時(shí)間之后轉(zhuǎn)換到已滿(mǎn)足狀態(tài),并使用指定的值作為結(jié)果。Promise.timeout 用來(lái)為一個(gè)已有的 Promise 添加超時(shí)功能。

Promise.delay(1000, 'hello').then(console.log);
Promise.delay(1000, 'hello')
 .timeout(500, 'timed out')
 .then(console.log)
 .catch(console.error);

集合操作

1. Promise.all

Promise.all 接受一個(gè) Iterable 參數(shù),返回值:一個(gè)新的 Promise。結(jié)果 Promise 只有在 Iterable 中全部 Promise 對(duì)象都變?yōu)閞esolve時(shí),才會(huì)返回resolve的Promise實(shí)例;任何 Promise 出現(xiàn)錯(cuò)誤會(huì)導(dǎo)致結(jié)果 Promise 被拒絕。新的 Promise 的最終結(jié)果是一個(gè)包含 Iterable 中 Promise 的結(jié)果的數(shù)組。該 Iterable 中可以包含任何值。如果值不是 Promise,則其值會(huì)直接出現(xiàn)在結(jié)果中,并不需要等待 Promise 完成。

var files = [];
for(var i = 0; i < 10; i++){
    files.push(fs.writeFileAsync('file-' + i + ‘.txt’, '', 'utf-8'));
}
Promise.all(files).then(result => {
    //
})

Promise.props,類(lèi)似于.all,但是針對(duì)對(duì)象屬性的,而不是數(shù)組。

2. Promise.map

很多情況下需要把Iterable中對(duì)象轉(zhuǎn)為Promise后再等待這些Promise完成??梢允褂肞romise.map方法:
Promise.map(iterable, mapper, concurrency):
參數(shù):

  • iterable: Iterable對(duì)象
  • mapper: 轉(zhuǎn)化為Promise的方法
  • concurrency: 可選參數(shù),控制同時(shí)運(yùn)行的Promise的數(shù)量,默認(rèn)值為Infinity,不限制并發(fā)數(shù)
//以下代碼使用map代替array.push+Promise.all方法
Promise.map(['1.txt', '2.txt', '3.txt'],
   name => fs.readFileAsync(path.join(__dirname, name), 'utf-8')
).then(results => console.log(results.join(', '))).catch(console.error);

如果任何一個(gè)promise實(shí)例執(zhí)行失敗,則返回狀態(tài)為reject的Promise實(shí)例。
,即當(dāng)數(shù)組的元素對(duì)應(yīng)的promise被解決時(shí),mapper函數(shù)會(huì)盡快被調(diào)用。這意味著由最終解決組成的元素順序不一定和輸入時(shí)一樣。
Promise.mapSeries 的作用與 Promise.map 相同,只不過(guò) mapSeries 按照 Iterable 中的順序依次遍歷每個(gè)元素。

3. Promise.some

在有多個(gè) Promise 時(shí),如果只需要等待其中部分 Promise 完成,可以使用 Promise.some 并指定完成的 Promise 數(shù)量。

Promise.some([
 fs.readFileAsync(path.join(__dirname, '1.txt'), 'utf-8'),
 fs.readFileAsync(path.join(__dirname, '2.txt'), 'utf-8'),
 fs.readFileAsync(path.join(__dirname, '3.txt'), 'utf-8')
], 2).then(results => console.log(results.join(', '))).catch(console.error);

Promise.any: 相當(dāng)于Promise.some并把數(shù)量設(shè)為1,返回值為單個(gè)值(不是長(zhǎng)度為1的數(shù)組)。
Promise.race: 與any類(lèi)似,不過(guò) race 的結(jié)果有可能是被拒絕的 Promise,因此推薦的做法是使用 any。

4. .filter和.each

Promise.filter 可以等待多個(gè) Promise 的完成,并對(duì)結(jié)果進(jìn)行過(guò)濾。它實(shí)際上的效果相當(dāng)于在 Promise.map 之后使用 Array 的 filter 方法來(lái)進(jìn)行過(guò)濾。

Promise.filter([
 fs.readFileAsync('1.txt', 'utf-8'),
 fs.readFileAsync('2.txt', 'utf-8'),
 fs.readFileAsync('3.txt', 'utf-8')
], value => value.length > 1).then(results => console.log(results.join(', '))).catch(console.error);

.each依次遍歷一個(gè)數(shù)組或者一個(gè)數(shù)組的promise。遍歷函數(shù)會(huì)被傳入四個(gè)參數(shù):(total, item, index, arrayLength)。
如果任何一個(gè)promise實(shí)例執(zhí)行失敗,則返回狀態(tài)為reject的Promise實(shí)例。
如果遍歷函數(shù)返回了一個(gè)promise或者其他含有.then()方法的對(duì)象,那么在繼續(xù)下一個(gè)循環(huán)之前,這個(gè)promise的結(jié)果會(huì)被延遲。
官網(wǎng)例子(過(guò)濾當(dāng)前目錄下可訪(fǎng)問(wèn)的文件夾):

var Promise = require("bluebird");
var E = require("core-error-predicates");
var fs = Promise.promisifyAll(require("fs"));

fs.readdirAsync(process.cwd()).filter(function(fileName) {
    return fs.statAsync(fileName)
        .then(function(stat) {
            return stat.isDirectory();
        })
        .catch(E.FileAccessError, function() {
            return false;
        });
}).each(function(directoryName) {
    console.log(directoryName, " is an accessible directory");
});

5. Promise.reduce

Promise.reduce 把多個(gè) Promise 的結(jié)果縮減成單個(gè)值。其作用類(lèi)似 Array 的 reduce 方法,但是可以處理 Promise 對(duì)象。

Promise.reduce(['1.txt', '2.txt', '3.txt'],
 (total, name) => {
   return fs.readFileAsync(path.join(__dirname, name), 'utf-8').then(data => total + data.length);
 }, 0)
 .then(result => console.log(`Total size: ${result}`)).catch(console.error);

資源使用

資源釋放邏輯一般在finally中添加,但是當(dāng)Promise相互嵌套時(shí),很容易產(chǎn)生資源沒(méi)有被釋放的情況。Bluebird 提供了更加健壯的資源管理方式,即使用資源釋放器(disposer)和 Promise.using 方法。
資源釋放器以 Disposer 對(duì)象表示,通過(guò) Promise 的 disposer 方法來(lái)創(chuàng)建。創(chuàng)建時(shí)的參數(shù)是一個(gè)用來(lái)釋放資源的方法。該方法的第一個(gè)參數(shù)是資源對(duì)象,第二個(gè)參數(shù)是 Promise.using 產(chǎn)生的 Promise 對(duì)象。Disposer 對(duì)象可以傳遞給 Promise.using 來(lái)保證其資源釋放邏輯被執(zhí)行。

class Connection {
 query() {
   return Promise.resolve('query');
 }
 close() {
   console.log('close');
 }
}
class DB {
 connect() {
   return Promise.resolve(new Connection());
 }
}
const disposer = new DB().connect().disposer(connection => connection.close());
Promise.using(disposer, connection => connection.query())
 .then(console.log).catch(console.error);

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • title: promise總結(jié) 總結(jié)在前 前言 下文類(lèi)似 Promise#then、Promise#resolv...
    JyLie閱讀 12,428評(píng)論 1 21
  • Promise 對(duì)象 Promise 的含義 Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函...
    neromous閱讀 8,844評(píng)論 1 56
  • Prepending(進(jìn)行時(shí)),Resolve(成功了),Reject(失敗了),then......等 1.Pr...
    _菩提本無(wú)樹(shù)_閱讀 49,383評(píng)論 0 21
  • 這本書(shū)是跟希一起去羅湖圖書(shū)館的時(shí)候,希挑的。拿回家來(lái)讀時(shí),希馬上愛(ài)上了這只憨厚可愛(ài)又胃口極大的老虎。剛好社區(qū)讀書(shū)會(huì)...
    Ico_Hu閱讀 2,300評(píng)論 0 0
  • 這幾天和朋友去了淮南 看了朋友的對(duì)象 然后把他們的合照發(fā)給了我的另一個(gè)朋友 。 我對(duì)象登我的qq看到了照片,然后打...
    一片小綠葉閱讀 412評(píng)論 0 1

友情鏈接更多精彩內(nèi)容