昨天去面试阿里前端开发的实习招聘,面试官问了我两个关于JSONP的两个问题,表示平时用的时候没有怎么去思考。
问题一:JSONP是需要动态创建script标签的,我们需不需要处理这些script元素?怎么处理? 我回答的是需要,然后回答了需要去移除script标签。面试官接着问:这样处理有没有什么副作用?没答上来;
问题二:JSONP请求的时候,服务器发生错误该怎么办,比如服务器崩掉,比如返回了404页面,前端该怎么处理这个错误,难道直接让它抛出么?又没答上来。
回来google了一下,第一个问题关于JSONP产生的动态JS的处理:只清除script标签是不够的,需要手动去清除这段JS占用的内存;第二个问题关于JSONP的服务器错误处理:查到的结果是JSONP不提供错误处理。
但是对自己查到的结果还是不够满意,希望大神可以指点一下,第一个问题产生副作用的原因、怎么去手动清除这些动态JS占用的内存以及第二个问题的解答,谢谢!
这两问题,建议楼主去看看jQuery、yui、kissy等框架/库的源码!
我主要想谈谈第一个问题。
jsonp动态创建的节点确实是需要删除的。
目前市面上不同的框架/库,它们的处理方法是不一样的,主要有两种:
jsonp创建script节点后,通常还会挂上onload、onreadystatechagne、onerror等事件(如果支持这些事件的话),面试者可能想考的就是在删除节点后怎么处理这些事件等。
还有一个需要考虑的就是,很多框架/库在实现jsonp时,一般都会生成一个uuid,比如
jQuery19109801354627124965_1398582826844
,然后将它挂载到window上,用以包装用户的callback,比如:这些挂载到window上的callback也是需要释放的。
至于删除节点后,还需不需要删除属性?我认为是不需要的,虽然一个
for-in
可以搞定一切,包括事件也删除了。1楼所说的script标签删除,元素的属性还是可以取到的?没错,是可以取到,怎么取的?
这样获取的话,肯定是能拿到的,因为此刻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对象存在循环引用!
在chrome上试一下以上代码,record一两分钟之后,手工点一下chrome的gc按钮,停止record。
这种情况是时候到了,却gc不了!!!这才是真正的内存泄露!