Почему обещание находится в ожидании, когда есть объект с ключевым словом «тогда» - PullRequest
3 голосов
/ 20 апреля 2019

JavaScript работает странно в ситуации ниже.

Я увидел этот ответ и получил вопрос о странном поведении Javascript: https://stackoverflow.com/a/50173415/1614973

Я обнаружил, что если мы изменим then в его коде на любое другое имя ключа, мы получим совершенно другой результат. Демоверсия CodePen: его , изменено

Я пробовал Chrome и Firefox, и все они имеют эту проблему. Я исследую проблему там и нахожу некоторые основные правила этой «ошибки».

// This one will always pending
const pendingPromise = Promise.resolve(x=>x).then(r => ({ then: y => 0 }));
pendingPromise.then(r => console.log("promise resolved")); // "promise resolved" will never logged

// Thanks @Jaromanda X's correction. a simpler version is:
const pendingPromise1 = Promise.resolve().then(() => ({then: y => 0}))
pendingPromise1.then(r => console.log("promise1 resolved")); // "promise1 resolved" will never logged

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

  1. Исходный должен быть выполнен с помощью функции. (ненужное ограничение)
  2. В .then должен быть возвращен Объект с ключом с именем «then».
  3. Значение клавиши then должно быть функцией.

Я бы хотел получить какую-либо подсказку о том, почему это происходит.

Ответы [ 2 ]

1 голос
/ 20 апреля 2019

Мы все знакомы с этим: в одном из .then(callback), если обратный вызов возвращает другое обещание, скажем, lastPromise, вся цепочка обещаний (до этого момента) фактически «станет» lastPromise.

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

Обещание должно предоставить метод then для доступа к его текущему или возможному значению или причине.

Метод then обещания принимает два аргумента:

promise.then(onFulfilled, onRejected)

Теперь вы возвращаете объект из обратного вызова, который имеет метод .then, что делает его доступным для просмотра. Таким образом, цепочка обещаний будет относиться к этому объекту как к товарищу, который считает, что это «обещание», назовет его .then(onFulfilled, onRejected) (который фактически является парой (resolve, reject)).

Теперь хороший знающий знает, как поступить с (onFulfilled, onRejected). К сожалению, они доверяют не тому парню. Ваша реализация выглядит так:

then = (onFulfilled) => 0

На самом деле вы никогда не вызываете onFulfilled(someValue) для разрешения из состояния ожидания, поэтому, поскольку вся цепочка теперь «становится» lastPromise, но ваша фальшивая lastPromise не удается разрешить / отклонить, вся цепочка просто застряла в состоянии ожидания для хорошо.

Это печальная история о слепом доверии к любому обещанию.

1 голос
/ 20 апреля 2019

Причина, по которой оно никогда не разрешается, заключается в том, что ваше окончательное «тогда» никогда не вызывает разрешение:

.then(r=>({then: y => 0})) просто возвращает недопустимое значение 0.

y является разрешениемПерезвоните.Чтобы ваш код работал, измените y на resolve и затем вызовите его.Или просто позвоните y.Дело в том, что до тех пор, пока не будет принято решение, обещание остается в ожидании.

console.log("Starting Strange Promise")
const pendingPromise = Promise.resolve(x=>x).then(r=>(
  {then: y => "Strange Promise Done!"}
));
pendingPromise.then(console.log) // never happens

console.log("Starting Hacked Promise")
const hackedPromise = Promise.resolve(x=>x).then(r=>(
  {then: resolve => resolve("Hacked Promise Done!")}
));
hackedPromise.then(console.log)  // happens, like, speed of light quickly
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...