Promise.resolve与new Promise(resolve)的区别

133

我正在使用bluebird,我看到有两种方式将同步函数解析为Promise,但我不理解两种方式之间的区别。它们的堆栈跟踪似乎有点不同,所以它们不仅仅是一个别名,对吗?

那么哪种方式更好呢?

方式A

function someFunction(someObject) {
  return new Promise(function(resolve) {
    someObject.resolved = true;
    resolve(someObject);
  });
}

方式B

function someFunction(someObject) {
  someObject.resolved = true;
  return Promise.resolve(someObject);
}

7
Promise.resolve 只是语法糖。 - Qantas 94 Heavy
2
简短回答 - 使用上没有区别。只是语法糖。 - Alex
3
"糖"是什么? - doubleOrt
12
“Syntactic sugar”是一种旨在使表达更易读或更流畅的语法。详见:维基百科 - Wyck
2个回答

109

与评论中两个答案相反-是有区别的。

然而,

Promise.resolve(x);

基本上与

new Promise(function(r){ r(x); });

有一个微妙之处。

返回Promise的函数通常应该保证它们不会同步抛出异常,因为它们可能异步地抛出异常。为了防止意外结果和竞态条件 - 抛出通常被转换为返回的拒绝(rejections)。

考虑到这一点 - 当规范被创建时,Promise构造函数是throw safe(即安全地抛出)。

如果someObjectundefined怎么办?

  • 方式A返回一个被拒绝的promise。
  • 方式B同步抛出。

Bluebird看到了这个问题,Petka添加了Promise.method来解决这个问题,所以你可以继续使用返回值。因此,在Bluebird中编写此代码的正确且最简单的方法实际上既不是A也不是B - 它是:

var someFunction = Promise.method(function someFunction(someObject){
    someObject.resolved = true;
    return someObject;
});

Promise.method将为您转换抛出异常的情况并将返回值转换为解决操作。这是最安全的处理方式,它通过返回值同化了可then的对象,因此即使someObject本身是一个promise,也能正常工作。

通常,Promise.resolve用于将对象和外部promise(thenable)转换为promise。这是它的使用案例。


返回 Promise 的函数通常应该保证它们不会同步抛出异常,因为它们可能会异步抛出异常。为什么函数应该是同步或异步的,而不能同时具备两者?您能否详细说明一下原因?目前我很喜欢使用 Promise.resolve(),您是否认为使用 Promise.resolve() 是一种反模式? - Ashley Coolman
2
@AshleyCoolman 请查看http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony - 一个有时表现为异步的方法应该始终如一地这样做以保持一致性。 - Benjamin Gruenbaum
Promise.resolve() 是否像使用 new 一样创建一个新的 Promise 实例?如果不是,那么 return Promise.resolve(yourCode) 更快且可以避免同步抛出异常。 - Steven Vachon
1
我感觉很糟糕,我使用“Promise.resolve().then(function(){ /可能会抛出错误的情况/}).then...”来确保错误变成了一个被拒绝的 promise… 我会更深入地研究“Promise.method”。 - Polopollo
1
@Polopollo 或者 Promise.coroutine,后者更加实用。 - Benjamin Gruenbaum

36

以上答案或评论中未提到的另一个区别是:

如果 someObject 是一个 Promisenew Promise(resolve) 将会额外花费两个 tick。


const p = new Promise(resovle => setTimeout(resovle));

new Promise(resolve => resolve(p)).then(() => {
  console.log("tick 3");
});

p.then(() => {
  console.log("tick 1");
}).then(() => {
  console.log("tick 2");
});

const p = new Promise(resolve => setTimeout(resolve));

Promise.resolve(p).then(() => {
  console.log("tick 3");
});

p.then(() => {
  console.log("tick 1");
}).then(() => {
  console.log("tick 2");
});

第二个代码片段将首先打印出“tick 3”。为什么?
  • If the value is a promise, Promise.resolve(value) would return value exactly. Promise.resolve(value) === value would be true. see MDN

  • But new Promise(resolve => resolve(value)) would return a new promise which has locked in to follow the value promise. It needs an extra one tick to make the 'locking-in'.

      // something like:
      addToMicroTaskQueue(() => {
        p.then(() => {
          /* resolve newly promise */
        })
          // all subsequent .then on newly promise go on from here
          .then(() => {
            console.log("tick 3");
          });
      });
    

    The tick 1 .then call would run first.



网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接