现在是否还有使用Q或BlueBird等承诺库的理由,因为我们拥有ES6承诺?

在Node.js添加了对promise的本地支持之后,是否还有理由使用像Q或者BlueBird这样的库?

例如,如果您正在开始一个新项目,并假设在这个项目中没有任何使用这些库的依赖关系,那么我们可以说没有更多的理由来使用这样的库吗?

古老的谚语说,你应该select正确的工具。 ES6承诺提供基础知识。 如果所有你想要或需要的是基础知识,那么应该/可以为你工作得很好。 但是,工具箱中有更多的工具,而不仅仅是基础知识,还有些情况下这些附加工具是非常有用的。 而且,我认为ES6承诺甚至会遗漏一些像Promisification这样的基础知识,在几乎每个node.js项目中都是有用的。

我对蓝鸟诺言图书馆最为熟悉,所以我将主要从我在图书馆的经历中讲话。

所以,这里是我使用更有能力的Promise库的六大理由

  1. 非Promisifiedasynchronous接口 .promisify().promisifyAll()对处理所有那些仍然需要普通callback但尚未返回promise的asynchronous接口非常有用 – 一行代码创build整个接口的promisified版本。

  2. 更快 – 在大多数环境中,蓝鸟比原生承诺要快得多 。

  3. asynchronous数组迭代的sortingPromise.mapSeries()Promise.reduce()允许您遍历数组,对每个元素调用asynchronous操作,但对asynchronous操作进行sorting,以便它们一个接一个地发生,而不是全部相同时间。 您可以这样做,因为目标服务器需要它或因为您需要将一个结果传递给下一个。

  4. Polyfill – 如果您想在老版本的浏览器客户端中使用承诺,无论如何您都需要使用polyfill。 也可以得到一个有能力的polyfill。 由于node.js具有ES6承诺,因此您不需要在node.js中使用polyfill,但可以在浏览器中进行填充。 如果你正在为node.js服务器和客户端编码,那么在两者中都有相同的承诺库和function(更容易共享代码,环境之间的上下文切换,使用常见的asynchronous代码编码技术等)可能是非常有用的。 )。

  5. 其他有用的function – 蓝鸟有Promise.map()Promise.some()Promise.any()Promise.filter()Promise.each()Promise.props()所有这些都偶尔得心应手。 虽然这些操作可以使用ES6承诺和附加代码来执行,但Bluebird提供的这些操作已经预先构build并预先testing过,所以使用它们更简单,代码也更less。

  6. 内置警告和完整的堆栈跟踪 – Bluebird有一些内置的警告,提醒你可能是错误的代码或错误的问题。 例如,如果您调用一个在.then()处理程序中创build新promise的函数,而不返回该promise(将其链接到当前promise链),那么在大多数情况下,这是一个意外错误,Bluebird会给你这是一个警告。 其他内置蓝鸟警告在这里描述 。

以下是关于这些不同主题的更多细节:

PromisifyAll

