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

У меня есть следующее:

new Promise(resolve => setTimeout(resolve, 2000))
    .then(() => console.log("after 2 seconds"));

new Promise(resolve => setTimeout(resolve, 3000))
    .then(console.log("before 3 seconds (instantly)"));

который производит следующий вывод:

> node index.js
before 3 seconds (instantly)
after 2 seconds

Promise.then () ожидает onFulfilled функция, но я прошел в console.log("before 2 seconds (instantly)"), который не является функцией. Вопрос из двух частей:

  • Почему console.log("before 2 seconds (instantly)") казнить сразу (или вообще)?
  • Почему второе обещание не вызвало исключение, когда я не передал функцию?

3 ответа

Код

console.log("before 3 seconds (instantly)")

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

.then(console.log("before 3 seconds (instantly)"))

результаты в console.log() сначала вызывается функция, затем возвращаемое значение передается .then(), Вот почему вы видите сообщение в консоли сразу.

Переходя undefined в .then() разрешено, и так как это то, что console.log() возвращается, ошибки не возникает.

Если ты хочешь это console.log() чтобы произойти, когда обещание выполнено, вы бы обернули его в функцию:

.then(function() { console.log("after 3 seconds"); })

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

Да. Все не функциональные аргументы должны игнорироваться. Увидеть ниже.

Почему console.log("до 2 секунд (мгновенно)") исполняется сразу (или вообще)?

Потому что в JS аргументы к вызовам функций оцениваются мгновенно (аппликативный порядок).

Почему второе обещание не вызвало исключение, когда я не передал функцию?

Так как console.log возвращается undefined а также .then() без аргументов допустимо (потому что оба обработчика являются необязательными). В вашем примере console.log() возвращает неопределенное значение, так что это похоже на вызов .then() без аргументов.

Но даже если он вызывается с некоторыми аргументами, которые не являются функциями, они все равно будут игнорироваться. Например, даже в этом примере "ОК" все равно дойдет до console.log в конце, что может быть удивительно:

Promise.resolve('ok')
    .then()
    .then(false)
    .then(null)
    .then(1)
    .then('x')
    .then([1, 2, 3])
    .then({a: 1, b: 2})
    .then(console.log);

См. Спецификацию Promises/A+, раздел 2.2.1, в которой описаны аргументы .then() метод:

2.2.1. OnFulfilled и onRejected являются необязательными аргументами:

  • Если onFulfilled не является функцией, ее следует игнорировать.
  • Если onRejected не является функцией, ее следует игнорировать.

Почему console.log("before 2 seconds (instantly)") казнить сразу (или вообще)?

Параметры функции оцениваются до ее вызова. Когда вы делаете alert(1+2) вы ожидаете 1+2 оценивать в первую очередь, и когда вы делаете alert(console.log("...")) вы также должны ожидать console.log("...") быть оцененным первым. Там нет ничего особенного then; это просто обычная функция, и ее аргументы обрабатываются так же, как аргументы любой другой функции.

Почему второе обещание не вызвало исключение, когда я не передал функцию?

Так как console.log возвращается undefined и спецификация языка ( ECMAScript 2015) говорит, что должно произойти, когда вы звоните then(undefined) и это не исключение. Давайте посмотрим, что он говорит:

25.4.5.3.1 PerformPromiseThen (обещание, onFulfilled, onRejected, resultCapability)

Абстрактная операция PerformPromiseThen выполняет операцию then для обещания, используя onFulfilled и onRejected в качестве действий по расчету. Результатом является обещание resultCapability.

  1. Утверждаю: IsPromise(обещание) верно.
  2. Утверждение: resultCapability является записью PromiseCapability.
  3. Если IsCallable (onFulfilled) имеет значение false, то
    1. Пусть на выполненном будет "Identity",
  4. Если IsCallable (onRejected) имеет значение false, то
    1. Пусть onRejected будет "Thrower",
  5. Пусть executeReaction будет PromiseReaction {[[Capabilities]]: resultCapability, [[Handler]]: onFulfilled }.
  6. ...

Существенные моменты здесь (3) и (5). В (3), так как onFulfilled является undefined, IsCallable (onFulfilled) является ложным, и поэтому onFulfilled установлено в "Identity", Затем в (5) создается PromiseReaction с [[Handler]] onFulfulled, который, как мы знаем, "Identity",

Вот что говорится в разделе " Записи PromiseReaction Records". "Identity":

Если [[Handler]] "Identity" это эквивалентно функции, которая просто возвращает свой первый аргумент.

Так что у вас есть это. призвание then(undefined) в основном то же самое, что звонить then(a => a) Вот почему вы не получите ошибку.

Другие вопросы по тегам