Подтвердить что ты не робот

Почему конструктору Promise требуется функция, которая вызывает "разрешение" по завершении, но "then" - нет - вместо этого возвращается значение?

Как я окунулся в изучение Promise s, мое понимание остановилось на следующем вопросе, который я не нахожу обсуждаемым (все, что я нахожу, - это конкретные обсуждения конструктора Promise, а Promise 'then ', но не обсуждение, которое сравнивает их шаблоны проектирования).


1. Конструктор Promise

Из документации MDN, , мы используем конструктор Promise (добавлен мой комментарий):

new Promise(function(resolve, reject) { ... }); // <-- Call this Stage 1

Объект функции с двумя аргументами resolve и reject. Первый аргумент исполняет обещание, второй аргумент отвергает его. Мы можем вызовите эти функции после завершения нашей работы.


2. Функция then

Переходя к функции then, которую можно вызвать в объекте Promise (который возвращает новый объект Promise), мы следующая сигнатура функции, описанная в документации (с добавленными мной комментариями):

p.then(onFulfilled, onRejected);

Chaining

Поскольку метод then возвращает Promise, вы можете легко вызовы.

var p2 = new Promise(function(resolve, reject) {
  resolve(1); // <-- Stage 1 again
});

p2.then(function(value) {
  console.log(value); // 1
  return value + 1; // <-- Call this Stage 2
}).then(function(value) {
  console.log(value); // 2
});

Мой вопрос

Из приведенного выше фрагмента кода мне кажется, что значение передано функции resolve в 1-й стадии (во втором входе resolve - ниже (2), выше ) передается на следующий этап (первая функция then, следующая в том же фрагменте кода). На этапе 1 нет возвращаемого значения. Однако это возвращаемое значение на этапе 2, которое после этого переходит на следующий этап (вторая функция then).

Это отсутствие соответствия между шаблоном проектирования для создания Promise и использование функции then по существующему обещанию (которое также возвращает Promise), просто исторический случай (один требует вызова обратного вызова, но ничего не возвращает, а другой возвращает значение, но не вызывает обратный вызов)?

Или мне не хватает основной причины, почему конструктор Promise использует другой шаблон проектирования, чем функция then?

4b9b3361

Ответ 1

Ответ Берги превосходный, и был очень полезен для меня. Этот ответ дополняет его. Чтобы визуализировать связь между конструктором Promise() и then(), я создал эту диаграмму. Надеюсь, это поможет кому-то... может быть, даже мне, через несколько месяцев.

Основная идея здесь заключается в том, что функция "исполнителя", переданная конструктору Promise(), устанавливает задачи в движении, которые будут устанавливать состояние обещания; тогда как обработчики, которые вы передадите на then(), будут реагировать на состояние обещания.

Диаграмма: Promise() executor vs. then() method (Примеры кода, адаптированные из классический учебник Jake Archibald.)

Это очень упрощенное представление о том, как все работает, оставляя много важных деталей. Но я думаю, что если вы сможете сохранить хороший обзор намеченной цели, это поможет избежать путаницы, когда вы попадете в детали.

Несколько выбранных деталей

Исполнитель немедленно вызывается

Одна важная деталь заключается в том, что функция-исполнитель, переданная конструктору Promise(), называется немедленно (до того, как конструктор вернет обещание); тогда как функции обработчика, переданные методу then(), не будут вызываться до позже (если вообще).

Берги упомянул об этом, но я хотел повторить его, не используя термины а/синхронно, что можно смутить, если вы не читаете внимательно: различие между функцией, вызывающей нечто асинхронно или вызываемой асинхронно, легко замаскировать в общении.

resolve() не onFulfill()

Еще одна деталь, которую я хотел бы подчеркнуть, потому что это немного смутило меня в том, что обратные вызовы resolve() и reject(), переданные функции-исполнителю конструктора Promise() , не обратные вызовы позже передаются методу then(). Это кажется очевидным в ретроспективе, но явная связь заставила меня крутиться в кругах слишком долго. Существует определенно соединение, но оно свободно, динамично.

