全动态前端页面架构(full ajax)中是如何处理javascript内存泄露问题的?

2013-03-31 13:55:29 +08:00
 breeswish
关于“全动态前端页面架构”可能不是很专业,总之我不知道最专业名词是什么= =

这个名词描述的是这样一种网站: 它的所有页面都是使用ajax加载并进行呈现的 局部刷新应用到了所有页面上

举例: google plus / jsgen

我打算在一个需求多样化并且前端功能比较rich的网站中使用这个技术(比如类似于google+)。


于是在全动态页面架构中 我主要想到了3方面的问题: 加载,内存,资源。以下是详细问题,不知大家有没有什么成熟的方案?

1.
加载上,应当一次性加载所有js呢还是按需加载?如果按需加载的话如何确保不会多次加载(conflict)?

另外加载某个页面时候如何知道它需要哪些js?

2.
内存上,如果是按需加载的话 并且假设js不会重复加载,那么势必随着用户点击页面越来越多,加载并贮存在浏览器中的js也会越来越多(最后内存的占用接近于甚至超过一次性加载解析所有js?) 有没有什么办法可以使得加载新页面时候有效释放上一个页面的js内存占用?

3.
资源泄露。

加载新页面时候不能释放上一个页面引入的js对象是一种内存泄露,然而还有更多可以泄露的,比如setInterval()创建的计时器。

假设页面A创建了一个计时器,然后切换到了页面B,那么这个计时器显然还在工作。如何有效地对这些资源进行综合性托管?(我希望有一种先期预防的模型,类似于一种context sandbox,而不是等到发现有泄露了再修复BUG)

另外还有DOM。假设页面A使用了TinyMCE,用户使用TinyMCE弹了个浮动窗(append in body),然后直接进入了页面B,那么这个Tinymce的浮动窗是不归自己控制的,根本抓不到除非重写。这种由于第三方内容引入的资源不可控怎么办?

最后还有javascript对象的泄露问题,这种内存泄露好像根本无法进行预防?

==========

说一下我自己曾经做的一个架构:

1. 按需加载
加载页面时候先获取要加载哪些js 然后加载之(如果已加载则忽略) 最后加载相关页面。

2. 资源上下文
随着每个页面分配一个资源上下文的对象,存储timer/intervalTimer/野生DOM,在切换页面时候进行资源释放。但是!它提供了托管的接口,却无法直接让所有东西都托管下来: 必须得开发者自己遵循规则使用其接口才行,于是最大的问题就是第三方库这种不遵循规则的怎么办?

可以看到这样一个架构实际上仍然不能从根本上解决资源泄露问题,严重对第三方库的资源泄露敏感。
另外,它也不能释放JS本身占用的内存(只能释放DOM/Timer)。

因此来请教大家,有没有什么好的想法?

(注意 一切问题都是由rich client和动态页面加载产生的)
6687 次点击
所在节点    JavaScript
18 条回复
cj1324
2013-03-31 20:10:38 +08:00
关注~ 这个环境下第三方库的选择应该谨慎
iinterest
2013-03-31 22:55:40 +08:00
OPOA——One Page,One Application
下面的问题好多,好复杂啊,先去洗澡了。。。
breeswish
2013-03-31 23:11:54 +08:00
@cj1324 是的!后来tinymce我干脆丢进一个iframe…
andy12530
2013-04-01 01:07:36 +08:00
我来歪个楼。
这种应该叫 富web应用

加载的话require js seajs之类有加载器,构建无刷新富应用采用backbone 轻量级框架。

每个页面要加载什么 需要开发者定义 也就是依赖。
0x0001
2013-04-01 07:49:10 +08:00
这叫Ria应用
其实真的必须都在一个页面么?不要为了炫技而开发…
用户体验才是重点,必要的跳转没发现什么不妥。

我更担心的日你代码的可读性和维护性
cmonday
2013-04-01 08:04:52 +08:00
都复杂到这个程度了竟然没有引入 requirejs ozjs 或者 seajs 这种依赖管理库么?你的这些问题前人早就遇到过而且解决过了
不可控的第三方库丢进 iframe 是对的,不过你仔细研究一下它的接口的话,我相信大多数时候都是可控的
est
2013-04-01 08:35:49 +08:00
有些内存泄露是浏览器js引擎的bug。你没法解决的。Google的GWT团队跟IE团队多次搞基成功修复了各种诡异bug。
anhulife
2013-04-01 10:00:00 +08:00
我们公司最近在做类似的应用
我们的解决方案是
每个页面、组件都是一个模块,模块之间有依赖关系

1 JS加载 RequireJS 负责加载JS和处理依赖,首先加载的是libs.js和app.all.js,都是些共用的JS,然后把分业务打包JS,按需加载

2 由于使用了RequireJS加载JS,所以不会出现重复加载的场景

3 每个模块都负责管理资源,比如模块里面有setInterval,那在模块销毁的时候,需要销毁setInterval,事件绑定也是这样的,这样能够有效地释放资源

我们使用的库有:
RequireJS jQuery Backbone.js Underscore.js mustache.js Grunt
Frannk
2013-04-01 10:07:23 +08:00
用Backbone常见的内存泄露是视图替换的时候没有删除view(相应的事件绑定),而只是删除了dom
把这个问题克服就够了
NemoAlex
2013-04-01 10:15:50 +08:00
我想,楼主说的是模块化管理代码和变量的问题吧?不是内存泄漏。
看标题我还以为现在写前端的人都要想着检查内存泄漏了...
heroicYang
2013-04-01 10:28:56 +08:00
@Frannk 现在直接使用remove不仅会删除dom也会移除事件绑定
heroicYang
2013-04-01 10:29:57 +08:00
@NemoAlex 呃...为什么觉得写前端就不检查内存泄漏呢?
atom
2013-04-01 12:12:09 +08:00
google有内存泄漏检测工具,https://code.google.com/p/leak-finder-for-javascript/

不过我们用一个比较土但是很实在的方法,每隔15分钟自动刷新一下页面,然后,世界就重新来过了。
Frannk
2013-04-01 13:08:11 +08:00
@heroicYang 好像是的 但是没有泄漏意识的话 就不会经常使用 remove unbind off 之类的方法
我觉得js前端泄露造成的问题不大 不会影响性能 但是事件的绑定管理不好(算是一种leak吧)的话 会对程序产生干扰
breeswish
2013-04-01 20:52:50 +08:00
@Frannk 主要是考虑都在一个页面上加载的话一旦内容较多,多加载几次以后Chrome内存就很高了= = 再下去不科学……(不过也许还没到浏览器自己的gc周期= =)
breeswish
2013-04-01 21:01:43 +08:00
@0x0001 感谢提醒;D 其实原本是为了取得更好的视觉效果 是个实验性分支~
breeswish
2013-04-01 21:03:38 +08:00
@anhulife 谢谢提供参考~我会自己研究一下它们 :)
heroicYang
2013-04-02 10:39:47 +08:00
@anhulife 我们也基本上是这样的技术堆栈!

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/64551

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX