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/aspectdojo/topicdojo/ondojo/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的更多相关文章

  1. [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 ...

  2. 5、二、App Components(应用程序组件):0、概述

    二.App Components(应用程序组件) 0.概述   App Components Android's application framework lets you create rich ...

  3. Open Harmony移植:build lite配置目录全梳理

    摘要:本文主要介绍build lite 轻量级编译构建系统涉及的配置目录的用途,分析相关的源代码. 本文分享自华为云社区<移植案例与原理 - build lite配置目录全梳理>,作者:z ...

  4. 转:分享13款PHP开发框架

    文章来自于:http://mashable.com/2014/04/04/php-frameworks-build-applications/ Building software applicatio ...

  5. 安装MySQL的时候遇到的错误

    这里我安装的是MySQL5.6 我遇到的错误有 (1)Warning: Bison executable not found in PATH 解决办法: yum install bison 原文摘自: ...

  6. REACT day 1

    https://facebook.github.io/react/ A JAVASCRIPT LIBRARY FOR BUILDING USER INTERFACES Declarative view ...

  7. 《静静的dojo》 总体教程介绍

    web2.0时代,ajax技术成为整个前端开发领域的基石.大部分的书籍.博客由此切入来介绍前端类库与框架,所以dojo往往只被当做一个ajax类库来介绍,然而仅仅以此来定位dojo,无异于管中窥豹.对 ...

  8. centos 7.0 编译安装mysql 5.6.22 再次总结 成功编译安装~ 越来越熟练了~

    查找php.ini文件所在位置 [root@localhost /]# find -name php.ini ./usr/etc/php/etc/php.ini mysql官网的安装说明http:// ...

  9. centos6.5环境源码编译安装mysql5.6.34

    centos6.5环境源码编译安装mysql5.6.34 源码下载地址http://dev.mysql.com/downloads/mysql/5.6.html#downloads 选择Generic ...

随机推荐

  1. 重温Javascript第一章

    一.script标签 script标签有6个属性,其中一个废弃,五个可选. 按照传统的写法,<script>的标签都是放在<head>元素中,但是在<head>中包 ...

  2. .NET跨平台之mac 下vs code 多层架构编程

    合肥程序员群:49313181.    合肥实名程序员群:128131462 (不愿透露姓名和信息者勿加入,申请备注填写姓名+技术+工作年限) Q  Q:408365330     E-Mail:eg ...

  3. ActionBar compat 如何禁用ActionBar的显示/隐藏动画

    ActionBar compat 如何关闭ActionBar的显示隐藏动画 @Override public boolean onCreateOptionsMenu(Menu menu) { //消除 ...

  4. 周爱民:真正的架构师是没有title的(图灵访谈)

    周爱民,现任豌豆荚架构师,国内软件开发界资深软件工程师.从1996年起开始涉足商业软件开发,历任部门经理.区域总经理.高级软件工程师.平台架构师等职,有18年的软件开发与架构.项目管理及团队建设经验, ...

  5. Application.Run()和Form.Show()以及Form.ShowDialog()

    ShowDialog()弹出模式化的窗体 Show()弹出非模式化的窗体 模式窗体,在关闭或隐藏前无法切换到主窗体. 非模式窗体,变换焦点使不必关闭窗体 总结:显示重要的信息,还是用模式窗体,如删除文 ...

  6. canvas动画

    1.动画主要是requestAnimationFrame方法,现在我们来一步步实现一个在画布内滚动的实例. html代码: <canvas id="canvas" width ...

  7. !important使用

    IE 6.0一直都不支持这个语法,而其他的浏览器都支持.因此我们就可以利用这一点来分别 给IE和其他浏览器不同的样式定义,例如,我们定义这样一个样式: colortest {border:20px s ...

  8. C++中的字面值指定类型

    C++中只有内置类型存在字面值,没有类(class)类型字面值.例如:0是int类型的字面值,3.14159是double类型的字面值. 字面值类型很多 整型浮点字面值 20             ...

  9. 驱动插ring3线程执行代码

    近日有在写一个小东西 需要在内核态中运行一个WIN32程序 之前提到的插入APC可以满足部分要求 但是一到WIN7 x86平台下就崩溃了WIN7下只能插入第三方的进程 一插入系统进程就崩溃,但是这样满 ...

  10. 如何用python搞定验证码中的噪点

    背景:朋友在为"关山口男子职业技术学校"写一款校园应用,于是找MoonXue写一个学生选课系统的登录接口.为了搞定这个接口,不得不先搞定这个系统的验证码. 验证码大概是这个样子 看 ...