承诺链接 - 如果所有功能都需要承诺

时间:2017-09-10 09:09:22

标签: javascript node.js asynchronous promise

假设我有三个异步函数链接在一起,func1 - > func2 - > func3,似乎有两种方法可以做到。

选项1:宣传第一个函数func1p = Promise.promisify(func1),将其他两个函数单独保留,然后创建一个这样的链:

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

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

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

根据MDN Web Docsthen函数(总是)返回一个新的承诺。所以在我看来,没有必要宣传func2和func3,因为它们已经被宣传了#39;通过func1p的then函数。换句话说,选项1就足够了。

我已经测试了两种选项,两者似乎都有效,并给了我相同的结果。然而,我担心的是两者之间的性能,开销等是否存在差异,如果是,那么哪一个更好。

我的问题:

  • 总是宣传所有功能是一个好习惯,所以我应该使用选项2,或者反过来呢?
  • 如果首选选项1,如果要从头开始创建func2和func3,它仍然是真的吗?

编辑: 这是我的代码(我使用Express JS和请求承诺)

EDIT2: 当我问这个问题时,我认为我的功能是异步的,问题是我应该怎么做。我没想到它会变成关于我的函数是否是实际异步的讨论。 Imho他们可能会或可能不会,但是下次他们总是有可能异步,当我不确定时,我宁愿假设他们是安全的。所以,为了清楚起见,我编辑了我的代码,以表明func1func2func3在此上下文中确实是异步的。

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

1 个答案:

答案 0 :(得分:2)

这个问题变得有点宽泛,因为你还在学习很多东西。 :-)以下是我看到的三个部分,我认为我现在可以合理地回答:

  1. 我应该何时使用Promise.promisify而不是仅使用then?他们有什么不同的做法?

  2. 我可以使用then的同步功能吗?

  3. 我应该如何编写异步函数以便将它们与promises一起使用?

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

    Promise.promisify是由Bluebird提供的函数,不是标准JavaScript Promise对象的一部分。它的工作是创建一个围绕标准Node-callback风格函数*的包装函数,它提供了一个承诺。它接受一个函数并返回一个包裹它的新函数。

    then是promises的标准功能,它将回调挂钩到promise的解析(以及可选的拒绝处理程序)。它接受一个函数并返回一个新的promise,它将解析或拒绝,具体取决于你给它的功能。

    除了涉及承诺之外,它们完全不相关。他们完全不同的事情。使用Promise.promisify的唯一原因是,如果你必须处理传统的Node-style-callback函数(比如大多数Node API中的函数,因为它早于promises)并且想要使用promises。相反,只要您使用promises,就会使用then

    2。我可以使用then的同步函数吗?

    是。没有特别的原因,但你可以。您传递的函数then将使用promise的解析值(或者如果将回调作为第二个参数传递其拒绝值)作为其唯一参数进行调用。如果您的then回调返回一个承诺,then会根据函数返回的承诺使其创建的承诺解析或拒绝;如果then回调返回非承诺值,则使用该值解析承诺then

    3。我应该如何编写异步函数,以便可以将它们与promises一起使用?

    让你的函数返回一个承诺。

    例如,查看您的func1,它不会返回承诺,实际上它无法正常运行:

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

    它无法正常工作的原因是它会从readFile回调中抛出。但是回调中的抛出并没有被任何有用的处理。

    要编写要与promises一起使用的函数,你需要它返回一个promise。你可以这样写:

    // `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

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

    如果你没有使用Bluebird,或者想要一次性宣传整个API(例如整个fs),你可能会看一下promisify package

    *标准的“节点回调式功能”是

    1. 接受列表中最后一个是回调函数的参数
    2. 以异步方式工作,然后
    3. 使用初始参数调用回调,该参数可能是错误或null,后跟(如果它是null)异步调用的结果。
    4. 让我们看一个例子:fs.readFile:它接受要读取的文件的路径,一个可选的options对象,以及作为最后一个参数,用于调用结果的回调。当它调用回调时,如果有错误,它会将该错误作为第一个参数传递,而根本没有第二个参数。如果没有错误,它会使用两个参数调用回调:null和文件数据。

      那里有一种模式:

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

      Promise.promisify为任何以这种方式工作的函数提供了一个启用promise的包装器。

      所以:你什么时候应该使用它?任何时候你想使用带有Node-callback风格函数的promises。