ES6 Promises 奇怪地从自定义 js 对象中提取正确的值

ES6 Promises strangely extract correct value out of custom js objects

我写了一个完全独立于Promise API but achieves similar goals. It uses window.requestAnimationFrame and falls back to setTimeout and has nothing common with Promises. In fact you can run it on ie9 - 10 or a machine from 2009 etc. Here is the source code

的库

下面的代码怎么可能工作,第二个承诺在延迟 10 秒后将值 (v + 3) 正确地输入到第三个承诺中?因为 rafx.async... returns 自定义专有对象。

const x = Promise.resolve()
.then(() => console.log("2nd promise"))
.then(() => {
  //600 frames === 10 secs
  return rafx.async(6)
  .skipFrames(600)
  .then(v => v + 1)
  .then(v => v + 3);
});

console.log(x instanceof Promise);

x.then(v => console.log("3rd promise", v));
<script src="https://cdn.jsdelivr.net/npm/rafx"></script>

期望 x.then(v... 处的 v 等于从自定义 then.

返回的任何自定义对象

这是 rafx.async(6).skipFrames(600)...then(v => v + 3) returns:

prt.Thenable {....
    status: Status {thenable: prt.Thenable, instance: Rafx...
    _argObj: {value: 10, done: true},
    _breaker: {value: false}
    ....

ThenableStatus 构造函数与 Promises 无关,它们完全是自定义的。

令我惊讶的是,这甚至有效:

const x = Promise.resolve()
.then(() => console.log("2nd promise"))
.then(() => {
  return rafx.async("hello")
  .loop(function(str){
    return str;
  })
  .until(str => window.testVar === " world!")
  .then(str => str + window.testVar);
});

console.log(x instanceof Promise);

x.then((value) => console.log("3rd promise", value))
.catch((e) => console.log(e));
<script src="https://cdn.jsdelivr.net/npm/rafx"></script>
<button onclick="window.testVar = ' world!';">set testVar to ' world!'</button>

您可以验证 Promise.prototype.then !== rafx.Thenable.prototype.thenthen 实现是完全独立的,如 here;

那么 Promise 怎么可能理解我的 API 是如何工作的????? (我确定我遗漏了一些非常清楚的东西)

PS:我用常规箭头函数(this 绑定的原因)替换了所有箭头函数,它仍然有效,但不应该..

Promises 的规范旨在使其可以与其他“thenables”互操作。即,具有 .then 属性 的对象是一个函数。如果你用 thenable 解决一个 promise(在你的例子中是通过在 .then 块中返回一个 thenable),外部 promise 将调用该函数,传入一个 resolve 和 reject 函数,并等待内部 thenable 到调用解决。只有这样,外部承诺才会解决。

例如:

const promise = new Promise((resolve, reject) => {
  const myThenable = {
    then: (resolve2, reject2) => {
      console.log('running .then')
      setTimeout(() => {
        console.log('resolving inner');
        resolve2("hello");
      }, 1000)
    }
  }

  console.log('resolving outer');
  resolve(myThenable);
})

promise.then(result => {
  console.log('final result', result);
})

然后你为你的 thenable 获得的代码并不是为了处理这个而设计的,但显然它可以:

prt.Thenable.prototype.then = function(f, rest){

当 promise 调用您的 .then 函数时,f 将是 resolve 函数,而 rest 将是 reject 函数。在你调用 f 的路上的某个点,它恰好具有你想要的行为,显然它没有导致任何异常 rest 成为你不期望的函数。