Dojo 1.7 如何在 require() 之外使用 dojo 组件

Posted

技术标签:

【中文标题】Dojo 1.7 如何在 require() 之外使用 dojo 组件【英文标题】:Dojo 1.7 how to use dojo components outside of require() 【发布时间】: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()' 回调函数的执行。

我的问题是,

    如何阻止“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 环境的必要引用的函数),然后我可以在其中执行我的代码,其中包含我需要的所有引用。跨度> 【参考方案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/

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

    ContentPane 一个id 并通过dijit 的registry.byId() 获取它的引用。

    在单独的模块中创建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 函数中出来的。

以上是关于Dojo 1.7 如何在 require() 之外使用 dojo 组件的主要内容,如果未能解决你的问题,请参考以下文章

Dojo 1.7 Ajax 内容和 AMD 要求

如何将自定义图像添加到按钮 (dojo 1.7)

如何将自定义图像添加到按钮(dojo 1.7)

dojo 1.7 AMD 框架有啥好处?

使用 Dojo 的 require.trace 跟踪整体加载进度

AMD 和 Dojo 1.7 问题