在ES6 JavaScript中,为什么then()的实现处理程序返回的承诺与then()返回的承诺不同?

在ES6 JavaScript中,为什么then()的实现处理程序返回的承诺与then()返回的承诺不同?,javascript,es6-promise,Javascript,Es6 Promise,我有一些方块从页面上滑下,以链式的方式: 代码是: new Promise(function(resolve, reject) { $("#shape").css({ top: 100 }); setTimeout(function() { resolve(); }, 1000); }).then(function() { return new Promise(function(resolve, reject) { $("#shape2").css(

我有一些方块从页面上滑下,以链式的方式:

代码是:

new Promise(function(resolve, reject) {
  $("#shape").css({
    top: 100
  });
  setTimeout(function() {
    resolve();
  }, 1000);
}).then(function() {
  return new Promise(function(resolve, reject) {
    $("#shape2").css({
      top: 100
    });
    setTimeout(function() {
      resolve();
    }, 1000);
  });
}).then(function() {
  return new Promise(function(resolve, reject) {
    $("#shape3").css({
      top: 100
    });
    setTimeout(function() {
      resolve();
    }, 1000);
  });
}).then(function() {
  return new Promise(function(resolve, reject) {
    $("#shape4").css({
      top: 100
    });
    setTimeout(function() {
      resolve();
    }, 1000);
  });
});
let foobar;

let lala = new Promise(function(resolve, reject) {
  $("#shape").css({
    // ...
}).then(function() {
  foobar =  new Promise(function(resolve, reject) {
    // ...
  return foobar;
});

lala.then(function() {
  console.log("checking:", lala, foobar, lala === foobar);
  return new Promise(function(resolve, reject) {
(代码在这里的代码片段中运行不太好:这里第一个方块已经开始向下滑动)

因此,要查看履行处理程序返回了什么承诺,以及
返回了什么承诺

代码是:

new Promise(function(resolve, reject) {
  $("#shape").css({
    top: 100
  });
  setTimeout(function() {
    resolve();
  }, 1000);
}).then(function() {
  return new Promise(function(resolve, reject) {
    $("#shape2").css({
      top: 100
    });
    setTimeout(function() {
      resolve();
    }, 1000);
  });
}).then(function() {
  return new Promise(function(resolve, reject) {
    $("#shape3").css({
      top: 100
    });
    setTimeout(function() {
      resolve();
    }, 1000);
  });
}).then(function() {
  return new Promise(function(resolve, reject) {
    $("#shape4").css({
      top: 100
    });
    setTimeout(function() {
      resolve();
    }, 1000);
  });
});
let foobar;

let lala = new Promise(function(resolve, reject) {
  $("#shape").css({
    // ...
}).then(function() {
  foobar =  new Promise(function(resolve, reject) {
    // ...
  return foobar;
});

lala.then(function() {
  console.log("checking:", lala, foobar, lala === foobar);
  return new Promise(function(resolve, reject) {
在调试控制台中,我们可以看到承诺是不同的。但为什么它们必须是不同的呢

其实里面说,

[如果
.then()
]返回另一个挂起的承诺对象,则
返回的承诺的解决/拒绝将在处理程序返回的承诺的解决/拒绝之后进行。另外,
then
返回的承诺值将与处理程序返回的承诺值相同

这表明这两个承诺是不同的(由履行处理程序返回的承诺和由
.then()
返回的承诺)。(我在中找不到描述)。问题是为什么?他们不能是同一个承诺吗

第二部分说:

此外,then返回的承诺值将与处理程序返回的承诺值相同

我最初以为它的意思是“届时返回的承诺将与处理程序返回的承诺相同”,但后来才发现它的实际意思是:“那么,
返回的承诺的解析值将与处理程序返回的承诺的解析值相同”。(这是正确的描述方式吗?)


在Google Chrome内部,两个承诺将显示相同的解析值
123456

,这是因为这些承诺是在不同的时间创建的:

newpromise(..).then()
返回一个立即可用的承诺(如
lala
),而传递给该
then
方法的回调将仅在
newpromise(..)
解析时执行,即可能要晚很多时间

然后
回调最终执行时,它可以完全控制返回的内容,因此如果它决定返回一个新的承诺,那么该承诺怎么可能是前一段时间通过调用
.then()
创建的承诺呢

或者,换言之,如果
then
回调返回一个新的承诺,为什么JavaScript会否决该创建,并将已经存在的承诺注入其中?这是不可取的

在您的代码中,如果您在任何
中检查
lala
,然后
回调,您将注意到它已被定义(因为此时所有非回调代码都已完成),而对
foobar
的赋值仍有待执行。它们不能相同。

非常简短的回答then()返回启用方法链接的承诺,如果您告诉履行处理程序返回承诺,则将向下一个then()提供等效的承诺。也就是说,如果创建一个承诺并将其返回,.then()将访问它

下面的证明

const promise1 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve("resolve promise1");
    }, 1000);
});

const promise2 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve("resolve promise2");
    }, 2000);
});

promise1.then(() => { return promise2 }).then(value => console.log(value))
//this will return resolve promise 2 after 2 seconds
这意味着.then()调用将使用Promise1(在本例中为promise2)的履行处理程序返回的承诺的resolve值

对于您的情况,foobar!==lala,因为在本例中lala是链中的“第一个承诺”,foobar是第四个或第五个,但是当您访问lala.then()时,您正在访问foobar承诺,但是因为它不包含任何解析值,所以您不会注意到


用一个值解析foobar并在lala中访问它。然后(res=>res…)

“它们不能是相同的承诺吗?”-不,它们不能。需要先创建
then()
返回的回调函数,然后再运行回调函数,该回调函数将在将来创建另一个回调函数。如果有,承诺可能会拒绝。因此,当返回
foobar
时,一些机制会接受此返回值,并查看它是否为承诺,并立即调用
returnedValue。然后(fn1,fn2)
,其中,
fn1
是履行处理程序,它解析
lala
…您可以在第2.3节的参考中找到发生的情况的规范。在该文本中,“表
x
”是您的
foobar
promise
是您的
lala
。您还可以了解库是如何实现该特定规范的。我已经发布了我自己的实现,很高兴你解释了OP的代码,但我很肯定OP知道这一点。重写他们的代码也很好,但我很确定OP也没有要求这样做。你在哪里试图回答他们的问题?我重新编写了代码,以便更好地解释如果其他人绊倒了会发生什么,但你没有回答问题。这就像你发布答案时的一个要求。谢谢你指出这一点。我实际上得出了一个不同的结论,似乎它们实际上是一样的。在你更新之后,这句话是错误的:“then()不返回承诺,除了…”
then()
始终返回承诺。这实际上增加了混乱。