既然我们有ES6承诺,还有理由使用Q或BlueBird等承诺库吗? [英] Are there still reasons to use promise libraries like Q or BlueBird now that we have ES6 promises?

查看:105
本文介绍了既然我们有ES6承诺,还有理由使用Q或BlueBird等承诺库吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Node.js添加了对promises的原生支持之后,还有理由使用像Q或BlueBird这样的库吗?

After Node.js added native support for promises, are there still reasons to use libraries like Q or BlueBird?

例如,如果你正在开始一个新项目并让我们在这个项目中假设你没有任何使用这些库的依赖项,我们可以说确实没有使用这些库的更多理由?

For example if you are starting a new project and let's assume in this project you don't have any dependencies that use these libraries, can we say that there are really no more reasons to use such libraries?

推荐答案

古老的谚语说你应该为这份工作挑选合适的工具。 ES6承诺提供基础知识。如果你想要或需要的只是基础知识,那么应该/可以为你做好。但是,工具箱中有更多工具而不仅仅是基础知识,并且在某些情况下,这些附加工具非常有用。而且,我认为ES6的承诺甚至缺少一些基本的东西,比如promisification,它们几乎在每个node.js项目中都很有用。

The old adage goes that you should pick the right tool for the job. ES6 promises provide the basics. If all you ever want or need is the basics, then that should/could work just fine for you. But, there are more tools in the tool bin than just the basics and there are situations where those additional tools are very useful. And, I'd argue that ES6 promises are even missing some of the basics like promisification that are useful in pretty much every node.js project.

我最熟悉使用蓝鸟承诺库,我将主要根据我对该图书馆的经验说话。

I'm most familiar with the Bluebird promise library so I'll speak mostly from my experience with that library.

因此,以下是我使用功能更强大的Promise库的六大理由


  1. 非Promisified异步接口 - .promisify() .promisifyAll ()非常有用,可以处理所有那些仍然需要普通回调并且还没有返回promises的异步接口 - 一行代码会创建一个整个接口的promisified版本。

  1. Non-Promisified async interfaces - .promisify() and .promisifyAll() are incredibly useful to handle all those async interfaces that still require plain callbacks and don't yet return promises - one line of code creates a promisified version of an entire interface.

更快 - Bluebird是比本机承诺快得多。

Faster - Bluebird is significantly faster than native promises in most environments.

异步数组迭代的排序 - Promise.mapSeries() Promise.reduce()允许您遍历数组,在每个元素上调用异步操作,但是对异步操作进行排序,使它们一个接一个地发生,而不是同时发生。您可以这样做,因为目标服务器需要它,或者您需要将一个结果传递给下一个。

Sequencing of async array iteration - Promise.mapSeries() or Promise.reduce() allow you to iterate through an array, calling an async operation on each element, but sequencing the async operations so they happen one after another, not all at the same time. You can do this either because the destination server requires it or because you need to pass one result to the next.

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

Polyfill - If you want to use promises in older versions of browser clients, you will need a polyfill anyway. May as well get a capable polyfill. Since node.js has ES6 promises, you don't need a polyfill in node.js, but you may in a browser. If you're coding both node.js server and client, it may be very useful to have the same promise library and features in both (easier to share code, context switch between environments, use common coding techniques for async code, etc...).

其他实用功能 - Bluebird有 Promise.map() Promise.some() Promise.any() Promise.filter () Promise.each() Promise.props()所有这些偶尔会派上用场。虽然可以使用ES6承诺和附加代码执行这些操作,但Bluebird已经预先构建并预先测试了这些操作,因此使用它们更简单,代码更少。

Other Useful Features - Bluebird has Promise.map(), Promise.some(), Promise.any(), Promise.filter(), Promise.each() and Promise.props() all of which are occasionally handy. While these operations can be performed with ES6 promises and additional code, Bluebird comes with these operations already pre-built and pre-tested so it's simpler and less code to use them.

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

Built in Warnings and Full Stack Traces - Bluebird has a number of built in warnings that alert you to issues that are probably wrong code or a bug. For example, if you call a function that creates a new promise inside a .then() handler without returning that promise (to link it into the current promise chain), then in most cases, that is an accidental bug and Bluebird will give you a warning to that effect. Other built-in Bluebird warnings are described here.

以下是有关这些主题的更多细节:

Here's some more detail on these various topics:

PromisifyAll

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

In any node.js project, I immediately use Bluebird everywhere because I use .promisifyAll() a lot on standard node.js modules like the fs module.

Node.js本身不提供内置模块的promise接口,这些模块执行异步IO,如 fs 模块。因此,如果你想在这些接口上使用promises,你可以手工编写你使用的每个模块函数的promise包装器,或者获得一个可以为你做这个或者不使用promises的库。