在任何node.js项目中,我都立即使用Bluebird,因为我在标准node.js模块(如fs模块.promisifyAll()上使用了.promisifyAll()

Node.js本身并不提供一个承诺接口到像fs模块那样执行asynchronousIO的内置模块。 所以,如果你想使用这些接口的承诺,你可以在每个你使用的模块函数上手工编写一个promise包装器,或者得到一个可以为你做的或者不使用promise的库。

Bluebird的Promise.promisify()Promise.promisifyAll()提供了一个自动包装node.js调用约定的asynchronousAPI来返回promise。 这是非常有用的和节省时间。 我用它所有的时间。

这是一个如何工作的例子:

 const Promise = require('bluebird'); const fs = Promise.promisifyAll(require('fs')); fs.readFileAsync('somefile.text').then(function(data) { // do something with data here }); 

另一种方法是手动为您想要使用的每个fs API创build自己的promise包装:

 const fs = require('fs'); function readFileAsync(file, options) { return new Promise(function(resolve, reject) { fs.readFile(file, options, function(err, data) { if (err) { reject(err); } else { resolve(data); } }); }); } readFileAsync('somefile.text').then(function(data) { // do something with data here }); 

而且,您必须手动为每个要使用的API函数执行此操作。 这显然没有意义。 这是样板代码。 你可能会得到一个工具,为你做这个工作。 蓝鸟的Promise.promisify()Promise.promisifyAll()就是这样一个实用程序。

其他有用的function

以下是我特别发现的一些Bluebirdfunction(下面有几个关于如何节省代码或加速开发的代码示例):

 Promise.promisify() Promise.promisifyAll() Promise.map() Promise.reduce() Promise.mapSeries() Promise.delay() 

Promise.map()除了其有用的function之外,还支持一个并发选项,可以让你指定应该允许同时运行多less个操作,当你有很多事情要做的时候这是特别有用的,但是可以压倒一些外部资源。

其中的一些可以被称为独立,并用于承诺本身parsing为一个可以节省大量代码的迭代。


填充工具

在一个浏览器项目中,由于您通常还想支持一些没有Promise支持的浏览器,因此您最终还是需要一个polyfill。 如果您也在使用jQuery,有时候可以使用jQuery中的promise支持(尽pipe在某些方面它是非常痛苦的,也许在jQuery 3.0中是固定的),但是如果项目涉及到任何有意义的asynchronous活动,蓝鸟的扩展function非常有用。


更快

另外值得注意的是,蓝鸟的承诺似乎比V8内置的承诺快得多。 看到这个post关于这个话题的更多讨论。


一个大事Node.js是失踪

什么会让我考虑在node.js开发中less使用Bluebird会是如果node.jsbuild立在一个promisify函数,所以你可以做这样的事情:

 const fs = requirep('fs'); fs.readFileAsync('somefile.text').then(function(data) { // do something with data here }); 

或者只是提供已经promisified方法作为内置模块的一部分。

在那之前,我和蓝鸟一起做这个事情:

 const Promise = require('bluebird'); const fs = Promise.promisifyAll(require('fs')); fs.readFileAsync('somefile.text').then(function(data) { // do something with data here }); 

让ES6承诺支持内置到node.js并且没有任何内置模块返回承诺似乎有点奇怪。 这需要在node.js中进行sorting 在那之前,我使用蓝鸟来提升整个图书馆。 所以,现在在node.js中实现了20%左右的承诺,因为没有任何内置模块允许您使用承诺,而无需先手动包装它们。


例子

下面是一个简单的Promise vs. Bluebird Promisify和Promise.map()的例子,用于并行读取一组文件并通知所有数据:

平原的承诺

 const files = ["file1.txt", "fileA.txt", "fileB.txt"]; const fs = require('fs'); // make promise version of fs.readFile() function fsReadFileP(file, options) { return new Promise(function(resolve, reject) { fs.readFile(file, options, function(err, data) { if (err) return reject(err); resolve(data); }); }); } Promise.all(files.map(fsReadFileP)).then(function(results) { // files data in results Array }, function(err) { // error here }); 

Bluebird Promise.map()Promise.promisifyAll()

 const Promise = require('bluebird'); const fs = Promise.promisifyAll(require('fs')); const files = ["file1.txt", "fileA.txt", "fileB.txt"]; Promise.map(files, fs.readFileAsync).then(function(results) { // files data in results Array }, function(err) { // error here }); 

这里有一个简单的Promise与Bluebird的Promisify和Promise.map()的例子,当你从一个远程主机读取一堆URL的时候,你最多可以一次读取4个URL,但是希望并行地保留多个请求:

简单的JS承诺

 const request = require('request'); const urls = [url1, url2, url3, url4, url5, ....]; // make promisified version of request.get() function requestGetP(url) { return new Promise(function(resolve, reject) { request.get(url, function(err, data) { if (err) return reject(err); resolve(data); }); }); } function getURLs(urlArray, concurrentLimit) { var numInFlight = 0; var index = 0; var results = new Array(urlArray.length); return new Promise(function(resolve, reject) { function next() { // load more until concurrentLimit is reached or until we got to the last one while (numInFlight < concurrentLimit && index < urlArray.length) { (function(i) { requestGetP(urlArray[index++]).then(function(data) { --numInFlight; results[i] = data; next(); }, function(err) { reject(err); }); ++numInFlight; })(index); } // since we always call next() upon completion of a request, we can test here // to see if there was nothing left to do or finish if (numInFlight === 0 && index === urlArray.length) { resolve(results); } } next(); }); } 

蓝鸟承诺

 const Promise = require('bluebird'); const request = Promise.promisifyAll(require('request')); const urls = [url1, url2, url3, url4, url5, ....]; Promise.map(urls, request.getAsync, {concurrency: 4}).then(function(results) { // urls fetched in order in results Array }, function(err) { // error here });