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 组件的主要内容,如果未能解决你的问题,请参考以下文章