既然我们有ES6承诺,是否仍然有理由使用像Q或BlueBird这样的承诺库?[已关闭]
在 Node.js 添加了对 promise 的原生支持之后,是否还有理由使用 Q 或 BlueBird 等库?
例如,如果您正在启动一个新项目,并且假设在此项目中您没有任何使用这些库的依赖项,那么我们能说真的没有更多理由使用此类库吗?
在 Node.js 添加了对 promise 的原生支持之后,是否还有理由使用 Q 或 BlueBird 等库?
例如,如果您正在启动一个新项目,并且假设在此项目中您没有任何使用这些库的依赖项,那么我们能说真的没有更多理由使用此类库吗?
古老的谚语是,你应该为这项工作选择合适的工具。ES6 承诺提供了基础知识。如果你想要或需要的只是基础知识,那么这应该/可以很好地工作。但是,工具箱中的工具不仅仅是基础知识,而且在某些情况下,这些附加工具非常有用。而且,我认为ES6的承诺甚至缺少一些基本功能,例如在几乎每个节点.js项目中都很有用的promisization。
我最熟悉的是蓝鸟承诺库,所以我主要从我与该库的经验中发言。
所以,这是我使用功能更强大的承诺库的6大理由
非 Promisized 异步接口 - 对于处理所有那些仍然需要普通回调并且尚未返回 promise 的异步接口非常有用 - 一行代码即可创建整个接口的 Promisized 版本。.promisify()
.promisifyAll()
更快 - 在大多数环境中,Bluebird 明显快于本机承诺。
异步数组迭代的顺序 - 或者允许您循环访问数组,对每个元素调用异步操作,但对异步操作进行排序,以便它们一个接一个地发生,而不是同时发生。您可以这样做,因为目标服务器需要它,或者因为您需要将一个结果传递给下一个结果。Promise.mapSeries()
Promise.reduce()
Polyfill - 如果你想在旧版本的浏览器客户端中使用承诺,你无论如何都需要一个polyfill。不妨得到一个有能力的polyfill。由于node.js具有ES6承诺,因此您不需要node中的polyfill.js,但您可以在浏览器中使用。如果您正在对节点.js服务器和客户端进行编码,则在两者中具有相同的承诺库和功能可能非常有用(更易于共享代码,环境之间的上下文切换,对异步代码使用常用编码技术等)。
其他有用的功能 - Bluebird 有 、 、 、 和 所有这些偶尔都很方便。虽然这些操作可以使用ES6承诺和其他代码来执行,但Bluebird附带了这些已经预先构建和预先测试的操作,因此使用它们更简单,代码更少。Promise.map()
Promise.some()
Promise.any()
Promise.filter()
Promise.each()
Promise.props()
内置警告和全栈跟踪 - Bluebird 具有许多内置警告,可提醒您注意可能是错误的代码或错误的问题。例如,如果您调用一个函数,该函数在处理程序中创建新 promise 而不返回该 promise(将其链接到当前 promise 链中),那么在大多数情况下,这是一个意外的错误,Bluebird 会给您一个警告。此处介绍了其他内置的 Bluebird 警告。.then()
以下是有关这些不同主题的更多详细信息:
全宣告
在任何节点.js项目中,我立即在任何地方使用Bluebird,因为我在标准节点上使用了很多.js模块,如模块。.promisifyAll()
fs
Node.js本身并不为像模块一样执行异步 IO 的内置模块提供承诺接口。因此,如果你想在这些接口中使用 promise,你要么在你使用的每个模块函数周围手动编写一个 promise 包装器,要么得到一个可以为你做这件事的库,或者不使用 promise。fs
蓝鸟的,并提供节点的自动包装.js调用约定异步API返回承诺。它非常有用且节省时间。我一直在使用它。Promise.promisify()
Promise.promisifyAll()
以下是其工作原理的示例:
const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'));
fs.readFileAsync('somefile.text').then(function(data) {
// do something with data here
});
另一种方法是为要使用的每个 API 手动创建自己的 promise 包装器:fs
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()
其他有用的功能
以下是我特别发现的一些有用的Bluebird功能(下面有几个代码示例,说明这些功能如何保存代码或加快开发速度):
Promise.promisify()
Promise.promisifyAll()
Promise.map()
Promise.reduce()
Promise.mapSeries()
Promise.delay()
除了其有用的功能外,还支持并发选项,该选项允许您指定应允许同时运行多少个操作,这在您有很多事情要做但不能压倒某些外部资源时特别有用。Promise.map()
其中一些既可以称为独立,也可以用于承诺本身解析为可迭代的可迭代,可以节省大量代码。
聚填充
在浏览器项目中,由于您通常仍然希望支持某些不支持Promise的浏览器,因此您最终还是需要一个polyfill。如果你也使用jQuery,你有时可以使用jQuery内置的承诺支持(尽管它在某些方面是非常不标准的,也许在jQuery 3.0中是固定的),但是如果项目涉及任何重要的异步活动,我发现Bluebird中的扩展功能非常有用。
更快
同样值得注意的是,Bluebird的承诺似乎比V8中内置的承诺要快得多。有关该主题的更多讨论,请参阅此帖子。
缺少一个大事件节点.js
是什么让我考虑在node中使用Bluebird.js开发是如果node.js内置了一个promisify函数,那么你可以做这样的事情:
const fs = requirep('fs');
fs.readFileAsync('somefile.text').then(function(data) {
// do something with data here
});
或者只是提供已经过期的方法作为内置模块的一部分。
在那之前,我用Bluebird做这件事:
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中得到解决。在那之前,我使用Bluebird来宣传整个库。所以,感觉承诺大约20%在node中实现.js现在,因为没有一个内置模块允许您在不手动包装它们的情况下使用它们。
下面是一个普通 Promises 与 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 的示例,当从远程主机读取一堆 URL 时,您一次最多可以读取 4 个 URL,但希望在允许的范围内并行保留尽可能多的请求:Promise.map()
普通的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
});