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

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

问题描述

我正在寻找一种很好的设计模式来跟踪一堆不同的异步 JavaScript 活动(图像加载、多个 AJAX 调用、有序的 AJAX 调用等...),这比很多自定义回调和自定义状态要好变量.你建议我用什么?是否有任何类型的队列系统能够拥有超越排序的逻辑?

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?

我有一个启动序列,它涉及许多异步进程(加载图像、等待计时器、进行一些 ajax 调用、进行一些初始化).一些异步进程可以启动以同时运行(加载图像、AJAX 调用),而一些必须排序(运行 AJAX 调用 #1,然后是 AJAX 调用 #2).现在,我已经让回调函数和一堆全局状态运行起来,以跟踪已完成或未完成的内容.它可以工作,但它非常混乱,并且我遇到了一些错误,因为确保您正确处理所有排序可能性和错误条件很复杂.

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. 加载了三个图像.一旦加载了一个特定的图像,我就想显示它.一旦显示了一定时间,我想显示第二张图像.第三个进入队列以供稍后显示.

  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.

三个 AJAX 调用必须按连续顺序发生(一个的输出用作下一个输入的一部分).

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).

当 AJAX 调用完成后,需要对结果进行一堆 JS 处理,然后需要加载另外两个图像.

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.

加载这两个图像后,还有一些显示内容要做.

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

完成所有操作后,您检查其中一个图像已显示多长时间,如果时间足够长,则显示下一个图像.如果没有,请再等待一段时间,然后再显示下一张图片.

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.

我遇到了 YUI 的 AsyncQueue,它不是针对以下类型的完整解决方案我有问题,但在同一个空间.它似乎更适合对一堆异步操作进行排序或排序,但我看不出它对我的决策类型有何帮助.

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.

推荐答案

promises 现在是 ES6 的标准,并且许多优秀的 Promise 库扩展了新特性和向后兼容性,promises 似乎是通往这里的道路.

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:

用于加载图像:

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 调用(简化版):

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

为了在执行操作之前等待特定的时间,您甚至可以制作 setTimeout() 的承诺版本,以便它可以与其他承诺操作链接:

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

.reduce() 的这种用法展示了一种经典的设计模式,用于使用 Promise 对数组进行一系列操作排序.

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

三个 AJAX 调用必须按连续顺序发生(一个的输出用作下一个输入的一部分).

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).

当 AJAX 调用完成后,需要对结果进行一堆 JS 处理,然后需要加载另外两个图像.

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天全站免登陆