承诺链-所有功能都应承诺 [英] Promise chaining - should all functions need to be promises

查看:64
本文介绍了承诺链-所有功能都应承诺的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我将三个异步函数链接在一起,即func1-> func2-> func3,看来有两种方法可以实现.

Assuming I have three asynchronous functions to be chained together, func1 --> func2 --> func3, it seems there are two ways to do it.

选项1:承诺第一个函数 func1p = Promise.promisify(func1),不另两个函数,然后创建如下所示的链:

Option 1: promisify the first function, func1p = Promise.promisify(func1), leave the other two alone, and then create a chain like this:

func1p
  .then(func2)
  .then(func3)
  .catch(err)

选项2:承诺所有三个函数, func1p = Promise.promisify(func1) func2p = Promise.promisify(func2) func3p = Promise.promisify(func3),然后创建一个像这样的链:

Option 2: promisify all three functions, func1p = Promise.promisify(func1), func2p = Promise.promisify(func2), func3p = Promise.promisify(func3) and then create a chain like this:

func1p
  .then(func2p)
  .then(func3p)
  .catch(err)

根据 MDN Web文档 then 函数(始终)会返回一个新的Promise.因此,在我看来,没有必要对func2和func3进行承诺化,因为func1p的 then 函数已经对它们进行了承诺".换句话说,选项1应该足够.

According to MDN Web Docs, the then function (always) returns a new promise. So it seems to me it's not necessary to promisify func2 and func3 because they would have already been 'promisified' by the then function of the func1p. In other words, option 1 should be enough.

我已经对这两个选项进行了测试,并且似乎都可以工作,并且给了我相同的结果.但是,我担心的是两者之间在性能,开销等方面是否存在任何差异,如果存在差异,哪个更好.

I've tested with both options and both seemed to work and gave the same result to me. My concern, however, is if there's any difference in performance, overhead etc. between the two and if so, which one is better.

我的问题:

  • 始终使所有功能都合理化是否是一个好习惯,因此我应该改用选项2,或者反之亦然?
  • 如果首选选项1,那么从头开始创建func2和func3是否仍然适用?

这是我的代码(我使用Express JS和request-promise)

Here are my code (I used Express JS and request-promise)

当我问这个问题时,我以为我的函数是异步的,这个问题是关于我应该如何使用它们.我没想到它会变成关于我的函数是否真正异步的讨论.恕我直言,它们可能存在也可能不存在,但是总有可能它们下次将是异步的,当我不确定时,我宁愿假定它们是安全的.为了清楚起见,我编辑了代码以指示 func1 func2 func3 在这种情况下确实是异步的.

When I asked this question I assumed my functions are asynchronous and the question is about what I should do with them. I didn't expect it to turn into a discussion about whether my functions are actual asynchronous or not. Imho they may or may not be but there is always the possibility that they will be asynchronous the next time and when I'm not sure, I'd rather assume that they are to be safe. So just to be clear, I edited my code to indicate that func1, func2, func3 are indeed asynchronous in this context.

 function func1 (filePath1) {
    fs.readFile(filePath1, (err, data1) => {
        if (err) throw err;
        console.log(data1);
    });
 }

 function func2 (filePath2) {
    fs.readFile(filePath2, (err, data2) => {
        if (err) throw err;
        console.log(data2);
    });
 }     

 function func3 (filePath3) {
    fs.readFile(filePath3, (err, data3) => {
        if (err) throw err;
        console.log(data3);
    });
 }

推荐答案

这个问题变得有点广泛,因为您仍在学习很多此类知识.:-)以下是我认为我现在可以合理回答的三个部分:

The question has become a bit broad because you're still learning a lot of this stuff. :-) Here are the three parts I see that I think I can now reasonably answer:

  1. 我何时应该使用 Promise.promisify ,而不是仅使用 then ?他们彼此之间有什么不同之处?

  1. When should I use Promise.promisify vs. just using then? What do they do differently from one another?

我可以与 then then一起使用同步功能吗?

Can I use synchronous functions with then?

我应该如何编写异步函数,以便可以在promise中使用它们?

How should I write asynchronous functions so that I can use them with promises?

1.我何时应该使用 Promise.promisify ,而不是仅使用 then ?他们彼此之间有什么不同之处?

Promise.promisify Bluebird ,并且不是标准JavaScript Promise对象的一部分.它的工作是围绕提供诺言的标准Node-callback-style函数*创建包装函数.它接受一个函数并返回包裹在其周围的新函数.

1. When should I use Promise.promisify vs. just using then? What do they do differently from one another?

Promise.promisify is a function provided by Bluebird and is not part of the standard JavaScript Promise object. Its job is to create a wrapper function around a standard Node-callback-style function* that provides a promise instead. It accepts a function and returns a new function wrapped around it.

