Dojo最佳实践-如何防止浏览器内存泄漏

对于浏览器端,尤其是 Internet Explorer 的内存泄漏问题及解决方法,已经有很深入和广泛的讨论。而本文将更多的讲解作为一个 Dojo 开发人员,如何正确使用 Dojo 的相关技术,遵循 Dojo 的编程模式来避免浏览器的内存泄露问题。

Ajax 应用新的挑战

Ajax 技术已经被广泛的应用,其给 Web 用户带来全新的使用体验同时,也给 Web 开发人员带来了各种各样新的挑战。Ajax 应用中浏览器端内存泄露问题便是其中之一。作为一名 Web 前端开发人员,如果某天系统测试人员给您开了一个名为“浏览器端内存泄露问题”的 Bug, 千万别感到意外,因为您正处在 web2.0 时代。

Internet Explorer 和 Mozilla Firefox 是使用人数最多的两个网页浏览器,因而我们主要讨论 JavaScript 在这两个浏览器中的内存泄露问题。在这两个浏览器中,用来管理 DOM 对象的组件对象模型(component object model)是导致 JavaScript 内存泄露的罪魁祸首。不管是原生的 Windows COM,还是 Mozilla 的 XPCOM 都使用引用计数(reference-counting)垃圾回收机制来分配和回收内存。然而用来管理 DOM 对象内存的引用计数机制并不总是和应用于 JavaScript 的标志和清除(mark-and-sweep)垃圾回收机制相兼容。问题便由此而来。

关于 JavaScript 内存泄露模式以及如何避免内存泄露,已经有很多经典参考资料(参见本文后面的参考资源)。但是由于 Dojo 工具集对于 JavaScript 所做的封装,使得这些资料对于 Dojo 开发人员,却并不很实用。而本文将关注于如何正确使用 Dojo 的相关技术,遵循 Dojo 的编程模式来避免浏览器的内存泄露问题,主要涉及到:

如何正确使用 Dojo 事件机制来避免内存泄露 如何正确使用 Dojo API 来销毁 DOM 节点 如何正确析构 Dojo 小部件(Widget)来避免内存泄露 如何正确使用 dojo.create API 来避免内存泄露 如何更好地设计 UI 代码来避免内存泄露

文中将辅以我们在软件开发中遇到的真实案例,来讲解如何使用这些编程模式来避免内存泄露问题。

Dojo 事件机制与避免内存泄漏

在 JavaScript 编程中,我们经常会用一个 JavaScript 函数来响应并处理某个 DOM 节点的特定事件。而这恰恰也是最容易引入循环引用(circular references)而最终导致内存泄露的地方。在 Dojo 中,其实我们只要按照一定的编程模式,便能很好地避免循环引用带来的问题。

Dojo 事件机制提供的 dojo.connect API 能够让我们方便地把一个 JavaScript 函数关联上某个 DOM 节点事件。Dojo 事件机制对这一操作过程的包装,让我们能够非常容易地处理这种关联所带来的循环引用。

清单 1. 使用 dojo.connect API

// 关联一个 JavaScript 函数与一个 DOM 节点事件 var myConnection = dojo.connect(domNode, "onclick", scope, "onClickHandler");

在清单 1 中通过使用 dojo.connect API ,我们用 onClickHandler 函数来响应并处理 domNode 节点抛出的 onclick 事件。在 dojo.connect 执行完之后,它将返回一个值,代表刚关联的 JavaScript 函数与 DOM 节点事件之间的联系,我们称之为“连接”(connection)。而该“连接”正是消除循环引用的关键!方法很简单,当该“连接”不需要的时候,比如被关联的 DOM 节点被销毁的时候,通过使用 dojo.disconnect API 来断开该“连接”。这样,被关联的 JavaScript 对象与 DOM 节点之间的循环引用就被断开了。也就避免一个潜在的内存泄露问题。dojo.disconnect API 使用方法见清单 2。

清单 2. 使用 dojo.disconnect API

// 在必要的时候断开“连接” dojo.disconnect(myConnection);

