本文探讨在 JavaScript 中处理多个异步并发请求的场景,如页面初始化时同时加载多项数据。文章分析了串行化、同步阻塞、计数器回调及轮询等传统方法的局限性,重点介绍了利用 jQuery 的 Deferred 对象配合 $.when() 方法优雅解决多并发回调问题的最佳实践,旨在提升代码可读性与执行效率。
多并发异步请求场景概述
在开发过程中,经常遇到这样的场景:页面初始化时需要显示加载状态,同时发起多个 AJAX 并发请求以获取数据,并在每个请求返回时关闭加载提示。
以订单页面为例,系统需要异步查询常用地址、商品详情及城市信息等多个数据源。业务逻辑要求必须等待所有数据加载完成后,才允许用户进行后续操作。
实现此类场景的核心难点在于如何有效控制多并发请求的执行顺序与状态同步。以下是几种常见的解决思路与具体方法。
传统处理方案及其局限性
方案一:将并行请求改为串行执行
若业务逻辑本身具有严格的先后依赖关系,且当前接口仅支持异步调用,可考虑此方案。然而,在当前场景下,各请求相互独立,串行化会显著降低页面性能,延长用户等待时间,因此并不推荐。
方案二:使用回调函数
该方法仅适用于并发数量较少的情况。随着请求数量增加,多层嵌套的回调函数将导致代码可读性急剧下降,形成所谓的“回调地狱”,难以维护。
function async1(){
//do sth...
}
function async2(){
//do sth...
async1();
}
async2();
方案三:将 AJAX 请求改为同步模式
例如在 jQuery 中,可以通过将 ajax 配置中的 async 参数设置为 false 来实现同步请求。这种方式虽然简单,但会阻塞主线程,影响用户体验,现代开发中已较少使用。
$.ajax({
url:"/jquery/test1.txt",
async:false
});
方案四:设置结束标识(计数器法)
一种较为简单的实现方式是引入计数器。每完成一个异步函数,计数器加 1;或者维护一个数组,每执行完一个异步函数便更新数组状态。当所有标识满足条件时,触发后续逻辑。
方案五:回调计数法
var cnt = 0;
function async1(){
//do sth...
callback();
}
function async2(){
//do sth...
callback();
}
function callback(){
cnt++;
if(2==cnt) console.log('都已执行完毕');
}
方案六:循环阻塞法
var cnt = 0;
function async1(){
//do sth...
cnt++;
}
function async2(){
//do sth...
cnt++;
}
while(2>cnt){}
方案七:循环非阻塞轮询法
上述两种循环方法均不建议过度使用,因为它们会占用浏览器资源,可能影响页面整体性能。
var cnt = 0;
function async1(){
//do sth...
cnt++;
}
function async2(){
//do sth...
cnt++;
}
var interval = setInterval(function(){
if(2===cnt){
console.log('已执行完成');
clearInterval(interval)
}
}
基于 jQuery 的最佳实践
方案八:利用第三方框架实现
jQuery 框架提供了强大的异步处理支持。
目前在实际项目中,笔者更倾向于采用 jQuery 提供的机制来处理此类问题。
var d1 = $.Deferred();
var d2 = $.Deferred();
function async1(){
d1.resolve( "Fish" );
}
function async2(){
d2.resolve( "Pizza" );
}
$.when( d1, d2 ).done(function ( v1, v2 ) {
console.log( v1 + v2 + '已完成');
});
以上内容介绍了 JavaScript 处理多并发异步请求的多种相关知识,希望能为开发者提供有效的参考与帮助。