【JS】关于JSONP的两点疑问
昨天去面试阿里前端开发的实习招聘,面试官问了我两个关于JSONP的两个问题,表示平时用的时候没有怎么去思考。
问题一:JSONP是需要动态创建script标签的,我们需不需要处理这些script元素?怎么处理? 我回答的是需要,然后回答了需要去移除script标签。面试官接着问:这样处理有没有什么副作用?没答上来;
问题二:JSONP请求的时候,服务器发生错误该怎么办,比如服务器崩掉,比如返回了404页面,前端该怎么处理这个错误,难道直接让它抛出么?又没答上来。
回来google了一下,第一个问题关于JSONP产生的动态JS的处理:只清除script标签是不够的,需要手动去清除这段JS占用的内存;第二个问题关于JSONP的服务器错误处理:查到的结果是JSONP不提供错误处理。
但是对自己查到的结果还是不够满意,希望大神可以指点一下,第一个问题产生副作用的原因、怎么去手动清除这些动态JS占用的内存以及第二个问题的解答,谢谢!
回答
这两问题,建议楼主去看看jQuery、yui、kissy等框架/库的源码!
我主要想谈谈第一个问题。
jsonp动态创建的节点确实是需要删除的。
目前市面上不同的框架/库,它们的处理方法是不一样的,主要有两种:
- onload/complete时,删除节点,比如jQuery
- 暂不删除节点,积累到一定数目时才删除,比如yui(不知道为啥要这么干)
jsonp创建script节点后,通常还会挂上onload、onreadystatechagne、onerror等事件(如果支持这些事件的话),面试者可能想考的就是在删除节点后怎么处理这些事件等。
还有一个需要考虑的就是,很多框架/库在实现jsonp时,一般都会生成一个uuid,比如jQuery19109801354627124965_1398582826844
,然后将它挂载到window上,用以包装用户的callback,比如:
window['jQuery19109801354627124965_1398582826844'] = function() { // ...
callback();
// ...
}
这些挂载到window上的callback也是需要释放的。
至于删除节点后,还需不需要删除属性?我认为是不需要的,虽然一个for-in
可以搞定一切,包括事件也删除了。
1楼所说的script标签删除,元素的属性还是可以取到的?没错,是可以取到,怎么取的?
function x(id) { var script = document.getElementById(id)
document.head.removeChild(script);
console.log(script.src);
;}
这样获取的话,肯定是能拿到的,因为此刻script确实还没释放!什么时候释放?至少也得函数x执行完后吧(实际的释放时机可能比这个还晚,函数执行完不一定立马触发gc)!
实际上,gc一般会发生在unload、inactive tab或者产生了太多垃圾不得不gc时。
而gc发生时,以上面的x
函数为例,只要x
函数中的script变量没有引用计数,它将会被回收。
一旦释放,内存就回归正常,不存在memory leak!
测试代码:gist
打开chrome timeline面板,切换到memory选项上,点击record开始记录,在console上运行loop
方法,观察memory图形变化,同时注意record上的gc event
(把chrome dev tool往上拉长一点就可以同时看到memory图形、records以及下方的counters),过一段时间后,可能你的图形会是这样:
注意到图中的两个箭头,内存以及dom node count为什么在线性增加中?可能有的人看到这里就惊呼,这不就是内存泄露吗?但请注意在这段时间内并没有gc(观察中间的RECORDS),所以内存增加是正常的。(每次调用一个函数都会增加一定的内存,除非gc了,才能释放这些内存,请看这里)。
这个时候,如果我手工点击chrome开发工具的gc按钮,强制gc,结果会是这样:
可以看到,内存立马释放了,如果你把顶部的时间轴选定在陡峰之后:
如上图红框所示,DOM Node count也下降到初始值16了!
结论:不是没释放,而是时候未到!!!
真正memory leak的情况?
pattern 1:没有删除节点,并且dom节点与js对象存在循环引用!
function leak() { var script = document.createElement('script');
var id = script.id = (+new Date).toString(36);
document.head.appendChild(script);
// 循环引用
document.getElementById(id).expando = script;
// leak case
script.bigString = new Array(10000).join("xxxx");
}
setInterval(leak, 1000);
在chrome上试一下以上代码,record一两分钟之后,手工点一下chrome的gc按钮,停止record。
这种情况是时候到了,却gc不了!!!这才是真正的内存泄露!
没想到看到校友了
JSONP我用到的也不多,我挑我知道的说吧。
1.清除标签后浏览器仅仅是移除这个节点而已,并没有对节点内的JS进行垃圾回收。你可以测试一下,即使script标签移除了,元素的属性还是可以取到的,比如src
属性。要回收这段JS可以手动清除script元素所有属性:
var jsonp = document.getElementById('myJson'); //取得script元素for (var prop in jsonp) {
delete jsonp[prop];
}
2.这个我也没什么把握,在JSONP的返回中嵌入状态码,前端根据状态码判断成功或失败然后调用不同的回调函数。还有比如用jquery的话,用$.getJSON()
或$.ajax()
方法在发生错误时可以用error
回调函数来捕获错误,前端对用户进行提示。另一个方法,设定一段延时,超过设定时间无响应的话提示用户稍后重试等等。
以上是 【JS】关于JSONP的两点疑问 的全部内容, 来源链接: utcz.com/a/82586.html