我建议使用Q.js使这个工作正常,以下是我的建议。关键是,每当您想要异步执行某些操作时,应返回一个Promise,并且一旦任务完成,您应该解决该Promise。这允许调用该函数的用户等待任务完成,然后执行其他操作。
与以前一样,我已经用 // ***
注释了我的更改内容。如果您有任何进一步的问题,请告诉我。
function traverseFiles() {
var promises = [ ];
for (var i=0, l=pages.length; i<l; i++) {
promise = getSizeSettingsFromPage(pages[i]);
promise.then(function(values) {
var width = values[0],
height = values[1],
filename = values[2];
calculateRatio(width, height, filename);
});
promises.push(promise);
}
Q.all(promises).then(checkWhenReady);
}
function getSizeSettingsFromPage(file) {
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;
deferred.resolve([ width, height, filename ]);
};
image.src = evt.target.result;
};
reader.readAsDataURL(file);
return deferred.promise;
}
编辑
defer
创建一个包含两部分的Deferred, 一个是promise
, 另一个是resolve
函数。 promise
是由getSizeSettingsFromPage
返回的。基本上,返回一个promise是一个函数说“我稍后会回来”这种方式。一旦函数完成任务(在此例中,即image.onload
事件已触发),则使用resolve
函数来解析promise。这表示等待promise的任何内容都已完成任务。
以下是一个更简单的示例:
function addAsync(a, b) {
var deferred = Q.defer();
setTimeout(function() {
deferred.resolve(a + b);
}, 2000);
return deferred.promise;
}
addAsync(3, 4).then(function(result) {
console.log(result);
});
addAsync
函数会在相加之前等待2秒钟,它返回一个异步的promise(deferred.promise
),并在等待2秒后解决该promise(deferred.resolve
)。可以在promise上调用then
方法,并传递一个回调函数以在promise被解决后执行。该回调函数将传入promise的解决值。
在您的情况中,我们有一个promise数组,并且需要等待所有promise完成后再执行某个函数,因此我们使用了Q.all。这是一个例子:
function addAsync(a, b) {
var deferred = Q.defer();
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);
});
defer
的原因,以及其他一些事情。干杯 :) - Nathan WallgetSizeSettingsFromPage
返回的Promise去调用calculateRatio
而无需传递whenReady
参数。只要您在使用Promise,为什么不全都用呢:-)。Promises消除了那些回调函数的需要。 - Nathan Wall