【问题标题】:Building an array of deferred functions (promises)?构建一系列延迟函数(承诺)?
【发布时间】:2017-01-21 20:53:07
【问题描述】:

我正在学习 Promise,在这个示例中,我正在尝试创建一组我可以使用 Promise.all(...) 执行的 Promise(在 native ES6 下)。

promise 应该“启动”一个函数,将传递给它的数字加倍。 我预计承诺的执行会推迟到我调用 Promises.all() 之后,但结果会立即打印出来。我错过了什么??

我希望承诺在我打电话给他们时开始,而不是尽快开始(如果不清楚的话)

 var buildPromises = function(numbers) {
    var res = [];
     numbers.forEach(function(num) {
         var p = new Promise(function(resolve, reject) {
             console.log(num * 2);
         });
         res.push(p);
     });
     return res;
 }

 var numbers = [1, 2, 3];
 var p = buildPromises(numbers); 

【问题讨论】:

    标签: javascript ecmascript-6


    【解决方案1】:

    promise 执行器函数(你传递给new Promise() 的回调函数)被设计为立即执行,因此你会立即看到你所有的console.log() 语句。

    执行程序中通常发生的情况是,您启动了一些异步操作,例如 ajax 请求或异步文件 I/O 请求,然后一段时间后,该请求将调用 resolve(xxx) 以使用值解析该承诺。您现在拥有的没有异步操作,从不调用 resolve() 并且根本不应该使用 Promise,因为这里没有异步活动。

    promise 不是函数。它不是“执行”的。因此,您实际上并没有像您的问题所暗示的那样创建具有承诺的延迟函数数组。你可以使用 Promise 来跟踪一些异步操作,并且当这些 Promise 通过将监听器附加到 Promise 解决时,你可以执行一些函数,但你并没有真正执行 Promise。

    要承诺您正在创建工作,您需要提供作为传递给new Promise(fn) 的承诺执行器回调执行的函数。这就是执行发生的地方。 Promise 本身只是一个对象,用作某些异步操作的未来值的占位符。当执行器中的代码调用resolve(someValue) 时,会设置承诺值。或者,可以通过调用reject(someError) 来指示错误。同时,executor 函数之外的代码可以向.then().catch() 注册侦听器,以侦听promise 中的状态变化(未来某个时间,当promise 满足某个值或以错误结束时)。

    因此,在调用 resolve()reject() 之后,适当的事件侦听器(使用 .then().catch() 注册)将触发,通知侦听代码终于有解决方案这个承诺(值或错误)。然后,该侦听代码可以处理该值或错误。

    Promise.all() 接受一个承诺数组并返回一个新的主承诺,当任何一个承诺数组拒绝或当所有承诺数组都被解决时,它被一个值数组解决。它会监视所有其他承诺,并从本质上为您提供所有这些承诺的摘要。

    为了模拟异步操作,我们可以将所有操作放在setTimeout() 中,然后调用resolve(),如下可运行的sn-p:

     var buildPromises = function (numbers) {
         var res = [];
         numbers.forEach(function (num) {
             var p = new Promise(function (resolve, reject) {
                 // this is called immediately and it starts
                 // an asynchronous operation that will finish later
                 setTimeout(function () {
                     var result = num * 2;
                     console.log("individual:", result);
                     // resolve the promise with our result
                     resolve(result);
                 }, Math.floor(Math.random() * 500) + 500);
             });
             res.push(p);
         });
         return Promise.all(res);
     }
    
     var numbers = [1, 2, 3, 4, 5];
     buildPromises(numbers).then(function (results) {
         console.log("group: ", JSON.stringify(results));
     });

    在运行此 sn-p 后的结果中,请注意单个 console.log() 语句可能按任何顺序(因为异步操作通常在时间上不可预测),但 Promise.all() 组结果始终保存在数组中 Promise 的原始顺序。这是Promise.all() 提供的另一项服务。


    此外,它节省了使用.map() 来构建您的承诺数组的代码,因为您正在遍历一个数组并构建一个新数组,每个元素一个承诺,这正是.map() 的设计目的。你可以这样做:

    var buildPromises = function (numbers) {
        return Promise.all(numbers.map(function (num) {
            return new Promise(function (resolve, reject) {
                setTimeout(function () {
                    var result = num * 2;
                    console.log("individual:", result);
                    resolve(result);
                }, Math.floor(Math.random() * 500) + 500);
            });
        }));
    }
    
    var numbers = [1, 2, 3, 4, 5];
    buildPromises(numbers).then(function (results) {
         console.log("group: ", JSON.stringify(results));
    });

    【讨论】:

    • +1 我认为设置超时 Math.random() * 1000 会更清楚地展示 Promise 的目的。
    • @lonesomeday - 同意。我将超时设置为随机的。
    【解决方案2】:

    您缺少的是 Promise 动作的结果,而不是动作本身。 Promise 只是您现在可以持有的对象,而您可以等待将来的值。

    一旦您调用返回 Promise 的函数,该操作就会执行。如果您想延迟,请延迟调用该函数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-27
      • 2023-03-21
      • 1970-01-01
      相关资源
      最近更新 更多