Q Promise 啥时候执行?

Posted

技术标签:

【中文标题】Q Promise 啥时候执行?【英文标题】: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() 只是一个承诺,只有在其数组中的所有承诺完成后才会完成 看到这些***.com/questions/35543964/…***.com/questions/38694958/… promise 是一个结果值,没有任何东西可以执行或调用。你想要的是一个返回承诺的函数——你可以随时存储和调用。 【参考方案1】:

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

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

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

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

【讨论】:

我真的很喜欢你的回复@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);
);

【讨论】:

以上是关于Q Promise 啥时候执行?的主要内容,如果未能解决你的问题,请参考以下文章

记录一下es6的promise的基本用法

递归执行promise nodejs

手写promise啥水平

为啥在使用promise时使用Q,bluebird框架? [复制]

promise之nodejsQ的详细用法总结

手写promise啥水平