为什么当键名称为“ then”的对象存在时,承诺仍未完成

时间:2019-04-19 23:25:57

标签: javascript promise

在以下情况下,JavaScript工作异常。

我看到了这个答案,并得到了有关Javascript怪异行为的问题:https://stackoverflow.com/a/50173415/1614973

我发现,如果将他的代码中的then更改为任何其他键名,我们将得到完全不同的结果。 CodePen演示:hischanged

我尝试了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”的Object。
  3. then的值必须是一个函数。

我想知道为什么会这样。

2 个答案:

答案 0 :(得分:1)

它永远无法解决的原因是,您最后的“ then”永远不会解决:

.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

答案 1 :(得分:1)

我们都很熟悉:在.then(callback)之一中,如果回调函数返回另一个承诺,例如lastPromise,则整个承诺链(到那时为止)将有效地“成为” { {1}}。

在内部,promise链根本不会检查lastPromise事物是否是真正的Promise。它仅检查其是否实现了 thenable接口(具有lastPromise方法)。如果是,则进一步假设该方法也符合spec

  

承诺必须提供then方法来访问其当前或最终值或原因。

     

promise的then方法接受两个参数:

     

.then()

现在,您从回调函数中返回一个具有promise.then(onFulfilled, onRejected)方法的对象,这使该对象成为可能的。因此,promise链会将这个对象视为同志,认为它是一个“承诺”,将其称为.then(实际上是.then(onFulfilled, onRejected)对)。

现在,一个善良的牧师知道与(resolve, reject)相关的事情。不幸的是,他们信任错误的人。您的实现如下:

(onFulfilled, onRejected)

您从未真正调用then = (onFulfilled) => 0 来从挂起状态解决,所以既然整个链现在都“成为” onFulfilled(someValue),但是您的假lastPromise无法解决/拒绝,整个链只是停留在待命状态。

那是一个盲目地信任任何可以成为诺言的悲惨故事。