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. cookie多次点赞效果

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...

  2. JavaScript中面向对象的的深拷贝和浅拷贝

    理解深拷贝和浅拷贝之前需要弄懂一些基础概念,内存中存储的变量类型分为值类型和引用类型. 1.值类型赋值的存储特点, 将变量内的数据全部拷贝一份, 存储给新的变量. 例如:var num = 123 : ...

  3. zookeeper学习系列:四、Paxos算法和zookeeper的关系

    一.问题起源 淘宝搜索的博客 http://www.searchtb.com/2011/01/zookeeper-research.html  提到Paxos是zookeeper的灵魂 有一篇文章标题 ...

  4. sql数据库表被锁,无法查询

    查看被锁表:   select   request_session_id   spid,OBJECT_NAME(resource_associated_entity_id) tableName    ...

  5. 学习solr

    1.下载地址 http://apache.opencas.org/lucene/solr/

  6. Spring整合Ehcache管理缓存(转)

    目录 前言 概述 安装 Ehcache的使用 HelloWorld范例 Ehcache基本操作 创建CacheManager 添加缓存 删除缓存 实现基本缓存操作 缓存配置 xml方式 API方式 S ...

  7. Redis设计与实现(一~五整合版)【搬运】

    Redis设计与实现(一~五整合版) by @飘过的小牛 一 前言 项目中用到了redis,但用到的都是最最基本的功能,比如简单的slave机制,数据结构只使用了字符串.但是一直听说redis是一个很 ...

  8. HTML 之 head

    使用 base 标签使页面中的所有标签在新窗口中打开.<!DOCTYPE html> <html> <head> <meta http-equiv=" ...

  9. c++内存对齐

    内存对齐原则: 1.数据成员对齐规则:struct, union的数据成员,第一个数据成员放在offset为0的地方,之后的数据成员的存储起始位置都是放在该数据成员大小的整数倍位置.如在32bit的机 ...

  10. linux 内核学习之五 system_call过程分析

    一   使用gdb工具跟踪分析一个自添加的系统调用 应用程序的进程通常在用户空间下运行,当它调用一个系统调用时,进程进入内核空间,执行的是kernel内部的代码,从而具有执行特权指令的权限,完成特定的 ...