1

我需要在我的 JavaScript/jQuery 中执行几个功能,但我想避免阻塞 UI。

AJAX 不是一个可行的解决方案,因为应用程序的性质,这些功能很容易达到数千个。异步执行此操作将杀死浏览器。

所以,我需要某种方式来链接浏览器需要处理的函数,并且只在第一个函数完成后发送下一个函数。

算法是这样的

对于从 2 到 15 的步骤

HTTP:GET 当前步骤的项目数量(范围从几百到几千)

对于每个项目,HTTP:GET 结果

如您所见,我有两个 GET 请求-“链”我需要以某种方式管理...尤其是最内层的循环使浏览器立即崩溃,如果它是异步完成的-但我仍然希望用户能够操作页面,所以纯(阻塞)同步的方式是行不通的。

4

2 回答 2

4

您可以轻松地异步执行此操作,而无需一次触发所有请求。您需要做的就是管理一个队列。为了清楚起见,以下是伪代码。它很容易转换为真正的 AJAX 请求:

// Basic structure of the request queue. It's a list of objects
// that defines ajax requests:
var request_queue = [{
    url : "some/path",
    callback : function_to_process_the_data
}];

// This function implements the main loop.
// It looks recursive but is not because each function
// call happens in an event handler:
function process_request_queue () {
    // If we have anything in the queue, do an ajax call.
    // Otherwise do nothing and let the loop end.
    if (request_queue.length) {
        // Get one request from the queue. We can either
        // shift or pop depending on weather you prefer
        // depth first or breadth first processing:
        var req = request_queue.pop();
        ajax(req.url,function(result){
            req.callback(result);
            // At the end of the ajax request process
            // the queue again:
            process_request_queue();
        }
    }
}

// Now get the ball rolling:
process_request_queue();

所以基本上我们把 ajax 调用本身变成了一个伪循环。它基本上是递归完成的经典延续传递编程风格。

在您的情况下,请求的一个示例是:

request_queue.push({
    url : "path/to/OUTER/request",
    callback : function (result) {
        // You mentioned that the result of the OUTER request
        // should trigger another round of INNER requests.
        // To do this simply add the INNER requests to the queue:

        request_queue.push({
            url : result.inner_url,
            callback : function_to_handle_inner_request
        });
    }
});

这是非常灵活的,因为您不仅可以选择广度优先或深度优先(shift vs pop)来处理请求。但是您也可以使用 splice 将内容添加到队列的中间,或者使用 unshift 与 push 将请求放在队列的头部以获取高优先级请求。

您还可以通过在每个循环中弹出多个请求来增加同时请求的数量。只需确保process_request_queue每个循环只调用一次,以避免同时请求的指数增长:

// Handling two simultaneous request channels:
function process_request_queue () {
    if (request_queue.length) {
        var req = request_queue.pop();
        ajax(req.url,function(result){
            req.callback(result);
            // Best to loop on the first request.
            // The second request below may never fire
            // if the queue runs out of requests.
            process_request_queue();
        }
    }
    if (request_queue.length) {
        var req = request_queue.pop();
        ajax(req.url,function(result){
            req.callback(result);
            // DON'T CALL process_request_queue here
            // We only want to call it once per "loop"
            // otherwise the "loop" would grow into a "tree"
        }
    }
}
于 2012-11-06T13:25:05.800 回答
1

您可以进行 ASYNC 并使用我前段时间编写的一个小型库,它可以让您对函数调用进行排队。

于 2012-11-06T12:12:16.493 回答