Using dijit/Destroyable to build safe Components
2014-05-27 13:42
369 查看
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
Here's an example demonstrating the tracking of some handles and how to have them removed at the end of the components lifecycle:
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 toown():
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>
相关文章推荐
- [Notes] Demo -- The practice about how to using SAP XI components to build up the mapping bridge cross the application layer
- Error Code: 1175 You are using safe update mode and you tried to update a table without a WHERE that
- Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent
- Using VS2015 64-bit compiler to build up igllib
- Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent
- rror Code: 1175. You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column To disable safe mode, toggle the option in Preferences -> SQL Editor and reconnec
- Failed to Match * of * Components using Unique Identifiers
- Error Code: 1175. You are using safe update mode and you tried to ......
- Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent!
- A year using Ionic to build hybrid applications
- Error Code: 1175 You are using safe update mode and you tried to update a table without a WHERE that
- You are using safe update mode and you tried to update a table without a WHERE that uses a K
- 项目管理实践【五】自动编译和发布网站【Using Visual Studio with Source Control System to build and publish website autom
- 处理MySQL更新表时Error Code: 1175. You are using safe update mode and you tried to update a table……
- On Rapsberry Pi, Using Archlinux to build LNMP, linux, Nginx, MySQL, PHP
- 项目管理实践【五】自动编译和发布网站【Using Visual Studio with Source Control System to build and publish website automatically】
- Using WebSocket to build an interactive web application
- How to build python3.3 using Visual Studio 2012 Ultimate
- Error Code: 1175. You are using safe update mode and you tried to update a table without a WHERE
- Error Code: 1175. You are using safe update mode and you tried to update a table without a WHERE