我需要在JavaScript / jQuery中执行几个功能,但我想避免阻塞UI。
AJAX不是一个可行的解决方案,由于应用程序的性质,这些功能很容易达到数千种。异步执行此操作将终止浏览器。
因此,我需要某种方式链接浏览器需要处理的功能,并且仅在第一个功能完成后才发送下一个功能。
该算法是这样的
适用于2到15步 HTTP:获取当前步骤的项目数量(范围从几百到几千) 对于每个项目,HTTP:获取结果
适用于2到15步
HTTP:获取当前步骤的项目数量(范围从几百到几千) 对于每个项目,HTTP:获取结果
HTTP:获取当前步骤的项目数量(范围从几百到几千)
对于每个项目,HTTP:获取结果
如您所见,我有两个我需要管理的GET-request-“ chains” …特别是最内层的循环,如果异步完成的话,会使浏览器立即崩溃- 但我仍然希望用户能够操作页面,因此纯(阻塞)同步方式将不起作用。
您可以轻松地异步执行此操作,而无需一次触发所有请求。您需要做的就是管理队列。为了清楚起见,以下是伪代码。它很容易转换为真实的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与pop)处理请求。但是,您也可以使用splice将内容添加到队列的中间,或者使用unshift vs push将请求放置在队列的开头以处理高优先级的请求。
您还可以通过在每个循环中弹出多个请求来增加同时请求的数量。只需确保process_request_queue每个循环仅调用一次即可避免同时请求呈指数增长:
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" } } }