Using dijit/Destroyable to build safe Components
In today's long-lived JavaScript apps it is essential to not introduce memory leaks within your custom components. Dojo Toolkit to the rescue: The dijit/Destroyable module addresses this problem and makes it really easy to track the various handles of an instance. Various components such as dojo/aspect, dojo/topic, dojo/on, dojo/Stateful and dojo/store/Observable return a handle which can be passed to dijit/Destroyable's own() method. The application must then call destroy() on the instance in order to release the handles.
Here's an example demonstrating the tracking of some handles and how to have them removed at the end of the components lifecycle:
Our layout
+ source.html
+ mylib
+ app.js
+ ChildWidget.js
+ MainWidget.js
+ templates
+ MainWidget.html
MainWidget.js
This is the main widget which makes use of events, aspects, topics etc. It tracks all its handles by passing them to own():
define([
"dojo/_base/declare",
"dijit/_WidgetBase",
"dijit/_TemplatedMixin",
"dojo/aspect",
"dojo/topic",
"dojo/on",
"dojo/Stateful",
"dojo/store/Memory",
"dojo/store/Observable",
"./ChildWidget",
"dojo/text!./templates/MainWidget.html"
], function (
declare,
WidgetBase,
TemplatedMixin,
aspect,
topic,
on,
Stateful,
Memory,
Observable,
ChildWidget,
template
) {
return declare([WidgetBase, TemplatedMixin], { templateString: template, // constructor args
timeout: null,
leaky: false, postCreate: function () {
this.setChildWidget();
this.setAspect();
this.setEvent();
this.setSubscription();
this.setStateful();
this.setObservable();
}, setChildWidget: function () {
var widget = new ChildWidget({ timeout: this.timeout }); if(!this.leaky) {
// register widget.destroy() to be called when this widget is destroyed
this.own(widget);
}
}, setAspect: function () {
var someObject = {
someMethod: function () {}
}, signal = aspect.after(someObject, 'someMethod', function () {
console.warn('aspect.after');
}); if(!this.leaky) {
// register signal.remove() to be called when this widget is destroyed
this.own(signal);
} // call someObject.someMethod() after this widget has been destroyed
setTimeout(function() {
someObject.someMethod();
}, this.timeout);
}, setEvent: function () {
var handle = on(this.clickableNode, 'click', function (ev) {
console.warn('on');
}); if(!this.leaky) {
// register handle.remove() to be called when this widget is destroyed
this.own(handle);
}
}, setSubscription: function () {
var subscription = topic.subscribe('some-topic', function (data) {
console.warn('topic.subscribe');
}); if(!this.leaky) {
// register subscription.remove() to be called when this widget is destroyed
this.own(subscription);
} // publish a topic after this widget has been destroyed
setTimeout(function() {
topic.publish('some-topic', {});
}, this.timeout);
}, setStateful: function () {
var stateful = new Stateful({ a: 'aaa' }), handle = stateful.watch('a', function (name, oldVal, newVal) {
console.warn('Stateful');
}); if(!this.leaky) {
// register handle.remove() to be called when this widget is destroyed (handle.unwatch() is deprecated)
this.own(handle);
} // modify a property after this widget has been destroyed
setTimeout(function() {
stateful.set('a', 'AAA');
}, this.timeout);
}, setObservable: function () {
var store = Observable(new Memory({
data: [{ id: 0, a: 'aaa' }]
})), result = store.query(), observer = result.observe(function (item, removedIndex, insertedIndex) {
console.warn('Observable');
}, true); if(!this.leaky) {
// register observer.remove() to be called when this widget is destroyed (observer.cancel() is deprecated)
this.own(observer);
} // add an item after this widget has been destroyed
setTimeout(function() {
store.put({ id: 1, b: 'bbb' });
}, this.timeout);
}
});
});
ChildWidget.js
A widget without DOM representation:
define([
"dojo/_base/declare",
"dijit/_WidgetBase"
], function (
declare,
WidgetBase
) {
return declare([WidgetBase], { timeoutId: null, // constructor args
timeout: null, postCreate: function () {
this.timeoutId = setTimeout(function () {
console.warn('child widget');
}, this.timeout);
}, destroy: function () {//alert('destroy')
this.inherited(arguments);
clearTimeout(this.timeoutId);
}
});
});
app.js
The entry point into the application:
define([
"./MainWidget",
"dojo/domReady!"
], function (MainWidget) { var timeout = 3000, widget = new MainWidget({
timeout: timeout,
leaky: false // this is just to demonstrate the behaviour of a leaky widget
}, 'widget'); widget.startup(); setTimeout(function () {
widget.destroy(true);
console.info('Widget is now destroyed while preserving the dom')
}, timeout - 1000); // destroy widget one second before the various potentially leaky handles in the widget are executed
});
source.html
... and finally the HTML page to bootstrap our application:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Destroyable</title>
<script>
var dojoConfig = {
async: true,
cacheBust: 1,
packages: [
{ name: 'mylib', location: 'path/to/mylib' } // relative to dojo/dojo.js
]
};
console.log('SOURCE');
</script> <script src="path/to/dojo/dojo.js"></script><!-- relative to this document --> <script>
require(['mylib/app']);
</script>
</head>
<body>
<div class="document">
<div id="widget"></div>
</div>
</body>
</html>
Using dijit/Destroyable to build safe Components的更多相关文章
- [Recompose] Configure Recompose to Build React Components from RxJS Streams
Recompose provides helper functions to stream props using an Observable library of your choice into ...
- 5、二、App Components(应用程序组件):0、概述
二.App Components(应用程序组件) 0.概述 App Components Android's application framework lets you create rich ...
- Open Harmony移植:build lite配置目录全梳理
摘要:本文主要介绍build lite 轻量级编译构建系统涉及的配置目录的用途,分析相关的源代码. 本文分享自华为云社区<移植案例与原理 - build lite配置目录全梳理>,作者:z ...
- 转:分享13款PHP开发框架
文章来自于:http://mashable.com/2014/04/04/php-frameworks-build-applications/ Building software applicatio ...
- 安装MySQL的时候遇到的错误
这里我安装的是MySQL5.6 我遇到的错误有 (1)Warning: Bison executable not found in PATH 解决办法: yum install bison 原文摘自: ...
- REACT day 1
https://facebook.github.io/react/ A JAVASCRIPT LIBRARY FOR BUILDING USER INTERFACES Declarative view ...
- 《静静的dojo》 总体教程介绍
web2.0时代,ajax技术成为整个前端开发领域的基石.大部分的书籍.博客由此切入来介绍前端类库与框架,所以dojo往往只被当做一个ajax类库来介绍,然而仅仅以此来定位dojo,无异于管中窥豹.对 ...
- centos 7.0 编译安装mysql 5.6.22 再次总结 成功编译安装~ 越来越熟练了~
查找php.ini文件所在位置 [root@localhost /]# find -name php.ini ./usr/etc/php/etc/php.ini mysql官网的安装说明http:// ...
- centos6.5环境源码编译安装mysql5.6.34
centos6.5环境源码编译安装mysql5.6.34 源码下载地址http://dev.mysql.com/downloads/mysql/5.6.html#downloads 选择Generic ...
随机推荐
- Selenium ide录制回放错误Timed out after 30000ms
[error] Timed out after 30000ms 该问题可能是速度控制条播放速度过快导致,调整播放速度至slow
- spring设置全局异常处理器
1.spring设置全局异常,它的原理是向上捕获 spring.xml配置 <!--自定义全局异常处理器--> <bean id="globalExceptionResol ...
- Ant 常用语法及选项
project 项目定义,一个ant文件就是一个 project,定义了项目名称,起始位置以及默认执行的 target. <project name="Easily" bas ...
- 《精通C#》第十七章
进程简单的说就是一个正在运行的程序,包含了运行该程序所需要的一切资源以及内存分配.线程是进程的基本执行单元,在进程的入口点(类似main())创建的第一个线程称之为主线程.只有一个主线程的进程是线程安 ...
- 为什么大家都用i标签<i></i>用作小图标?
用 <i> 元素做图标在语义上是不正确的(虽然看起来像 icon 的缩写): <i> 比 <span> 短,但 gzip 后差异很小,不过打字可以少按三个键: 多数 ...
- MYSQL命令行使用指南
一.连接MYSQL. 格式: mysql -h主机地址 -u用户名 -p用户密码 1.例1:连接到本机上的MYSQL. 首先在打开DOS窗口,然后进入目录 mysqlbin,再键入命令mysql -u ...
- JS学习笔记01
文章转载pigpigpig4587 的 1.Javascript是区分大小写的语言.也就是说.关键字.变量,函数和所有的标识符都必须采取一致的大小写形式.因为html不严格区分大小写,所以在html中 ...
- 解决ViewPager多次刷新后重叠问题
@Override public void destroyItem(ViewGroup container, int position, Object object) { ((ViewPager) c ...
- Strategy pattern策略模式
在Java的集合框架中,经常需要通过构造方法传入一个比较器Comparator,或者创建比较器传入Collections的静态方法中作为方法参数,进行比较排序等,使用的是策略模式. 一.策略模式的定义 ...
- iOS中文网址路径转换URLEncode
如果返回的URL中有中文可以用此方法转换 今天发现一个蛋疼的问题,服务端返回的urlString里面有时含有中文,使用 [NSURL URLWithString:urlString]生成URL对象时, ...