下面是我使用 Q.js 的建议。关键是任何时候你想异步做某事,你应该返回一个promise,一旦任务完成你应该解决这个promise。这允许函数的调用者监听要完成的任务,然后做其他事情。
和以前一样,我用 评论了我的更改// ***
。如果您还有其他问题,请告诉我。
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;
}
编辑
defer
创建一个Deferred,它包含两部分,apromise
和resolve
函数。由promise
返回getSizeSettingsFromPage
。基本上,返回一个承诺是一个函数说“我稍后会回复你”的一种方式。一旦函数完成它的任务(在这种情况下,一旦image.onload
事件被触发),该resolve
函数将用于解决承诺。这表明任何等待任务已完成的承诺。
这是一个更简单的例子:
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 秒。由于它是异步的,它返回一个 Promise ( deferred.promse
) 并在 2 秒等待 ( ) 后解决该 Promise deferred.resolve
。该then
方法可以在 Promise 上调用,并传递一个回调函数以在 Promise 解决后执行。回调函数在 promise 的分辨率值中传递。
在您的情况下,我们有一系列承诺,我们需要在执行函数之前等待所有承诺都完成,因此我们使用了 Q.all。这是一个例子:
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