これを 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
aと関数の 2 つの部分を含むDeferredを作成します。はによって返されます。基本的に promise を返すことは、関数が「後で返信します」と言う方法です。関数がそのタスクを完了すると (この場合はイベントが発生すると)、関数は promise を解決するために使用されます。これは、タスクが完了したという約束を待っているものに示します。promise
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
関数は 2 つのaddAsync
数値を追加しますが、それらを追加する前に 2 秒待機します。非同期であるため、Promise を返し ( deferred.promse
)、2 秒待機した後に Promise を解決します ( deferred.resolve
)。プロミスでthen
メソッドを呼び出し、プロミスが解決された後に実行されるコールバック関数を渡すことができます。コールバック関数は、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