【问题标题】:Bluebird.JS Promise: new Promise(function (resolve, reject){}) vs Promise.try(function(){})Bluebird.JS Promise: new Promise(function (resolve, reject){}) vs Promise.try(function(){})
【发布时间】:2015-11-15 20:52:43
【问题描述】:

什么时候应该使用哪个?以下是一样的吗?

新的 Promise() 示例:

function multiRejectExample(){ 
  return new Promise(function (resolve, reject){
    if(statement){
      console.log('statement 1');
      reject(throw new Error('error'));
    }
    if(statement){
     console.log('statement 2');
     reject(throw new Error('error')); 
   }
  });
}

Promise.try() 示例:

function tryExample(){
  return Promise.try(function(){
    if(statement){
      console.log('statement 1');
      throw new Error('error');
    }
    if(statement){
     console.log('statement 2');
     throw new Error('error'); 
   }
  });
}

【问题讨论】:

  • 松散相关:Promise.reject vs throw error。你不应该使用new Promise 构造函数,除非你实际上是在做一些异步的事情。这里的正确方法是return Promise.reject(…)(或使用Promise.try/Promise.method)。

标签: javascript promise bluebird


【解决方案1】:

在这种情况下,您可以主要使用其中任何一种(只有一个行为差异)。第一个是标准的 Promise 功能,可以与任何 Promise 库一起使用。

Promise.try() 是 Bluebird 库专门实现的功能,不属于我所知道的任何标准流程的一部分。

使用Promise.try() 的原因是如果您有一个返回承诺的函数,但生成该承诺的代码也可能导致同步异常。由于该异常不在任何承诺处理程序中,因此您将混合使用错误处理。一些代码执行路径可能会导致返回一个将解析或拒绝的承诺,而其他代码执行路径可能会引发异常。为了安全地编写代码,你必须同时响应 promise 并在代码周围放置一个 try/catch 块,这会变得笨拙。

Promise.try() 只是一种自动捕获任何异常并将其转换为拒绝的方法(类似于.then() 处理程序中发生的情况)。

在您的两种情况下,Promise.try() 不会以这种方式使您受益,因为new Promise() 回调已经捕获异常并将它们转换为拒绝,因此那里已经为您完成了功能。你可以在这里看到演示:http://jsfiddle.net/jfriend00/wLov9844/

Bluebird 文档提供了这个例子,更清楚地显示了好处:

function getUserById(id) {
    return Promise.try(function() {
        if (typeof id !== "number") {
            // Courtesy of Promise.try() this exception will be turned 
            // into a returned promise that is rejected with the 
            // exception as the reason
            throw new Error("id must be a number");
        }
        return db.getUserById(id);
    });
}

getUserById().then(successFn, errFn);

这里使用Promise.try() 确保getUserById() 将始终返回一个promise,即使该方法内部的代码同步抛出异常。这简化了getUserById() 的使用,因为您始终可以只响应承诺,而不必围绕它使用您自己的异常处理程序。

没有Promise.try(),您可以像这样自己编写相同的代码(以捕获函数内所有可能的同步异常):

function getUserById(id) {
    try {
        if (typeof id !== "number") {
            throw new Error("id must be a number");
        }
        return db.getUserById(id);
    } catch(e) {
        return Promise.reject(e);
    }
}

getUserById().then(successFn, errFn);

或者,你可以这样编码:

function getUserById(id) {
    if (typeof id !== "number") {
        throw new Error("id must be a number");
    }
    return db.getUserById(id);
}

try {
    getUserById().then(successFn, errFn);
} catch(e) {
    errFn(e);
}

大概,您可以看到Promise.try() 在某些情况下如何简化事情。


仅供参考,在您的第一个示例中,您使用的语法无效。你可以这样做:

reject(throw new Error('error')); 

我假设你的意思是这样的:

reject(new Error('error')); 

虽然我认为这不是您真正要问的问题,但如果您自己不返回承诺,Promise.try() 也会自动返回已解决的承诺。由于通过您的第一个示例的一条路径没有解决或拒绝,这将导致您的两个示例有所不同。

【讨论】:

    【解决方案2】:

    它们不一样。

    考虑两个陈述都是错误的情况。在这种情况下,multiRejectExample() 永远不会拒绝解决返回的承诺,而tryExample() 将“失败”并自动解决承诺(值为undefined,因为您不返回任何东西)。

    演示:

    var Promise = require('bluebird');
    
    function test1() {
      return Promise.try(function() { });
    }
    
    function test2() {
      return new Promise(function(resolve, reject) { });
    }
    
    test1().then(function() { console.log('resolved #1'); });
    test2().then(function() { console.log('resolved #2'); });
    

    这将记录resolved #1,但不会记录resolved #2,因为承诺从未真正解决(也不会被拒绝)。

    【讨论】:

      【解决方案3】:

      以下是一样的吗?

      没有。正如@robertklep 已经提到的,当statement 为假时,它们确实有不同的结果。 Promise.try 捕获异常,否则使用函数的返回值进行解析,而 Promise 构造函数只是创建一个新的 Promise,并不关心它何时不是 resolve()d。

      我应该什么时候使用哪个?

      您应该使用Promise 构造函数,并且真的只有当,您是promisifying an asynchronous callback API。其他一切,尤其是when involving other promises,基本上都是反模式。
      所以不要使用它,就像你在你的问题中所说的那样。

      你通常也不会throw。您正在编写一个返回 Promise 的函数(因为它是异步的),并且它应该始终返回一个 Promise。如果您想返回一个因错误而被拒绝的承诺,您可以使用Promise.reject 显式创建一个。因此,正确的方法是

      function multiRejectExample(){ 
          if (statement){
              console.log('statement 1');
              return Promise.reject(new Error('error'));
          }
          if (statement){
              console.log('statement 2');
              return Promise.reject(new Error('error')); 
          }
          return Promise.resolve();
      }
      

      当然,这个特定的示例没有多大意义,因为您的案例都不是异步的,而且根本没有理由使用 Promise。只需使用引发异常的同步函数即可。通常,您最终会得到一些 return …,这实际上是一个异步承诺,而不是由 undefined 实现的承诺。

      现在,如果你有这样的功能,并且厌倦了重复写return Promise.reject,你可以使用Bluebird 特有的Promise.tryPromise.method 方法作为语法糖。 p>

      【讨论】:

        猜你喜欢
        • 2019-04-07
        • 1970-01-01
        • 2019-01-20
        • 2019-09-15
        • 2018-10-10
        • 1970-01-01
        • 2019-08-31
        • 1970-01-01
        • 2018-01-16
        相关资源
        最近更新 更多