在开发 Dojo 小部件的时候,我们也需要消除 DOM 节点与 JavaScript 函数关联带来的循环引用问题,只是方法稍有不同。在小部件开发中,可以使用小部件基类 dijit._Widget 提供的 connect 方法来关联 JavaScript 方法和 DOM 节点事件。相比使用 dojo.connect, 使用基类 dijit._Widget 提供的 connect 方法会让我们的代码更简洁。我们并不需要关心用 connect 之后生成的“连接”(connections)以及何时断开它们。基类 dijit._Widget 提供的 connect 方法会把生成的“连接”自动存储起来。当小部件被销毁时,这些存储的“连接”也会连同一起被自动销毁(参考“Dojo 小部件析构与避免内存泄漏”小节图 1 中小部件销毁过程中的 disconnect 阶段)。很明显,这样的使用方式,让我们的代码显得更加简洁与容易维护。

清单 3.使用 dijit._Widget 基类的 connect 方法

// 在小部件开发中关联 JavaScript 函数与 DOM 事件 this.connect(domNode, "onclick", "onClickHandler");

熟悉 Dojo 小部件开发的读者可能会想到小部件开发中另外一种通过模板技术关联 JavaScript 函数与 DOM 节点事件的方式,使用小部件模板中的 dojoAttachEvent 属性。那么,使用该技术的话,我们是否需要手工处理“连接”呢?和使用 dijit._Widget 基类的 connect 方法一样,答案是不需要!对于在小部件模板中使用 dojoAttachEvent 属性的方式,Dojo 也会帮我们自动处理产生的“连接”,不需要我们再写任何额外的代码。

清单 4. 使用小部件模板技术中的 dojoAttachEvent 属性

// 小部件模板文件片段… <div class="close" dojoAttachEvent="onclick:closeHelpBox">X </div> … // 小部件 JavaScript 定义文件片段 closeHelpBox: function(event) { this.destroy(); } …

对于非小部件开发的情况,我们必须使用 dojo.connect API,并手动地使用 dojo.disconnect API 处理“连接”。一种比较好的模式是定义一个帮助方法用来注册特定上下文内生成的所有“连接”,当该上下文结束时一并切断注册的所有“连接”。参考清单 5 中代码。

清单 5. 非小部件开发情况,使用 dojo.connect API 的编程模式

// 定义帮助方法 connectionHelper = { scopes:{}, connect : function(/*string*/ scope, /*Object|null*/ obj, /*String*/ event, /*Object|null*/ context, /*String|Function*/ method){ var conn = dojo.connect(obj, event, context, method); if(!this.scopes[scope]){ this.scopes[scope] = []; } this.scopes[scope].push(conn); return conn; }, clear: function(/*string*/ scope){ if(this.scopes[scope]){ dojo.forEach(this.scopes[scope], dojo.disconnect) } } }

时间: 2024-09-13 08:17:54

Dojo最佳实践-如何防止浏览器内存泄漏的相关文章

纠结的IE浏览器内存泄漏的测试

