【问题标题】:Promises chaining, wrong orderPromise 链接,错误的顺序
【发布时间】:2019-03-19 08:31:30
【问题描述】:

我想了解 Javascript 中的承诺链。所以我写了这个小小提琴: https://jsfiddle.net/GarfieldKlon/89syq4fh/

它按预期工作。 c 等待 b,b 等待 a。

但是当我将这些行更改为:

a().then( result => console.log(result))
.then( () => {b().then( result => console.log(result))})
.then( () => {c().then( result => console.log(result))});

所以我在 b 和 c 周围添加了花括号,然后输出为 1、3、2。我不明白为什么。

当我添加退货时,它会再次起作用:

a().then( result => console.log(result))
.then( () => {return b().then( result => console.log(result))})
.then( () => {return c().then( result => console.log(result))});

但是为什么呢?当没有花括号时,您只能写一个语句,对吗?而且这个语句是隐式返回的?

当你使用花括号时,你必须明确地返回一些东西?

但是为什么在使用大括号而不返回时会弄乱顺序呢?为什么返回丢失时它仍然会记录一些东西?

【问题讨论】:

  • 用花括号,你需要返回值,这是热胖箭头的作品。
  • 在这两种情况下,排序都是随机的。在 then 块中返回实际上是为了消耗下一个 then 块(在您的情况下不会发生)
  • 这与 Promise 没有任何关系,这就是箭头函数语法的工作原理。如果你定义了一个块体,除非你明确地做,否则什么都不会返回。
  • @varun agarwal 在哪些情况下排序是随机的?链接承诺时,顺序不应该是随机的,对吗?

标签: javascript promise es6-promise chaining method-chaining


【解决方案1】:

当没有花括号时,您只能编写一个隐式返回的表达式? 当你使用花括号时,你必须明确返回一些东西?

Yes.

但是为什么在使用大括号而不返回时会弄乱顺序?为什么返回丢失时它仍然会记录一些东西?

因为 promise then 函数依赖于链接的返回值。

记住then returns a new promise for the result of the callback。当该结果是另一个承诺时,它会等待该内部承诺的结果,然后再履行返回的承诺 - 您正在链接第二个 then() 调用的那个。

如果您的回调开始 b().then(…) 但返回 undefined,则链中的下一步(c() 调用)不会等待 b 完成。

【讨论】:

    【解决方案2】:

    当使用箭头语法时,你可以在很多方面解释它:

    () => 'hello'
    

    等价于

    () => { return 'hello'; }
    

    但是,当做

    () => {'hello'}
    

    和你写的一样:

    .then( () => {b().then( result => console.log(result))})
    

    那么你可以把它解释为

    () => {'hello'; return;}
    

    因此,在代码中,您的承诺处理 b().then( result => console.log(result)) 在 void return; 完成之前被调用。您根本没有返回结果承诺对象。它会在 b 完成时调用,无论您在做什么。

    【讨论】:

    • 感谢您提供有用的示例。所以 'c' 在 'b' 之前被调用,因为两者都不是承诺,而 'c' 的等待时间更短。正确的?如果是,那我想我明白了。
    • @GarfieldKlon bc 都是返回承诺对象的函数。然而,在您的示例中,您并没有在a()....then 链中返回这些承诺对象(没有return 的那个)。 a.then 收到了一个 void 返回,它不是一个承诺对象。因此,当来自b() 的承诺对象被满足时,它会继续进行而不是等待。在带有return 语句的示例中,a.then 确实收到了一个承诺对象(来自b())并在运行下一个.then 语句之前等待它。
    【解决方案3】:

    这与箭头函数有关。当您省略花括号时,返回是隐式的。所以

    const f = () => 42;
    

    等价于

    const f = () => { return 42; };
    

    另外,b().then(something).then(somenthingElse) 仍然只有一个表达式,所以可以隐式返回。

    【讨论】:

      【解决方案4】:

      Promise 是一个对象,表示异步操作的结果。 重要的是要记住,Promise 不仅仅是注册回调以在某些异步代码完成时运行的抽象方法——它们代表该异步代码的 结果

      当我们编写.then() 调用链时,我们并没有在单个 Promise 对象上注册多个回调。相反,每次调用 then() 方法都会返回一个新的 Promise 对象。

      在传递给then() 的函数完成之前,新的 Promise 对象不会被实现。满足承诺 1 的值成为 callback2() 函数的输入。回调执行一些计算并返回一个值v。当回调返回值时,promise 被解析为值v

      当一个 Promise 被一个本身不是 Promise 的值解析时,它会立即用那个值来实现。

      在这种情况下理解很重要,所以我改写一下:如果一个回调返回一个非 Promise,那么这个返回值就成为了 Promise 的值,并且 Promise 被实现了。 p>

      如果返回值v 本身是一个Promise,那么这个promise 已经解决但还没有实现。

      您的情况:

      请允许我在这里发布函数 a、b 和 c:

      let a = function() {
          return new Promise( (resolve, reject) => {
          setTimeout(() => resolve(1), 300);
        });
      }
      let b = function() {
          return new Promise( (resolve, reject) => {
          setTimeout(() => resolve(2), 200);
        });
      }
      let c = function() {
          return new Promise( (resolve, reject) => {
          setTimeout(() => resolve(3), 100);
        });
      }
      

      和实现

      a().then( result => console.log(result))
      .then( () => {b().then( result => console.log(result))})
      .then( () => {c().then( result => console.log(result))});
      

      这是正在发生的事情

      通过将花括号添加到箭头函数体,我们不再获得自动返回。

      这个函数现在返回 undefined 而不是返回一个 Promise,这意味着当前的 Promise 已经完成,并且这个 Promise 链中的下一个阶段将被调用,并使用 undefined 作为它的输入。

      因此,函数a 被调用,返回一个promise,即一旦完成,就会调用callback1。 回调 1 返回 undefined,因此 promise1 已完成,下一个 .then() 调用回调 2。 callback2 调用 b,它本身返回一个 Promise,但 callback2 不返回这个 Promise。 callback2 返回undefined。 Promise2 用undefined 实现,生活还在继续——Callback3 被调用。

      此时bc 正在同时运行,因为cb 快100 毫秒,所以你得到了1,3,2 的顺序。

      术语

      当第一个回调(then 方法的参数)被调用时,我们说承诺已经实现。

      我们说,当调用第二个回调(then 方法的参数)时,Promise 已被拒绝。

      如果一个 Promise 既没有被履行也没有被拒绝,那么它就是待处理的。一旦一个承诺被履行或被拒绝,我们就说它已经解决了。

      如果异步代码正常运行(并且 Promise 已实现),那么该结果本质上就是代码的返回值。

      如果 Promise 实现了,那么该值是一个返回值,它会被传递给注册为 then() 的第一个参数的任何回调函数。

      Promise 也可以解决。很容易将这种已解决状态与已完成状态或已解决状态混淆,但两者并不完全相同。

      Resolved 意味着另一个 Promise 已被分配给当前 Promise 的值。当前的 Promise 已与另一个 Promise 关联或“锁定”。 我们还不知道 Promise 会被实现还是被拒绝,因为它还没有解决。它的命运现在完全取决于 Promise 会发生什么

      【讨论】:

        猜你喜欢
        • 2023-03-22
        • 2018-06-30
        • 2017-07-13
        • 1970-01-01
        • 1970-01-01
        • 2015-05-07
        • 1970-01-01
        • 2013-09-26
        • 2013-07-19
        相关资源
        最近更新 更多