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 ...
随机推荐
- trim(),正则表达式中文匹配
^[/u4E00-/u9FA5]+$ 匹配中文 验证Email地址:“^w+[-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*$” 验证InternetURL:“^http://([ ...
- 每天一个percona 工具 --- pt-kill
主要用途:pt-kill是用来kill MySQL连接的一个工具,在MySQL中因为空闲连接较多导致超过最大连接数,或某个有问题的sql导致mysql负载很高时,需要将其KILL掉来保证服务器正常运行 ...
- ArcGIS操作Excel文件没有注册类解决办法
在ArcGIS Desktop中进行表连接时选择了一张excel表,但添加该表时报错: 原因是机器上缺少Office的数据驱动. ArcGIS 支持 : Excel 2003 以及更早版本的 .xls ...
- MVC5+EF6 入门完整教程六
本篇我们谈谈分部视图(Partial View). 上篇文章提到过Partial和Action这两个helper, 本篇文章主要就结合这两个helper来讲解分部视图(Partial View)的应用 ...
- AJAX(一、基本知识)
AJAX:Asynchronous ([ə'sɪŋkrənəs; eɪ-])Javascript (['dʒɑ:və,skrɪpt])and XML 异步的Javascript和XMLAJAX不是新的 ...
- mysql 5.7配置文件参数详解
read_buffer_size 默认大小:128KB 最大:2GB 最小:8KB 增量:必须为4KB的整数倍,如果配置的不是整数倍,会向下取整 用途: 1.MyISAM表顺序扫描提供的缓存 2.所有 ...
- NetworkComms V3 使用TCP通信传递IList<T>类型的数据
客户端从服务器获取一组IList<T>类型的数据非常常见(通常从数据库中获取) 我们用NeworkComms V3来演示一下(NetworkcommsV2.x版本也同样支持) [ 使用pr ...
- JS数组常用函数以及查找数组中是否有重复元素的三种常用方法
阅读目录: DS01:常用的查找数组中是否有重复元素的三种方法 DS02:常用的JS函数集锦 DS01.常用的查找数组中是否有重复元素的三种方法 1. var ary = new Array(&qu ...
- js中Array的一些扩展
IE下很多Array的方法都不被支持.每次都要写.所以记下来,以免忘记: 以下是对Array的一些扩展,在FF ,google 下是不需要加的. /** * 方法Array.filter(functi ...
- 如何隐藏DOM元素
在CSS中,要隐藏DOM元素常见的方法有: 设置元素的opacity值为0 设置元素的visibility值为hidden 设置元素的display值为none 设置元素的position值为abso ...