Вместо этого обратные вызовы resolve() и reject() представляют собой функции , предоставляемые системой, и передаются функции-исполнителю конструктором Promise при создании обещания. Когда вызывается функция resolve(), выполняется системный код, который потенциально изменяет состояние обещания и в конечном итоге приводит к обратному вызову onFulfilled(), который вызывается асинхронно. Не думайте призывать resolve() как плотную оболочку для вызова onFulfill()!

Ответ 2

Нет никакого соответствия между конструктором Promise и then, потому что это две независимые вещи, предназначенные для разных целей.

Конструктор Promise используется только для promisifying 1 асинхронных функций. Действительно, как вы говорите, он построен на вызове resolve/reject обратных вызовов для асинхронной отправки значений, и в этом случае нет возвращаемых значений.

То, что сам конструктор Promise принимает этот "обратный" обратный вызов (которому он синхронно проходит resolve и reject), на самом деле является улучшением старшего отложенного шаблона и не имеет никакого предполагаемого сходства для обратных вызовов then.

var p = new Promise(function(res, rej) {    |    var def = Promise.Deferred();
    setTimeout(res, 100);                   |    setTimeout(def.resolve, 100);
});                                         |    var p = def.promise;

Обратные вызовы then в контрасте - это классические асинхронные обратные вызовы с дополнительной функцией, из которых вы можете return от них. Для получения значений они асинхронно вызываются.

p.then(function(val) { … });

Подводя итог различиям:

  • Promise является конструктором, а then является методом
  • Promise принимает один обратный вызов, а then занимает до двух
  • Promise синхронно вызывает обратный вызов, а then асинхронно вызывает свои обратные вызовы
  • Promise всегда вызывает обратный вызов,
    then может не вызывать свои обратные вызовы (если обещание не выполнено/отклонено)
  • Promise передает возможности для разрешения/отклонения обещания обратного вызова,
    then передает значение результата/отклонения результата обещания, которое оно вызывало на
  • Promise вызывает обратный вызов с целью выполнения побочных эффектов (вызов reject/resolve),
    then вызывает свои обратные вызовы для их значений результата (для цепочки)

Да, оба возвращают promises, хотя они разделяют эту черту со многими другими функциями (Promise.resolve, Promise.reject, fetch,...). Фактически все они основаны на тех же принципах построения обещаний и разрешения/отклонения, которые также предоставляет конструктор Promise, хотя это и не их основная цель. then в основном предлагает возможность прикреплять обратные вызовы onFulfilled/onRejected к существующему обещанию, которое довольно диаметрально для конструктора Promise.

То, что оба используют обратные вызовы, просто совпадение - не историческая случайность, а скорее коадаптация языковой функции.

1: В идеале вам никогда не понадобится это, потому что все асинхронные API-интерфейсы возвращаются promises

Ответ 3

Весь смысл функции-исполнителя-конструктора обещаний заключается в распространении функций разрешения и отклонения на использование кода без обещаний, его обертывании и преобразовании для использования обещания. Если вы хотите ограничить это только синхронными функциями, то да, вместо этого можно было бы использовать возвращаемое значение из функции, но это было бы глупо, поскольку полезная часть - распространять распознаватель и отклонять функции на код, который на самом деле выполняется позже (путь после возврата), например для обратных вызовов, переданных в некоторый асинхронный API.

Ответ 4

Вдохновленный предыдущими ответами (я рассмотрю ту часть, которая меня больше всего сбила с толку):

Аргументы resolve и reject в конструкторе Promise не являются функциями, которые вы определяете. Подумайте о них как о крючках, которые вы можете внедрить в свой код операции async (обычно вы resolve с ответом на успех и reject с причиной сбоя), так что javascript имеет возможность в конечном итоге маркировать обещание как выполненное или отклоненное в зависимости от результата вашего асинхронная работа; как только это произойдет, соответствующая функция, которую вы определили then(fun1, fun2), запускается, чтобы потреблять обещание (либо fun1(success_response) либо fun2(failure_reason), в зависимости от того, выполнено ли обещание/отклонено). Поскольку fun1 и fun2 - это простые старые javascript-функции (они просто принимают будущие результаты вашей операции async как аргументы), они return значения (которые могут быть undefined если вы явно не возвращаете).

Также см. Замечательные статьи Mozilla:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise