Node.js:何时使用承诺与回调 [英] Node.js: When to use Promises vs Callbacks

查看:30
本文介绍了Node.js:何时使用承诺与回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在更新一些较旧的 Node.js 代码.在此过程中,我正在设计新模块以使用旧代码.我现在发现,与我第一次写这篇文章时相比,我更多地依赖于使用 ES6 承诺而不是回调.所以现在我混合了一些返回承诺的函数和一些回调函数——这很乏味.我认为最终应该重构以使用承诺.但在此之前...

I have some older Node.js code that I'm updating. In the process I'm designing new modules to work with the old code. I'm finding that now, as opposed to when I first wrote this, I rely more on using ES6 promises rather than callbacks. So now I have this mix of some functions returning promises and some taking callbacks - which is tedious. I think eventually it should be refactored to use promises. But before that is done...

在哪些情况下更喜欢使用 Promise 而在哪些情况下更喜欢回调?

What are the situations where promises are preferred and where are callbacks preferred?

是否有任何类型的情况回调可以比承诺更好地处理,反之亦然?

Is there any type of situation that a callback can handle better than a promise and vice-versa?

根据我目前所见,我真的看不出有任何理由使用回调代替承诺.是真的吗?

Based on what I've seen so far, I can't really see any reason to use callbacks instead of promises. Is that true?

推荐答案

首先,您几乎从不想编写包含回调和异步操作承诺的代码.如果您正在转向承诺或引入一些承诺,那么您可能希望将同一部分代码中的回调重构为承诺.对于合适的操作类型,promise 比普通回调有很多优点,当已经在某个代码区域工作时进行转换是非常值得的.

First off, you pretty much never want to write code that is a mix of callbacks and promises for async operations. If you're moving to promises or introducing some promises, then you probably want to refactor the callbacks in that same section of code into promises. For the appropriate types of operations, there are so many advantages of promises over plain callbacks that it is well worth the effort to convert when already working in an area of code.

Promise 非常适合:

  • 监控同步操作
  • 即只需要通知一次(通常是完成或错误)
  • 协调或管理多个异步操作,例如对异步操作进行排序或分支,或同时管理多个运行中的操作
  • 从嵌套或深度嵌套的异步操作传播错误
  • 为使用 async/await 准备代码(或现在使用转译器)
  • 符合 Promise 模型的操作,其中只有三种状态:pendingfulfilledrejected 并且状态从 转换>待定=>已完成 或来自 pending =>被拒绝的然后不能改变(单一的单向转换).
  • 动态链接或链接异步操作(例如执行这两个异步操作,检查结果,然后根据中间结果决定要执行哪些其他异步操作)
  • 同时管理异步和同步操作
  • 自动捕获异步完成回调中发生的任何异常并向上传播(在普通回调中,这些异常有时会被静默隐藏).
  • Monitoring synchronous operations
  • That need to notify only once (usually completion or error)
  • Coordinating or managing multiple asynchronous operations such as sequencing or branching async operations or managing multiple operations in flight at the same time
  • Propagating errors from nested or deeply nested async operations
  • Getting code ready for the use of async/await (or using it now with a transpiler)
  • Operations that fit the Promise model where there are only three states: pending, fulfilled and rejected and where the state transitions from pending => fulfilled or from pending => rejected can then not change (a single one-way transition).
  • Dynamically linking or chaining asynchronous operations (such as do these two async operations, examine the result, then decide which other async operations to do based on the intermediate result)
  • Managing a mix of asynchronous and synchronous operations
  • Automatically catching and propagating upwards any exceptions that occur in async completion callbacks (in plain callbacks these exceptions are sometimes silently hidden).

普通回调适用于承诺无法做到的事情:

  • 同步通知(例如Array.prototype.map()的回调)
  • 可能发生多次的通知(因此需要多次调用回调).Promise 是一次性设备,不能用于重复通知.
  • 无法映射到待处理、已完成、已拒绝单向状态模型的情况.

而且,我还会将 EventEmitter 添加到组合中.

And, I'd also add EventEmitter to the mix.

EventEmitter 非常适合:

  • 发布/订阅类型通知
  • 具有事件模型的接口,特别是当事件可以发生多次(如流)时
  • 当第 3 方代码想要参与或监控某些事情时,除了 eventEmitter 之外没有任何 API 时,会出现松耦合.无需设计 API.只需公开一个 eventEmitter 并定义一些事件和与之相关的数据即可.

关于将普通回调代码转换为 Promises 的注意事项

如果你的回调符合节点调用约定,回调作为最后一个参数传递并像这样调用callback(err, result),那么你在某种程度上会自动将父函数包装在一个带有 util.promisify() 或者如果使用 Bluebird promise 库,带有 Promise.promisify().

If your callbacks fit the node calling convention with the callback passed as the last argument and called like this callback(err, result), then you somewhat automatically wrap the parent function in a promise with util.promisify() in node.js or if using the Bluebird promise library, with Promise.promisify().

使用 Bluebird,您甚至可以一次性承诺整个模块(在 node.js 调用约定中使用异步回调),例如:

With Bluebird, you can even promisify an entire module (that uses async callbacks in the node.js calling convention) at once such as:

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

fs.writeFileAsync("file.txt", data).then(() => {
    // done here
}).catch(err => {
    // error here
});

<小时>

在 node.js 版本 8+

现在有 util.promisify() 它将使用 node.js 异步调用约定的异步函数转换为返回承诺的函数.

There is now util.promisify() which will convert an async function that uses the node.js async calling convention to a function that returns a promise.

来自文档的示例:

const util = require('util');
const fs = require('fs');

const stat = util.promisify(fs.stat);

// usage of promisified function
stat('.').then((stats) => {
  // Do something with `stats`
}).catch((error) => {
  // Handle the error.
});

这篇关于Node.js:何时使用承诺与回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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