在编写代码高亮脚本的时候,问了瓶子一个问题,就是在循环里处理删除DOM元素的时候,会动态改变NodeList的length,所以测试许久, 最后发现是这个问题,狂晕.但是期间谈到了一个关于removeChild的时候在IE下无法回收内存的泄漏问题,他展示了一个EXT里针对IE使用的方 法: var div=document.getElementById("div"); var first=div.firstChild,next=first; while(next){ var d=doc

Dojo最佳实践

传统 Web 应用程序可以非常好的支持浏览器的书签收藏以及前进后退按钮.而在基于 Ajax 的 Web 应用中,页面的内容刷新往往是通过异步请求的方式动态局部刷新,而不会重新请求一个页面,因而页面对应的 URL 并不会变化,前进后退按钮也不会起任何作用.这样就导致在这类 Ajax 应用中无法通过书签来记录特定的视图.本文将首先介绍通用的基于超链接锚点的可书签化的 Ajax 应用的编程模式,然后以该编程模式的分析与设计为基础并结合实例来说明如何应用 Dojo 提供的 Dojo.back 技术来实现

.NET内存管理的最佳实践

问题描述 我们在实际编程中使用的内存往往都会超出程序需要的内存,对于桌面应用程序内存是相对廉价的,但如果你在开发ASP.NET应用程序,需要处理服务器上大量的内存时,过度使用内存可能会带来很多痛苦,因此有必要讨论一下.NET内存管理的最佳实践,以减少内存浪费. 程序员在为类中的成员变量获取内存时往往有些多余的行为,因为有些不必要的内存使用会浪费掉一些内存空间,我们来看一段代码: publicclassBadUse { privateSqlConnectioncon=newSqlConnectio

找出并解决 JavaScript 和 Dojo 引起的浏览器内存泄露问题

简介: 如果大量使用 JavaScript 和 Ajax 技术开发 Web 2.0 应用程序,您很有可能会遇到浏览器的内存泄漏问题.如果您有一个单页应用程序或者一个页面要处理很多 UI 操作,问题可能比较严重.在本文中,学习如何使用 sIEve 工具检测并解决内存泄漏问题,本文也包含内存泄漏问题的应用示例以及解决方案. 发布日期: 2012 年 4 月 09 日 级别: 中级 原创语言: 英文 访问情况 : 10932 次浏览 评论: 0 (查看 | 添加评论 - 登录)  平均分 (7个评分)

使用Dojo的Ajax应用开发进阶教程,第8部分: Dijit开发最佳实践

Dijit 组件(widget)是 Dojo 提供的图形用户界面组件库.它提供了 Ajax 应用开发中会用到的常用组件,可以帮助开发人员快速的构建 Ajax 应用.本文并不会介绍 Dojo 默认提供的组件,而是侧重于介绍 Dijit 组件的编程模型和最佳实践,其目的是帮助开发人员更好的开发自己的 Dijit 组件.下面首先对 Dijit 做概要介绍. Dijit 概述 Dijit 组件的存在是 Dojo 框架区别于其它 JavaScript 框架的一个重要特性.在桌面应用开发中,开发人员大量使用

[翻译] Facebook 的 iOS 内存泄漏监测自动化实践

原文链接 [需翻墙]:Automatic memory leak detection on iOS 内存是移动设备上的共享资源,如果一个 App 无法正确地进行内存管理的话,将会导致内存消耗殆尽,闪退以及性能的严重下降. Facebook 的 iOS 版本的许多功能模块共用了同一份内存空间,如果其中的某一个模块消耗了特别多的内存资源的话,将会对整个 App 造成严重影响.举个栗子,当某个功能模块不小心造成了内存泄漏的时候,这个情况就很有可能会发生. 在 Facebook,我们有非常多的工程师同时

Web前端优化最佳实践之JavaScript篇

Web 前端优化最佳实践之 JavaScript 篇,这部分有 6 条规则,和 CSS 篇 重复的有几条.前端优化最佳实践,最重要的还是"实践",要理解这东西容易得很,关键是要去"实践",去"执行",去"反馈",去获取受益. 1. 脚本放到 HTML 代码页底部 (Put Scripts at the Bottom) 当一个脚本在下载的时候,浏览器干不了其它的事儿(串行了).所以,把它扔到最后面去处理.对于一些功能性的脚本,可

解析Web缓存及其最佳实践

背景说明 缓存一直是前端性能优化中,浓墨重彩的一笔.了解前端缓存是打造高性能网站的必要知识. 之前,对于缓存的认知一直停留在看<HTTP权威指南>和一些相关帖子的深度,过了一段时间,又总是忘记,正好最近不是很忙,结合内网上的一些参考资料,结合实践,试着全面解析一下缓存以及其最佳实践. 前后端交互中涉及到的缓存 前端 我们日常所见最多的也是我们最常利用的就是浏览器对于HTTP规范实现所进行的资源缓存,HTTP规范中,定义了4个缓存相关的字段. 对HTTP感兴趣的同学也可以看我对<HTTP权

深入理解JavaScript程序中内存泄漏_javascript技巧

垃圾回收解放了我们,它让我们可将精力集中在应用程序逻辑(而不是内存管理)上.但是,垃圾收集并不神奇.了解它的工作原理,以及如何使它保留本应在很久以前释放的内存,就可以实现更快更可靠的应用程序.在本文中,学习一种定位 JavaScript 应用程序中内存泄漏的系统方法.几种常见的泄漏模式,以及解决这些泄漏的适当方法. 一.简介 当处理 JavaScript 这样的脚本语言时,很容易忘记每个对象.类.字符串.数字和方法都需要分配和保留内存.语言和运行时的垃圾回收器隐藏了内存分配和释放的具体细节. 许