• 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/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>
    

      

  • 相关阅读:
    (转)nginx的root和alias指令的区别
    (转)Bash 快捷键 完整版
    (转)curl 命令使用
    Ansible 部署
    (转)把Sublime Text 2 加入右键菜单(带图标),Edit with Sublime Text
    配置IP地址及HOSTNAME脚本
    Linux Shell : Test命令参数解析
    计算阶乘 n! = 1 * 2 * 3 * ... * n
    .编写一个函数,输入n为偶数时,调用函数求1/2+】1/4+...+1/n,当输入n为奇数时,调用函数1/1+1/3+...+1/n
    简单的ATM机的取款过程
  • 原文地址:https://www.cnblogs.com/malaikuangren/p/3754948.html
Copyright © 2020-2023  润新知