ajax闭包问题及反思
啥话也别说,直接上代码
function subData(){
var pList = [];
//设置成功函数
if(!("success" in defaultAjaxParam)){
defaultAjaxParam.success = (data) => {
if(data.flag){
if ("dataList" in data){
var dataList = data["dataList"];
for (var i=0;i<dataList.length;i++) {
pList.push(dataList[i]);
}
}
}else{
alert(data.msg);
}
}
}
//ajax请求
$.ajax(defaultAjaxParam);
return pList;
}
其中的defaultAjaxParam如下所示
//全局变量
var defaultAjaxParam = {
type:"POST",
url:"con.do",
async:false,
dataType:'json',
data:{},
error: function (data) {
alert("网络连接不稳定");
}
};
$.fn.updataPictureList(options){
...//此处省略代码
//更新ajaxParam
if("ajaxParam" in options){
$.extend(defaultAjaxParam,options.ajaxParam);
}
subData();
}
非常简单的一个ajax返回函数,为了加强其功能性,我又对它初步进行了封装,同时利用全局变量增加了记忆功能
但是问题也随之而来了,使用这个加强版的ajax时,第一次可以正常运行,第二次时返回为空!
我百思而不得其解,使用了前端的调试工具,一行行调试;发现当第二次运行时,ajax.success中的pList和subData中的pList虽然名称一样,但却好像2个值(虽然名称一样,但是修改任意一个,另外一个都没有反应)
第一次调用:
第二次调用:
很明显,第二次调用的还是第一次的变量,导致第二次的返回值直接为空!
其实这个问题非常简单,第二次调用却使用的第一次的变量,没有按照我的要求重新生成,导致了第二次中没法获取第一次的变量
我优先想到的是,这可能是js隐含的坑,于是专门去查了一下,这种在函数内部定义函数并传值的方法叫做闭包;其作用就是能扩大变量的作用域
明白原理了,问题还是要解决,尝试了闭包中的各种解决方案,比如在外层套个匿名函数,将值取出来重新放到其它数组,其中具体的方法我就不赘述了,无非是百度"js 闭包"这样的字符串然后按照上面的文档做罢了
足足6个小时,文章读了十几篇,问题还是没解决
实在翻不动了,休息一会时突然想到:
这个问题综合一下就是上次的变量作用域被扩大多了,直白点就是它在应该生命周期结束时没有结束生命周期;虽然我不知道js引擎是怎么实现闭包的,但是这就是一个GC问题,它不回收,我强行给他回收不就完事了?
于是,果断将它赋值为空,创建一个临时变量做中转将值传递出去.果然,问题搞定
突然有些感慨:学习更底层的技术,就是为了不让别人的代码捆住自己的手脚
但是这只是折中之法,我后面又专门问了大佬,大佬看了5分钟代码,然后和我说:你seccess判断第二次没执行
!?!..(这就是我和大佬的差距吗?QwQ)
原因其实很简单,第一次添加了seccess函数,但是ajaxParam是一个全局参数,第二次调用时检测到有seccess函数,所以就没有添加,导致第二次根本没有形成闭包!
而我的"强制删除"生效的原因是:当js遇到一个变量时,会优先在本地寻找该变量,没找到则去更高层寻找,闭包所形成的变量是在最里层的,js寻找时,会优先使用它;但我把它强制删除后,js在本地找不到同名变量,不得不向上层找
虽然是一个非常简单的问题,但是其中涉及到GC,作用域,闭包等多个方面的问题,所以我就把它写了出来,希望这篇文章能对你解决问题的思路有所启发.
最后,我平时不怎么写文章,所以可能出现词不达意的地方,还请大家多多包涵