then 是Promise的标准功能,可以将回调回调到Promise的解决方案(以及可选的处理程序中,以拒绝其).它接受一个函数并返回一个新的promise,该promise将根据您提供的功能做什么来解决或拒绝.

then is a standard feature of promises that hooks up a callback to the promise's resolution (and optionally a handler to its rejection). It accepts a function and returns a new promise that will resolve or reject depending on what the function you give it does.

它们完全无关,除了都涉及承诺.他们做的事情完全不同.使用 Promise.promisify 的唯一原因是您是否必须处理传统的Node样式回调函数(像大多数Node API中的那些一样,因为它早于Promise)并且想要使用Promise跟他们.相反,您每次使用诺言时都先使用 then .

They're completely unrelated, other than both involving promises. They do completely different things. The only reason for using Promise.promisify is if you have to deal with legacy Node-style-callback functions (like those in the majority of the Node API, since it predates promises) and want to use promises with them. In contrast, you use then any time you use promises.

是的.没有特定的原因,但是可以.传递给您 then 的函数将以promise的解析度值(如果您将回调作为第二个参数传递,则返回其拒绝值)作为其唯一参数.如果您的 then 回调函数返回了一个Promise,则 then 会根据函数返回的Promise做出创建解析或拒绝的Promise.如果 then 回调返回非承诺值,则使用该值解析 then 创建的承诺.

Yes. There's no particular reason to, but you can. The function you pass then gets called with the resolution value of the promise (or its rejection value if you pass the callback as the second argument) as its only argument. If your then callback returns a promise, then makes the promise it creates resolve or reject based on the promise the function returns; if the then callback returns a non-promise value, the promise then creates is resolved with that value.

让您的函数返回承诺.

例如,查看您的 func1 ,它不会返回诺言,并且实际上不能正常工作:

Looking at your func1, for instance, it doesn't return a promise and in fact it doesn't work properly:

// Your `func1` from the question
function func1 (filePath1) {
    fs.readFile(filePath1, (err, data1) => {
        if (err) throw err;
        console.log(data1);
    });
}

无法正常工作的原因是它从 readFile 回调中抛出.但是,没有任何有用的方法来处理该回调中的抛出.

The reason it doesn't work properly is that it throws from the readFile callback. But throws in that callback are not handled by anything usefully.

要编写要与Promise一起使用的函数,您需要让它返回Promise.您可以这样编写:

To write that function to be used with promises, you'd have it return a promise. You can do that by writing it like this:

// `func1` updated to use promises, and also to accept options
function func1(filePath1, options) {
    return new Promise((resolve, reject) => {
        fs.readFile(filePath1, options, (err, data1) => {
            if (err) {
                reject(err);
            } else {
                resolve(data1);
            }
        });
    });
}

...或者,如果您使用的是Bluebird,则只需使用 Promise.promisify ,因为您执行的所有功能都是调用 readFile :

...or, if you're using Bluebird, by simply using Promise.promisify, since all your function does is call readFile:

const func1 = Promise.promisify(fs.readFile);

如果您不使用Bluebird,或者想一次性分发整个API(例如整个 fs ),则可以查看

If you're not using Bluebird, or if you want to promisify entire APIs (like the whole of fs) in one go, you might look at the promisify package instead.

*标准的节点回调样式功能"就是

* A standard "Node-callback-style function" is one that

  1. 接受参数,列表中的最后一个是回调函数
  2. 异步执行其工作,然后
  3. 使用错误或 null 的初始参数调用回调,然后调用异步调用的结果(如果是 null ).
  1. Accepts arguments where the last in the list is a callback function
  2. oes its work asynchronously, then
  3. Calls the callback with an initial argument which is either an error or null, followed (if it's null) by the result of the asynchronous call.

让我们看一个示例: fs.readFile :它接受要读取的文件的路径,一个可选的 options 对象,并作为最后一个参数使用结果调用回调.当它调用回调时,如果有错误,它将把该错误作为第一个参数传递而根本没有第二个参数传递.如果没有错误,它将使用两个参数调用回调: null 和文件数据.

Let's look at an example: fs.readFile: It accepts the path of the file to read, an optional options object, and as the last argument a callback to call with the results. When it calls the callback, if there was an error, it passes that error as the first argument and no second argument at all. If there wasn't an error, it calls the callback with two arguments: null, and the file data.

所以这里有一个模式:

  • API函数的最后一个参数是回调
  • 回调的第一个参数是错误或 null

Promise.promisify 将启用了promise的包装器封装在以这种方式工作的任何功能上.

Promise.promisify puts a promise-enabled wrapper around any function that works in that way.

所以:您什么时候应该使用它?任何时候您想将Promise与Node-callback-style函数一起使用.

So: When should you use it? Any time you want to use promises with a Node-callback-style function.

这篇关于承诺链-所有功能都应承诺的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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