用于管理多个异步的JavaScript操作设计模式 [英] Design pattern for managing multiple asynchronous JavaScript operations

查看:139
本文介绍了用于管理多个异步的JavaScript操作设计模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一个好的设计模式保持了一堆不同的异步的JavaScript活动的轨迹(图片加载,多个AJAX调用,测序AJAX调用等),这比只是很多定制的回调和自定义的状态更好变量。你会建议我使用?是否与有逻辑不仅仅是测序能力的任何类型的队列系统?

例题

我有一个涉及多个异步进程的启动顺序(加载图像,等待计时器,使得一些Ajax调用,做一些初始化)。一些非同步过程可以发射在同一时间(图像的装载,AJAX调用)运行,部分待测序(运行AJAX调用#1,然后AJAX调用#2)。现在,我就拥有了一切流失的回调函数和一堆全局状态的持续跟踪哪些已经或尚未完成。它的工作原理,但它是相当混乱和我有,因为确保你处理所有的测序正确的可能性和错误条件的复杂性的一些错误。

当你有问题,它也是一个相当痛苦的调试,因为它像海森堡测不准原理。只要你的序列,一切都在改变中的任何位置设置断点。你必须把各种在code调试语句,试图辨别发生了什么。

下面是一个更具体的描述:


  1. 有三个图像加载。当一个特定的图像加载,我想显示它。一旦它已经显示了一定的时间,我想显示第二图像。第三个去,以便以后显示的队列。


  2. 有必须在连续顺序(一个的输出作为下一个的输入的一部分)。发生3的AJAX调用


  3. 在Ajax调用都做了,还有一堆的结果JS处理做的,然后两个图像需要得到加载。


  4. 在这两个图像加载,还有一些显示的东西做的。


  5. 当做好了所有的,你检查的图像多久已经显示,如果有足够的时间已经过去了,显示下一个图像。如果没有,显示下一个图像之前等待一些时间。


每个步骤都有成功和错误处理程序。有些错误处理程序的开球替代code仍然能够继续成功。

我不希望任何人在这里遵循的确切过程,但只给乡亲步骤之间的逻辑类型的想法。

编辑:我碰到 YUI的AsyncQueue 这是不是类型的完整解决方案来问题我有,不过是在同一个空间。这似乎是更测序或订购了一堆异步操作,但我看不出它如何决定的类型有助于使我有。


解决方案

通过承诺现在ES6标准和许多扩展,对于这两个新功能和向后兼容性好承诺库,似乎应许是去这里的路。

该解决方案以每个异步操作并创建返回一个承诺的包装开始:

有关加载图像:

 函数的LoadImage(URL){
    返回新希望(函数(解析,拒绝){
        VAR IMG =新的图像();
        img.onload =功能(){
            解决(IMG);
        };
        img.onerror = img.onabort =功能(){
            拒绝(URL);
        };
        img.src =网址;
    });
}

有关调用Ajax(简体版):

 函数ajaxGet(URL){
    返回新希望(函数(解析,拒绝){
        VAR REQ =新XMLHtt prequest();
        req.addEventListener(负荷,决心);
        req.addEventListener(错误,拒绝);
        req.addEventListener(中止,拒绝);
        req.open(GET,URL);
        req.send();
    });
}

有关执行操作前等待一个特定的时间量,你甚至可以制作一个承诺版本的setTimeout(),因此它可以与其他承诺业务被链接:

  //延时,返回一个承诺
// val为可选
功能延迟(T,VAL){
    返回新希望(函数(解析){
        的setTimeout(函数(){
            解决(VAL);
        },T);
    });
}

现在,这些都可以被组合以创建逻辑问的问题是:


  

有三个图像加载。当一个特定的图像加载,我想显示它。一旦它已经显示了一定的时间,我想显示第二图像。队列中的第三个无二后显示。


  //启动所有三个图像并行加载,得到每一个承诺
VAR imagePromises = [URL1,URL2,URL3] .MAP(函数(项目){
    返回的LoadImage(项目);
});//与它们之间的延迟按顺序显示三个图像
imagePromises.reduce(功能(P,项目){
    返回p.then(函数(){
        //当一个图像已准备就绪显示它
        返回item.then(功能(IMG){
            displayImage(IMG);
            返回延迟(15 * 1000);
        });
    });
},Promise.resolve());

这使用。降低()的显示使用的承诺对数组排序的一系列操作的经典设计模式。


  

有必须在连续顺序(一个的输出作为下一个的输入的一部分)。

发生3的AJAX调用


  

当Ajax调用完成后,有一堆的结果JS处理做,然后需要获得加载两个图像。


  VAR P = ajaxGet(URL1)。然后(功能(结果:1){
    //做什么结果1
    返回ajaxGet(URL2);
}),然后(功能(结果2){
    //做什么结果2
    返回ajaxGet(URL3);
}),然后(功能(结果3){
    //过程最终在这里结果3
    //现在载入两幅图片,并在加载时做一些东西展示
    返回Promise.all(的LoadImage(IMGX)的LoadImage(IMGY))。然后(功能(IMGS){
        doSomeDisplayStuff(IMGS);
    });
});

I'm looking for a good design pattern for keeping track of a bunch of different asynchronous JavaScript activities (images loading, multiple AJAX calls, sequenced AJAX calls, etc…) that's better than just a lot of custom callbacks and custom state variables. What would you suggest I use? Is there any type of queue system with the ability to have logic beyond just sequencing?

Example Problem

I have a startup sequence that involves a number of asynchronous processes (loading images, waiting for timers, making some ajax calls, doing some initialization). Some of the asynch processes can be launched to run at the same time (loading of images, AJAX calls) and some have to be sequenced (run AJAX call #1, then AJAX call #2). Right now, I've got everything running off callback functions and a bunch of global state that keeps track of what has or hasn't completed. It works, but it's quite messy and I've had a few bugs because of the complication of making sure you handle all the sequencing possibilities right and error conditions.

When you have problems, it's also quite a pain to debug because it's like the Heisenberg uncertainty principle. As soon as you set a breakpoint anywhere in the sequence, everything changes. You have to put all sorts of debugging statements in the code to try to discern what's happening.

Here's a more specific description:

  1. There are three images loading. As soon as one specific image is loaded, I want to display it. Once it's been displayed for a certain amount of time, I want to display the second image. The third one goes in a queue for later display.

  2. There are three AJAX calls that must happen in consecutive order (the output of one is used as part of the input of the next).

  3. When the AJAX calls are done, there's a bunch of JS processing of the results to do and then two more images need to get loaded.

  4. When those two images are loaded, there's some more display stuff to do.

  5. When all that is done, you examine how long one of the images has been displayed and if enough time has passed, display the next image. If not, wait some more time before displaying the next image.

Each step has both success and error handlers. Some of the error handlers kick off alternate code that can still continue successfully.

I don't expect anyone to follow the exact process here, but just to give folks an idea of the type of logic between the steps.

Edit: I came across YUI's AsyncQueue which isn't a complete solution for the type of problem I have, but is in the same space. It seems to be more for sequencing or ordering a bunch of async operations, but I don't see how it helps with the type of decision making I have.

解决方案

With promises now standard in ES6 and many good promise libraries extending that for both new features and backwards compatibility, it seems that promises are the way to go here.

The solution starts with taking each async operation and creating a wrapper that returns a promise:

For loading an image:

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;
    });
}

For making an Ajax call (simplified version):

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();
    });
}

For waiting a particular amount of time before executing an operation, you can even making a promise version of setTimeout() so it can be chained with other promise operations:

// delay, return a promise
// val is optional
function delay(t, val) {
    return new Promise(function(resolve) {
        setTimeout(function() {
            resolve(val);
        }, t);
    });
}

Now, these can be combined to create the logic the question asked for:

There are three images loading. As soon as one specific image is loaded, I want to display it. Once it's been displayed for a certain amount of time, I want to display the second image. The third one goes in a queue for later display.

// 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());

This use of .reduce() shows a classic design pattern for sequencing a series of operations on an array using promises.

There are three AJAX calls that must happen in consecutive order (the output of one is used as part of the input of the next).

and

When the AJAX calls are done, there's a bunch of JS processing of the results to do and then two more images need to get loaded.

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);
    });
});

这篇关于用于管理多个异步的JavaScript操作设计模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