【问题标题】:When do Q promises get executed?Q Promise 什么时候执行?
【发布时间】:2017-02-20 13:57:42
【问题描述】:

我在理解 Promise 时遇到了一个(看似根本的)问题。先上代码:

'use strict';

var Q = require("q");

var mockPromise = function (statement) {
    var deferred = Q.defer();

    console.log("I'm running before I'm queued ...");

    setTimeout(function () {
        deferred.resolve(statement);
    }, 5000);

    return deferred.promise;
};

var promises = [
    mockPromise("1st statement"),
    mockPromise("2nd statement"),
    mockPromise("3rd statement")
];

Q.all(promises)
.then(function (results) {
    console.log(results);
});

每个 promise 函数都会在将其添加到 promise 数组时被调用,而不是像我想象的那样调用 Q.all。

我在这里没有得到什么?

如何在不立即调用承诺的情况下将一组承诺排队?

【问题讨论】:

  • 为什么要将promise排队然后执行呢?如果它们一被触发就执行,速度会更快
  • Q.all() 只是一个承诺,只有在其数组中的所有承诺完成后才会完成
  • promise 是一个结果值,没有任何东西可以执行或调用。你想要的是一个返回承诺的函数——你可以随时存储和调用。

标签: javascript node.js q


【解决方案1】:
  1. Promise 是对象。它们没有被“执行”。他们被“解决”或“拒绝”。创建数组时,您正在执行 mockPromise() 函数 3 次。这个函数会立即在代码的那个点执行。

  2. mockPromise() 函数创建一个 deferred 并返回相关的 Promise。它还设置了一个计时器来解决将来返回的承诺。

  3. Q.all() 只是等待 3 个承诺被“解决”。 (从技术上讲,它返回一个新的 Promise,当之前的 3 个 Promise 被解决时,该 Promise 将被解决)

如果你想一个接一个地执行三个异步函数,我会推荐使用优秀的async.js 库。它提供了许多异步流控制原语。在您的情况下,您可能对 serieswaterfall 方法感兴趣。

【讨论】:

  • 我真的很喜欢你的回复@tato。在我的(未简化的)案例中,返回承诺的函数会根据计算添加到数组中。我注意到,甚至在数组完全填充之前,函数就被调用了。这不是一个大问题,但这不会造成竞争条件吗?
  • ...也就是说,如果 promises 数组仍在填充,Q.all(promises) 不能过早读取完成吗?
  • 在 javascript 中你永远不会有竞争条件。它是单线程的。所以第一次调用 mockPromise() 将在开始第二次之前完全执行。但是,请注意,mockPromise() 的完整执行 只涉及启动计时器。计时器完成将在未来发生,并将解决承诺。
  • ... 和 Q.all() 直到对 mockPromise() 的三个调用完全执行后才会执行(同样,只启动计时器)
  • @Lindauson 不,Q.all(promises) 永远不会过早读取完成,从 Q.all(promises) 返回的承诺将不会被解决,直到数组中的所有承诺都完成(解决或拒绝) )
【解决方案2】:

似乎令人困惑的是,您理解 Promise API 是为惰性评估而设计的,但事实并非如此。

Promise 是一种处理长时间运行请求的方式,它们旨在立即启动以最大限度地减少等待时间,并利用链接和连接来阐明应如何处理这些长时间运行请求的结果。

您可以尝试使用 api Q-Lazy,它允许您延迟调用 Promise,直到它们被订阅。

【讨论】:

  • 似乎 Q API 更关心同步承诺完成与同步调用。您认为这是一个正确的评估吗?
  • @Lindauson Promises 与调用无关
  • @Lindauson 没有真正同步,因为 Promise api 对时间的影响很小,但组织会很准确,Q API 有助于根据成功和失败条件组织回调的执行链。
【解决方案3】:

您通常会延迟异步功能,而不仅仅是一个值。例如:

'use strict';

var Q = require("q");

var mockPromise = function (statement) {
    var deferred = Q.defer();

    console.log("I'm running before I'm queued ...");

    setTimeout(function () {
        deferred.resolve(statement());
    }, 5000);

    return deferred.promise;
};

var promises = [
    mockPromise(function() { 
        console.log("running1"); 
        return "1st statement";
    }),
    mockPromise(function() { 
        console.log("running2"); 
        return "2nd statement";
    }),
    mockPromise(function() { 
        console.log("running3"); 
        return "3rd statement";
    }),
];

Q.all(promises)
.then(function (results) {
    console.log(results);
});

请注意,延迟功能将运行,无论您是否曾在承诺上调用.then

【讨论】:

  • 感谢您的回复安德鲁。对我来说更有趣的是,即使没有/之前调用 Q.all(promise),函数也会被执行。
【解决方案4】:

让我展示一个使用标准承诺的示例。它们的工作方式与 Q 承诺几乎相同:

function mockPromise(value) {
  return new Promise(resolve => {
    console.log("I'm not running before I'm queued ...");
    setTimeout(() => {
      resolve(value);
    }, 1000);
  });
}

mockPromise("1st promise").then(x => {
  console.log(x);
  return mockPromise("2nd promise");
}).then(x => {
  console.log(x);
  return mockPromise("3nd promise");
}).then(x => {
  console.log(x);
});

【讨论】:

    猜你喜欢
    • 2012-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-07
    • 1970-01-01
    • 2011-06-23
    • 2013-05-01
    • 2019-06-16
    相关资源
    最近更新 更多