【问题标题】:Dojo 1.7 how to use dojo components outside of require()Dojo 1.7 如何在 require() 之外使用 dojo 组件
【发布时间】:2012-05-17 07:13:23
【问题描述】:

我在 Dojo 1.7.2 中使用 AMD 加载器创建了如下所示的 Dojo 小部件

var myCpane;

require([
            "dijit/layout/ContentPane"
        ], function(ContentPane) {
        myCpane = new ContentPane();
});

myCpane.startup();  // It gives 'myCpane' as undefined

在上面的示例中,在最后一条语句中,变量“myCpane”以“未定义”的形式出现,如果我在“require()”回调函数中使用“myCpane.startup()”,它将起作用很好。

但我想在“require”函数之外使用那个“myCpane”变量(出于多种原因)。我知道由于 Dojo 的组件加载过程而延迟了 'require()' 回调函数的执行。

我的问题是,

  1. 如何阻止“require()”函数,直到它完成执行它的回调函数。

所以当控件从'require()'函数出来时,变量'myCpane'不会是'undefined'

================================================ =============

为了克服这个问题,我编写了一个小函数来加载模块并等待模块加载完成

LoadModule: function(modulePath) { // modulePath = "dijit/layout/ContentPane" 
        var moduleObject = undefined; 

        require({async:  false}, [modulePath], function(getModuleObject) { 
                moduleObject = getModuleObject; 
        }); 

        // Wait until the module loads completes 
        while(moduleObject === undefined); 

        // Return the loaded module. 
        return moduleObject; 
} 

函数的输出总是执行while循环,控件永远不会进入'require()的回调函数来设置变量“moduleObject”的值。

什么时候'require()'函数会调用它的回调函数?我已经使用浏览器调试器窗口验证了文件'ContentPane.js'已正确加载,但未调用回调函数,如果我注释while循环,则正确调用回调。

在我的情况下,控件何时会进入回调函数?

【问题讨论】:

  • JavaScript 是单线程的,当异步事件发生时,它会进入 Event Queue。浏览器有内部循环,称为 Event Loop,它检查队列并处理事件、执行函数等 (source)。所以ContentPane.js 已加载,但在LoadModule 函数结束之前不会执行加载程序的回调,这要归功于您的while busy loop 永远不会发生。你应该改变thinking的方式,因为你无法改变JavaScript的工作方式。
  • 这件事也难倒我,因为对我来说,这只是一种不同的思维方式。我接受了我需要了解更多关于 Javascript 的事实。我现在的想法是,我需要创建自己的控制器对象(这是一个接收对 Dojo 环境的必要引用的函数),然后我可以在其中执行我的代码,其中包含我需要的所有引用。跨度>

标签: dojo amd


【解决方案1】:

我不确定你要实现什么,但它看起来像a programming anti-pattern。无论如何,你可以通过dojo/_base/Deferred

require(["dojo/_base/Deferred"], function(Deferred) {

    var deferred = new Deferred();

    require(["dijit/layout/ContentPane"], function(ContentPane) {
        var myCpane = new ContentPane();
        deferred.resolve(myCpane); //resolve, i.e. call `then` callback
    });

    deferred.then(function(myCpane) {
        console.log(myCpane);
        myCpane.startup();
    });

});​    

在 jsFiddle 搞砸它:http://jsfiddle.net/phusick/HYQEd/

我还建议您考虑以下两种策略中的一种来实现相同的效果:

  1. ContentPane 一个id 并通过dijit 的registry.byId() 获取它的引用。
  2. 在单独的模块中创建ContentPane 实例并将其公开为该模块的返回值:

    // file: myCpane.js
    define(["dijit/layout/ContentPane"], function(ContentPane) { 
        var myCpane = new ContentPane();
        return myCpane;
    });
    
    
    // file: main.js
    require(["./myCpane"], function(myCpane) {
        myCpane.startup();
    });
    

【讨论】:

    【解决方案2】:

    我认为这更多的是范围问题而不是 amd 加载程序问题;考虑

    var x;
    function foo() {
      x = { bar : 1 };
    }
    
    // you wouldn't expect to have reference to x variable here
    if(typeof x.bar == "undefined") console.log(x);
    // foo() is called at a random time - or in dojo loader case, when modules are present
    foo();
    console.log(x.bar); // oohh now its there ^^
    

    在这种情况下,x 转换为您的 myCpane,它在函数内声明为变量 (var $$),该函数是加载程序完成时需要模块的回调

    Deferred 是一个很好的处理程序,如下所述。不过,如果您已经在分离(异步)函数流中,那么会产生轻微的开销。为了完全控制,查看 require() 你也可以这样做:

    var myCpane;
    
    require({ async:  false  }, [
                "dijit/layout/ContentPane"
            ], function(ContentPane) {
            myCpane = new ContentPane();
    });
    // require does not return until module loading is done and callback executed
    myCpane.startup();  
    

    【讨论】:

    • { async: false } 不起作用,执行控制只是从 require 函数中出来的。
    猜你喜欢
    • 2012-02-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-14
    • 2013-04-05
    • 1970-01-01
    相关资源
    最近更新 更多