Bluebird.JS Promise:new Promise(function (resolve, reject){}) vs Promise.try(function(){})

Bluebird.JS Promise: new Promise(function (resolve, reject){}) vs Promise.try(function(){})

我应该什么时候使用哪个?以下是否相同?

新的 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 功能,可以与任何 promise 库一起使用。

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

使用 Promise.try() 的原因是如果您有一个 return 承诺的函数,但生成该承诺的代码也可能导致同步异常。由于该异常不在任何 promise 处理程序中,因此您将混合使用错误处理。某些代码执行路径可能会导致 returned 承诺将解析或拒绝,而其他代码执行路径可能会引发异常。为了安全地编写代码,您必须响应承诺并在代码周围放置一个 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() 始终是 return 承诺,即使该方法中的代码同步抛出异常也是如此。这简化了 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')); 

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

它们不一样。

考虑两种说法都不正确的情况。在这种情况下,multiRejectExample() 永远不会拒绝 解决 returned 承诺,而 tryExample() 会 "fall through" 并自动解决承诺(值为 undefined 因为你没有 return 任何东西)。

演示:

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 因为承诺从未真正解决(也没有被拒绝)。

Are the following the same?

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

When should I use which?

你应该使用 Promise 构造函数当且仅当,并且 真的只有当 ,你是 promisifying an asynchronous callback API. Everything else, especially when involving other promises,基本上是一个反模式。
所以不要像你在问题中那样使用它

你通常也不会 throw。您正在编写一个 return 承诺的函数(因为它是异步的),并且它应该始终 return 承诺。如果你想 return 一个因错误而被拒绝的承诺,你可以使用 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();
}

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

实现的承诺

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