V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
breeswish
V2EX  ›  JavaScript

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

  •  
  •   breeswish · 2013-03-31 13:55:29 +08:00 via Android · 6675 次点击
    这是一个创建于 4035 天前的主题,其中的信息可能已经有所发展或是发生改变。
    关于“全动态前端页面架构”可能不是很专业,总之我不知道最专业名词是什么= =

    这个名词描述的是这样一种网站: 它的所有页面都是使用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和动态页面加载产生的)
    18 条回复    1970-01-01 08:00:00 +08:00
    cj1324
        1
    cj1324  
       2013-03-31 20:10:38 +08:00
    关注~ 这个环境下第三方库的选择应该谨慎
    iinterest
        2
    iinterest  
       2013-03-31 22:55:40 +08:00
    OPOA——One Page,One Application
    下面的问题好多,好复杂啊,先去洗澡了。。。
    breeswish
        3
    breeswish  
    OP
       2013-03-31 23:11:54 +08:00 via Android
    @cj1324 是的!后来tinymce我干脆丢进一个iframe…
    andy12530
        4
    andy12530  
       2013-04-01 01:07:36 +08:00 via iPhone   ❤️ 1
    我来歪个楼。
    这种应该叫 富web应用

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

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

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

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

    不过我们用一个比较土但是很实在的方法,每隔15分钟自动刷新一下页面,然后,世界就重新来过了。
    Frannk
        14
    Frannk  
       2013-04-01 13:08:11 +08:00   ❤️ 1
    @heroicYang 好像是的 但是没有泄漏意识的话 就不会经常使用 remove unbind off 之类的方法
    我觉得js前端泄露造成的问题不大 不会影响性能 但是事件的绑定管理不好(算是一种leak吧)的话 会对程序产生干扰
    breeswish
        15
    breeswish  
    OP
       2013-04-01 20:52:50 +08:00 via Android
    @Frannk 主要是考虑都在一个页面上加载的话一旦内容较多,多加载几次以后Chrome内存就很高了= = 再下去不科学……(不过也许还没到浏览器自己的gc周期= =)
    breeswish
        16
    breeswish  
    OP
       2013-04-01 21:01:43 +08:00 via Android
    @0x0001 感谢提醒;D 其实原本是为了取得更好的视觉效果 是个实验性分支~
    breeswish
        17
    breeswish  
    OP
       2013-04-01 21:03:38 +08:00 via Android
    @anhulife 谢谢提供参考~我会自己研究一下它们 :)
    heroicYang
        18
    heroicYang  
       2013-04-02 10:39:47 +08:00
    @anhulife 我们也基本上是这样的技术堆栈!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5961 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 02:17 · PVG 10:17 · LAX 19:17 · JFK 22:17
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.