jfr*_*d00 23 javascript design-patterns asynchronous callback
我正在寻找一个好的设计模式来跟踪一堆不同的异步JavaScript活动(图像加载,多个AJAX调用,有序的AJAX调用等等),这比仅仅很多自定义回调和自定义状态变量更好.你建议我用什么?是否有任何类型的队列系统能够具有超越排序的逻辑?
我有一个启动序列,涉及许多异步进程(加载图像,等待定时器,进行一些ajax调用,进行一些初始化).一些异步流程可以同时启动(加载图像,AJAX调用),有些必须排序(运行AJAX调用#1,然后运行AJAX调用#2).现在,我已经完成了所有关闭回调函数和一系列全局状态的操作,这些状态跟踪已完成或未完成的内容.它有效,但它很乱,我有一些错误,因为确保你正确处理所有排序可能性和错误条件的复杂性.
当你遇到问题时,调试也很麻烦,因为它就像海森堡的不确定性原理.只要在序列中的任何位置设置断点,一切都会发生变化.您必须在代码中放置各种调试语句,以试图辨别正在发生的事情.
这是一个更具体的描述:
有三个图像加载.加载一个特定图像后,我想显示它.一旦显示一段时间后,我想显示第二张图像.第三个进入队列以便稍后显示.
有三个AJAX调用必须按连续顺序发生(一个的输出用作下一个输入的一部分).
当完成AJAX调用时,需要对结果进行大量JS处理,然后需要加载另外两个图像.
加载这两个图像时,还有一些显示内容要做.
完成所有操作后,您可以检查其中一个图像的显示时间,如果已经过了足够的时间,则显示下一个图像.如果没有,请在显示下一张图像之前再等一会儿.
每个步骤都有成功和错误处理程序.一些错误处理程序启动了仍可成功继续的备用代码.
我不希望任何人在这里遵循确切的过程,只是为了让人们了解这些步骤之间的逻辑类型.
编辑:我遇到了YUI的AsyncQueue,它不是我遇到的问题类型的完整解决方案,但是在同一个空间.对于排序或排序一堆异步操作似乎更多,但我不知道它对我所做的决策类型有何帮助.
现在,Promise 已成为 ES6 中的标准,并且许多优秀的 Promise 库都扩展了它以实现新功能和向后兼容性,看来 Promise 是解决这个问题的方法。
该解决方案首先采用每个异步操作并创建一个返回承诺的包装器:
对于加载图像:
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;
});
}
Run Code Online (Sandbox Code Playgroud)
用于进行 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();
});
}
Run Code Online (Sandbox Code Playgroud)
为了在执行操作之前等待特定的时间,您甚至可以制作一个 Promise 版本,setTimeout()以便它可以与其他 Promise 操作链接起来:
// delay, return a promise
// val is optional
function delay(t, val) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(val);
}, t);
});
}
Run Code Online (Sandbox Code Playgroud)
现在,可以将这些组合起来创建问题所要求的逻辑:
正在加载三张图像。一旦加载了一张特定图像,我就想显示它。一旦它显示了一定时间,我想显示第二张图像。第三个进入队列以供稍后显示。
// 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());
Run Code Online (Sandbox Code Playgroud)
这种用法.reduce()展示了一种经典的设计模式,即使用 Promise 对数组上的一系列操作进行排序。
三个 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);
});
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
11040 次 |
| 最近记录: |