Node.js does not itself provide a promise interface to the built-in modules that do async IO like the fs module. So, if you want to use promises with those interfaces you are left to either hand code a promise wrapper around each module function you use or get a library that can do that for you or not use promises.

Bluebird的 Promise.promisify() Promise.promisifyAll()提供node.js的自动包装,调用约定async API来返回promises。这非常有用,节省时间。我一直都在使用它。

Bluebird's Promise.promisify() and Promise.promisifyAll() provide an automatic wrapping of node.js calling convention async APIs to return promises. It's extremely useful and time saving. I use it all the time.

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

Here's an example of how that works:

const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'));

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

另一种方法是为每个 fs <手动创建自己的承诺包装器/ code>您想要使用的API:

The alternative would be to manually create your own promise wrapper for each fs API you wanted to use:

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函数手动执行此操作。这显然没有意义。这是样板代码。您也可以使用一个实用程序来为您工作。 Bluebird的 Promise.promisify() Promise.promisifyAll()就是这样一个实用程序。

And, you have to manually do this for each API function you want to use. This clearly doesn't make sense. It's boilerplate code. You might as well get a utility that does this work for you. Bluebird's Promise.promisify() and Promise.promisifyAll() are such a utility.

其他实用功能

以下是我特别认为有用的一些Bluebird功能(有一对以下代码示例如何节省代码或加快开发速度):

Here are some of the Bluebird features that I specifically find useful (there are a couple code examples below on how these can save code or speed development):

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

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

In addition to its useful function, Promise.map() also supports a concurrency option that lets you specify how many operations should be allowed to be running at the same time which is particularly useful when you have a lot of something to do, but can't overwhelm some outside resource.

其中一些既可以单独调用,也可以用于承诺,它可以解析为可以节省大量代码的迭代。

Some of these can be both called stand-alone and used on a promise that itself resolves to an iterable which can save a lot of code.

Polyfill

在浏览器项目中,因为您通常需要为了仍然支持一些没有Promise支持的浏览器,你最终还是需要一个polyfill。如果你也在使用jQuery,你有时可以使用jQuery中内置的promise支持(尽管在某些方面很难非标准,可能在jQuery 3.0中修复),但是如果项目涉及任何重要的异步活动,我发现Bluebird中的扩展功能非常有用。

In a browser project, since you generally want to still support some browsers that don't have Promise support, you end up needing a polyfill anyway. If you're also using jQuery, you can sometimes just use the promise support built into jQuery (though it is painfully non-standard in some ways, perhaps fixed in jQuery 3.0), but if the project involves any signficant async activity, I find the extended features in Bluebird very useful.

更快

值得注意的是,Bluebird的承诺似乎明显快于V8内置的承诺。见这篇文章有关该主题的更多讨论。

Also worth noting that Bluebird's promises appear to be significantly faster than the promises built into V8. See this post for more discussion on that topic.

Big Thing Node.js缺失

如果node.js在promisify函数中构建,那么让我考虑在node.js开发中使用Bluebird的原因是什么,所以你可以这样做:

What would make me consider using Bluebird less in node.js development would be if node.js built in a promisify function so you could do something like this:

const fs = requirep('fs');

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

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

Or just offer already promisified methods as part of the built-in modules.

在此之前,我使用Bluebird执行此操作:

Until then, I do this with Bluebird:

const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'));

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

在node.js中内置ES6承诺支持并且没有内置任何内容似乎有点奇怪-in模块返回承诺。这需要在node.js中进行整理。在那之前,我使用Bluebird来宣传整个图书馆。因此,感觉承诺在node.js中实现约20%,因为没有任何内置模块允许您使用promises而不先手动包装它们。

It seems a bit odd to have ES6 promise support built into node.js and have none of the built-in modules return promises. This needs to get sorted out in node.js. Until then, I use Bluebird to promisify whole libraries. So, it feels like promises are about 20% implemented in node.js now since none of the built-in modules let you use promises with them without manually wrapping them first.

以下是普通Promises与Bluebird的promisify和 Promise.map()的示例用于并行读取一组文件并在完成所有数据时通知:

Here's an example of plain Promises vs. Bluebird's promisify and Promise.map() for reading a set of files in parallel and notifying when done with all the data:

普通承诺

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()

Bluebird Promise.map() and 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.map()从远程主机读取一堆URL时,您最多可以一次读取4个URL,但希望并行保留尽可能多的请求允许:


Here's an example of plain Promises vs. Bluebird's promisify and Promise.map() when reading a bunch of URLs from a remote host where you can read at most 4 at a time, but want to keep as many requests in parallel as allowed:

普通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
});

这篇关于既然我们有ES6承诺,还有理由使用Q或BlueBird等承诺库吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