如何使用q.js承诺与多个异步操作工作 [英] how to use q.js promises to work with multiple asynchronous operations

查看:93
本文介绍了如何使用q.js承诺与多个异步操作工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请注意:这个问题也是跨张贴在Q.js邮件列表在这里

Note: This question is also cross-posted in Q.js mailing list over here.

我曾与多个异步操作的情况和答案我接受指出,使用库如使用承诺q.js会更有利。

i had a situation with multiple asynchronous operations and the answer I accepted pointed out that using Promises using a library such as q.js would be more beneficial.

我相信重构我的code使用的承诺,但因为code是pretty久,我已经削减不相干的部分,并出口的关键零部件到一个单独的回购协议。

I am convinced to refactor my code to use Promises but because the code is pretty long, i have trimmed the irrelevant portions and exported the crucial parts into a separate repo.

回购是这里和最重要的文件是的这个

The repo is here and the most important file is this.

要求是,我想的页面大小是遍历所有dragged'n下降文件后,非空。

The requirement is that I want pageSizes to be non-empty after traversing all the dragged'n dropped files.

问题是,FileAPI操作里面的 getSizeSet​​tingsFromPage 函数导致的 getSizeSet​​tingsFromPage 是异步。

The problem is that the FileAPI operations inside getSizeSettingsFromPage function causes getSizeSettingsFromPage to be async.

所以我不能把 checkWhenReady(); 像这样

function traverseFiles() {
  for (var i=0, l=pages.length; i<l; i++) {
    getSizeSettingsFromPage(pages[i], calculateRatio);   
  }
  checkWhenReady(); // this always returns 0.
}

这工作,但效果不理想。我preFER所有经历了此功能calculateRatio成功的页面后打电话到checkWhenReady一次。

This works, but it is not ideal. I prefer to call checkWhenReady just ONCE after all the pages have undergone this function calculateRatio successfully.

function calculateRatio(width, height, filename) {
  // .... code 
  pageSizes.add(filename, object);
  checkWhenReady(); // this works but it is not ideal. I prefer to call this method AFTER all the `pages` have undergone calculateRatio
  // ..... more code...
}

如何重构code利用承诺在Q.js?

推荐答案

我的建议得到与Q.js这方面的工作如下。关键是,任何时候你希望异步做的事,你应该返回一个承诺,一旦任务完成,你应该可以解决这一承诺。这使得该函数的调用者监听要完成的任务,然后去做别的事情。

My suggestions to get this working with Q.js are below. The key is that anytime you want to do something asynchronously, you should return a promise, and once the task is completed you should resolve that promise. That allows the callers of the function to listen for the task to be completed and then do something else.

像以前一样,我有评论我的修改// *** 。让我知道,如果您有任何进一步的问题。

As before, I have commented my changes with // ***. Let me know if you have any further questions.

        function traverseFiles() {
            // *** Create an array to hold our promises
            var promises = [ ];
            for (var i=0, l=pages.length; i<l; i++) {
                // *** Store the promise returned by getSizeSettingsFromPage in a variable
                promise = getSizeSettingsFromPage(pages[i]);
                promise.then(function(values) {
                    var width = values[0],
                        height = values[1],
                        filename = values[2];
                    // *** When the promise is resolved, call calculateRatio
                    calculateRatio(width, height, filename);
                });
                // *** Add the promise returned by getSizeSettingsFromPage to the array
                promises.push(promise);
            }
            // *** Call checkWhenReady after all promises have been resolved
            Q.all(promises).then(checkWhenReady);
        }

        function getSizeSettingsFromPage(file) {
            // *** Create a Deferred
            var deferred = Q.defer();
            reader = new FileReader();
            reader.onload = function(evt) {
                var image = new Image();
                image.onload = function(evt) {
                    var width = this.width;
                    var height = this.height;
                    var filename = file.name;
                    // *** Resolve the Deferred
                    deferred.resolve([ width, height, filename ]);
                };
                image.src = evt.target.result;
            };
            reader.readAsDataURL(file);
            // *** Return a Promise
            return deferred.promise;
        }


修改

延迟创建一个延迟,它包含两个部分,一个决心功能。在 getSizeSet​​tingsFromPage 返回。基本上返回许是给一个函数说的一种方式:我会回来给你以后。一旦函数已经完成它的任务(在这种情况下,一旦 image.onload 事件已触发)的解析功能用于解决的承诺。这表明,以任何等待的任务已经完成的承诺。


Edit

defer creates a Deferred, which contains two parts, a promise and the resolve function. The promise is returned by getSizeSettingsFromPage. Basically returning a promise is a way for a function to say "I'll get back to you later." Once the function has completed it's task (in this case once the image.onload event has fired) the resolve function is used to resolve the promise. That indicates to anything waiting on the promise that the task has been completed.

下面是一个简单的例子:

Here's a simpler example:

function addAsync(a, b) {
    var deferred = Q.defer();
    // Wait 2 seconds and then add a + b
    setTimeout(function() {
        deferred.resolve(a + b);
    }, 2000);
    return deferred.promise;
}

addAsync(3, 4).then(function(result) {
    console.log(result);
});
// logs 7 after 2 seconds

addAsync 函数将两个电话号码,但它加入他们之前等待2秒。由于它是异步的,它会返回一个承诺( deferred.promse ),并解析2秒钟的等待( deferred.resolve )。在然后方法可以算得上一个承诺,并通过一个回调函数的承诺已经得到解决后执行。回调函数传递的承诺的分辨率值。

The addAsync function adds two numbers but it waits 2 seconds before adding them. Since it's asynchronous, it returns a promise (deferred.promse) and resolves the promise after the 2 second wait (deferred.resolve). The then method can be called on a promise and passed a callback function to be executed after the promise has been resolved. The callback function is passed in the resolution value of the promise.

在你的情况,我们有承诺的数组,我们需要等待的所有执行函数之前进行其中的的,所以我们用的 Q.all 。这里有一个例子:

In your case, we had an array of promises and we needed to wait for all of them to be done before executing a function, so we used Q.all. Here's an example:

function addAsync(a, b) {
    var deferred = Q.defer();
    // Wait 2 seconds and then add a + b
    setTimeout(function() {
        deferred.resolve(a + b);
    }, 2000);
    return deferred.promise;
}

Q.all([
    addAsync(1, 1),
    addAsync(2, 2),
    addAsync(3, 3)
]).spread(function(result1, result2, result3) {
    console.log(result1, result2, result3);
});
// logs "2 4 6" after approximately 2 seconds

这篇关于如何使用q.js承诺与多个异步操作工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