Promise.resolve против нового обещания (разрешение)

98

Я использую bluebird и вижу два способа преобразовать синхронные функции в Promise, но я не вижу различий между ними. Похоже, трассировка стека немного отличается, так что это не просто, не так ли alias?

Итак, какой способ предпочтительнее?

Путь А

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

Путь Б

function someFunction(someObject) {
  someObject.resolved = true;
  return Promise.resolve(someObject);
}
Пипо
источник
3
Promise.resolveэто просто сахар.
Qantas 94 Heavy
1
Короткий ответ - никакой разницы в использовании. Просто сахар.
Pinal
@Pinal Что такое "сахар"?
doubleOrt
6
@Телец. Синтаксический сахар - это синтаксис, разработанный для облегчения чтения и выражения. см .: википедия .
Wyck

Ответы:

85

Вопреки обоим ответам в комментариях - разница есть.

Пока

Promise.resolve(x);

в основном то же самое, что

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

есть тонкость.

Функции, возвращающие обещание, обычно должны иметь гарантию того, что они не должны вызывать синхронно, поскольку они могут вызывать асинхронно. Чтобы предотвратить неожиданные результаты и условия гонки - броски обычно конвертируются в возвращенные отклонения.

Имея это в виду - когда спецификация была создана, конструктор обещаний безопасен.

Что если someObjectесть undefined?

  • Способ А возвращает отклоненное обещание.
  • Путь Б бросает синхронно.

Bluebird увидел это, и Petka добавил, Promise.methodчтобы решить эту проблему, чтобы вы могли продолжать использовать возвращаемые значения. Так что правильный и самый простой способ написать это в Bluebird на самом деле ни то, ни другое - это:

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

Promise.method преобразует броски в отклоненные и возвращает в решенные за вас. Это наиболее безопасный способ сделать это, и он ассимилирует thenспособности через возвращаемые значения, поэтому он будет работать, даже если someObjectна самом деле это обещание.

Обычно Promise.resolveиспользуется для приведения объектов и внешних обещаний (thenables) к обещаниям. Это его вариант использования.

Бенджамин Грюнбаум
источник
«Функции, возвращающие обещание, обычно должны иметь гарантию, что они не должны вызывать синхронно, поскольку они могут вызывать асинхронно». Не могли бы вы подробнее объяснить, почему функции должны быть синхронными или асинхронными, но не одновременно? В настоящее время мне нравится Promise.resolve (). Не могли бы вы сказать, что использование Promise.resolve()- это анти-шаблон?
Эшли Кулман
2
@AshleyCoolman см. Blog.izs.me/post/59142742143/designing-apis-for-asynchrony - метод, который иногда ведет себя асинхронно, всегда должен делать это для согласованности.
Бенджамин Грюнбаум
Создает ли Promise.resolve()новый экземпляр Promiseтаким же образом, как и при использовании new? Если нет, return Promise.resolve(yourCode)будет быстрее и избежать синхронных бросков.
Стивен Вашон,
1
Мне плохо, я использую «Promise.resolve (). Then (function () {/ * case, который может вызвать ошибку * /}). Then ...», чтобы убедиться, что ошибка превратилась в отклоненное обещание ... Я подробнее рассмотрю "Promise.method"
Полополло
1
@Polopollo или Promise.coroutineчто еще полезнее.
Бенджамин Грюнбаум,
18

Есть еще одно различие, не упомянутое в приведенных выше ответах или комментариях:

Если someObjectесть Promise, new Promise(resolve)будут стоить два дополнительных тика.


Сравните два следующих фрагмента кода:

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(resovle => setTimeout(resovle));

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

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

Второй фрагмент сначала напечатает «галочку 3». Зачем?

  • Если значение является обещанием, Promise.resolve(value)вернет значение точно. Promise.resolve(value) === valueбыло бы правдой. см. MDN

  • Но new Promise(resolve => resolve(value))вернет новое обещание, которое будет следовать valueобещанию. Для «блокировки» требуется дополнительная галочка.

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

    tick 1 .thenВызов будет работать в первую очередь.


Ссылки:

Эдвард Чен
источник