记一次jQuery Ajax并发使用

237 阅读2分钟

背景

最近接手了个老项目,主要用到的技术栈有点老: RequireJS + jQuery。在实现 jQuery Ajax 并发请求数据中遇到了些问题,顺便做下记录。

实现内容

通过 jQuery Ajax 并发请求数据,要保证并发的接口都完成请求(成功或者失败)才能进行下一步。

第一版代码

    var cacheAvatar = {}
    var completeTag = 0;
    for (var j; j < uidList.length; j++) {
        $.ajax({
            url: `//www.baidu.com/u/xxxx/${uidList[j]}`,
            type: 'get',
            dataType: 'json',
            cache: false,
            success: function(res){
                ...
                // 赋值
                cacheAvatar[uidList[j]] = res.data.avatar
            },
            error: function(){
                ...
            },
            complete: function(){
                completeTag++
                if (completeTag === uidList.length) {
                    // 完成所有请求
                }
            }
        })
    }    

第一版代码执行下来,发现接口 urluidList[j]是对的,而 cacheAvatar[uidList[j]]key 却只有一个,并是 uidList 最后一个 item 。想了下 var 没有块级作用域的问题,那就用老的方法:闭包作用域。

第二版代码

    var cacheAvatar = {}
    var completeTag = 0;
    for (var j; j < uidList.length; j++) {
        (function(j){
            $.ajax({
                url: `//www.baidu.com/u/xxxx/${uidList[j]}`,
                type: 'get',
                dataType: 'json',
                cache: false,
                success: function(res){
                    ...
                    // 赋值
                    cacheAvatar[uidList[j]] = res.data.avatar
                },
                error: function(){
                    ...
                },
                complete: function(){
                    completeTag++
                    if (completeTag === uidList.length) {
                        // 完成所有请求
                    }
                }
            })
        })(j)
    }    

第二版代码执行下来, cacheAvatar[uidList[j]] 赋值正常了,但还有别的问题:completeTag 的值多次回调触发都是 1, 没按我们预期的自加,影响了 是否所有请求 的判断。

那如果我们把 completeTag 的值也传入闭包中呢? 答案还是不行的,因为 completeTag 的值是 基本类型, 这时 completeTag 也就是 按值传递, 闭包内部各自拿到只是实参的副本,同时保存在各自的上下文中,对副本修改并不会影响变量 completeTag 自身,所以多个闭包里 completeTag 多次自加只会等于 1

既然知道了原因,那我们就用 按引用传递 的方式来解决,改变 completeTag 值的类型,通过传递对象的引用,实现多个闭包里实际上是对同一个对象的读写。

第三版代码

    var cacheAvatar = {}
    var completeTag = [];
    for (var j; j < uidList.length; j++) {
        (function(j){
            $.ajax({
                url: `//www.baidu.com/u/xxxx/${uidList[j]}`,
                type: 'get',
                dataType: 'json',
                cache: false,
                success: function(res){
                    ...
                    // 赋值
                    cacheAvatar[uidList[j]] = res.data.avatar
                },
                error: function(){
                    ...
                },
                complete: function(){
                    completeTag.push(j)
                    if (completeTag.length === uidList.length) {
                        // 完成所有请求
                    }
                }
            })
        })(j)
    }    

completeTag 变量类型改为 引用类型,这样传入闭包时内部拿到的实际上是completeTag内存地址引用,这样代码如我们预期所执行了。

总结

所谓 ”万变不离其宗“,不管技术栈多老或者五花八门迭代更新,还是不要忽略了基础的学习。