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

3
我使用Dojo 1.7.2中的AMD loader创建了以下Dojo widget。
var myCpane;

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

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

在上面的示例中,在最后一个语句中,变量'myCpane'未定义。如果我在'require()'回调函数内部使用'myCpane.startup()',那么它就能正常工作。
但我想要在'require'函数外部使用该'myCpane'变量(由于许多原因)。我知道'require()'回调函数的执行由于Dojo的组件加载过程而被延迟了。
我的问题是:
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循环,则回调将被正确调用。
在我的情况下,控制何时进入回调函数?

1
JavaScript 是单线程的,当发生异步事件时,它会进入“事件队列”。浏览器有一个内部循环,称为“事件循环”,它检查队列并处理事件、执行函数等(来源)。所以 ContentPane.js 被加载,但是加载器的回调函数在 LoadModule 函数结束之前不会被执行,而由于您的 while “忙碌循环”,这永远不会发生。你应该改变思考方式,因为你无法改变 JavaScript 的工作方式。 - phusick
这个东西也让我感到困惑,因为对我来说它是一种完全不同的思考方式。我开始认识到我需要学习更多关于Javascript 的知识。我目前的想法是需要创建自己的控制器对象(这是一个函数,将接收到Dojo环境所需的必要引用),然后我可以在其中执行我需要在范围内的所有引用和代码。 - mydoghasworms
2个回答

3

我不确定你想要实现什么,但是对我来说,它看起来像一个编程反模式。无论如何,你可以通过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. Give the ContentPane an id and obtain its reference via dijit's registry.byId().
  2. Create ContentPane instance in a separate module and expose it as a return value of that module:

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

1

我认为这更多是范围问题,而不是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 $$)在一个函数内部,该函数是加载程序要求模块完成时的回调函数。
延迟处理程序对此非常有用,如下所述。但如果您已经处于分离的(异步)函数流中,则会略有开销。要获得完全控制,请查看 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 函数中退出。 - sokid

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接