Благодаря обещаниям, теперь стандартным в ES6, и множеству хороших библиотек обещаний, расширяющих возможности как для новых функций, так и для обратной совместимости, кажется, что обещания - это путь сюда.
Решение начинается с выполнения каждой асинхронной операции исоздание оболочки, которая возвращает обещание:
для загрузки изображения:
function loadImage(url) {
return new Promise(function(resolve, reject) {
var img = new Image();
img.onload = function() {
resolve(img);
};
img.onerror = img.onabort = function() {
reject(url);
};
img.src = url;
});
}
для выполнения вызова Ajax (упрощенная версия):
function ajaxGet(url) {
return new Promise(function(resolve, reject) {
var req = new XMLHttpRequest();
req.addEventListener("load", resolve);
req.addEventListener("error", reject);
req.addEventListener("abort", reject);
req.open("GET", url);
req.send();
});
}
для ожиданияЗа определенное время до выполнения операции вы даже можете создать версию обещания setTimeout()
, чтобы она могла быть связана с другими операциями обещания:
// delay, return a promise
// val is optional
function delay(t, val) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(val);
}, t);
});
}
Теперь их можно объединить для создания логикизадаваемый вопрос:
Загрузка трех изображений.Как только будет загружено одно конкретное изображение, я хочу его отобразить.Как только оно будет отображаться в течение определенного времени, я хочу отобразить второе изображение.Третий помещается в очередь для последующего отображения.
// start all three images loading in parallel, get a promise for each one
var imagePromises = [url1, url2, url3].map(function(item) {
return loadImage(item);
});
// display the three images in sequence with a delay between them
imagePromises.reduce(function(p, item) {
return p.then(function() {
// when the next image is ready display it
return item.then(function(img) {
displayImage(img);
return delay(15 * 1000);
});
});
}, Promise.resolve());
При использовании .reduce()
показан классический шаблон проектирования для последовательности последовательности операций над массивом с использованием обещаний.
Существует три вызова AJAX, которые должны выполняться последовательно (выход одного используется как часть ввода следующего).
и
Когда AJAX-вызовы завершены, выполняется обработка результатов JS, а затем необходимо загрузить еще два изображения.
var p = ajaxGet(url1).then(function(results1) {
// do something with results1
return ajaxGet(url2);
}).then(function(results2) {
// do something with results2
return ajaxGet(url3);
}).then(function(results3) {
// process final results3 here
// now load two images and when they are loaded do some display stuff
return Promise.all(loadImage(imgx), loadImage(imgy)).then(function(imgs) {
doSomeDisplayStuff(imgs);
});
});