需要和异步&循环依赖

时间:2014-03-31 15:25:16

标签: javascript asynchronous requirejs circular-dependency appjs

我目前正在开发一个Web应用程序来编辑一些自定义文件格式(一个小编辑器,提供编辑配置文件的界面)。 这个应用程序的一个关键元素是一个名为" FileReader"这是一个包装器,它根据检测到的配置文件类型触发正确的接口。这样我只生成一个新的FileReader(src) - src是一个url或blob,它保持干净。

一旦检索到配置文件的类型,包装器就会检查它是否有与之关联的接口并简单地使用它。每个接口(针对每种不同的配置类型)都在单独的JS文件中定义。一旦包装器完全加载,我挂钩所有事件并开始执行应用程序。

以下是我与相关元素一起使用的HTML框架:

<!doctype html>
<html><head></head>
<body>
    <div id="UI"></div>
    <script src="js/fileReader/fileReader.js" >App.FileReader = function(){ ... }</script>
    <script src="js/fileReader/configType1.js" >App.FileReader.registerFileType("config1",object)</script>
    <script src="js/fileReader/configType2.js" >App.FileReader.registerFileType("config2",object)</script>
    <script src="js/fileReader/configType3.js" >App.FileReader.registerFileType("config3",object)</script>
    <script src="js/main.js" >App.run();</script>
</body>
</html>

现在,应用程序长大了,我决定将我的应用转换为使用requirejs 。 我的问题主要是关于&#34;什么是最好的组织&#34;处理这些模块因为我只能考虑一旦加载了所有文件类型模块就可以使用FileReader,但是我不能先加载它们,因为它们需要mainWrapper来注册它们的类型。

我能想出的最佳结构是:

main.js:

require(['require','FileReader','./fileReader/config1','./fileReader/config2','./fileReader/config3'],
    function( require ) {
        require(['require','./core/app'], function( require , App ) {
            App.run( window ) ;
        });
    });
});

fileReader.js:

define(function () {

    ...

    return FileReader ;

});

config1.js:

define(['FileReader'], function ( FileReader ) {

    var Interface = ... ;

    ...

    App.FileReader.registerFileType("config1",Interface)

    return FileReader ;

});

app.js:

define(['FileReader'], function ( FileReader ) {

    var App = function(){} ;

    App.run = function(){ FileReader.openFile( ... ) ; ... } ;

    return App ;

});

我的问题是什么? 为了确保FileReader对象包含正确的Interface对象,我首先手动强制requirejs加载所有FileReader相关文件,然后加载主app文件。这样,一旦App对象请求FileReader对象,它就已经包含了注册的正确接口。 我想要实现的只是要求 &#34; ./芯/应用&#34;在主文件中 &#34; ./的FileReader&#34;在核心/应用程序文件中 然后在第一次加载期间,如果可以将配置类型模块加载到fileReader文件中,注册所有内容然后返回答案,那就没问题。

我尝试的是:(在FileReader中)

fileReader.js:

define(["require"],function ( require ) {

    ...

    require(["config1","config2","config3"],
    function(){
        //occurs asynchronously, after the App.run() is triggered because of the synchronous return 
        callback(FileReader) ; //unfortunately I did not find any callback of this sort
                               //if it existed I could asynchronously find the list of the modules in the directory, load the them, and only then fire this fictive "ready" event
    }

    return FileReader ; //the first return occurs synchronously, so before the the fileReader is ready : modules are missing

});

那么加载这种模块的最佳方法是什么(在config-type文件和主FileReader之间存在某种循环依赖关系)?什么&#39;如果我想强制它是异步的,那么我可以阅读config-type目录中可用的内容?通过简单的HTML脚本列表,它们按正确的顺序加载,并且我可以轻松访问模块列表,现在我想确保在应用程序启动之前已经准备就绪。

2 个答案:

答案 0 :(得分:0)

在我看来,您可以将记录哪些文件类型可用的功能包含在一个新模块中,可能名为FileTypeRegistry。所以你的配置文件可能是这样的:

define(['FileTypeRegistry'], function ( FileTypeRegistry ) {

    var Interface = ... ;

    ...

    FileTypeRegistry.registerFileType("config1", Interface);    
});

这些模块不需要返回值。 registerFileType只是在注册表中注册一个类型。

FileReader.js可能包含:

define(["FileTypeRegistry", "config1", "config2", "config3"], function ( FileTypeRegistry ) {

    var FileReader = {};

    var FileReader.openFile = function (...) {
        var impl = FileTypeRegister.getFileTypeImplementation(...);
    };

    return FileReader;
});

getFileTypeImplementation根据类型名称检索实现(先前已注册的Interface)。

答案 1 :(得分:0)

路易斯&#39;答案很有意思,但它只是改变了创建新模块的问题,即使它将依赖项放在正确的上下文中,我也试图搜索一些真正的异步模块定义(而不仅仅是加载)。

我最终能想到的最好的方法是编辑require.js源文件以添加我期望的行为。我注册了一个新的处理程序(一个特殊的依赖行为,如&#34;要求&#34;或&#34;导出&#34;),称为&#34;延迟&#34;为模块定义提供了回调函数:

基本上,这是这样的:

define(["delay"], function ( delay ) {

    var Module = ... ;

    setTimeout(function(){ //Some asynchronous actions
        delay(Module) ; //This does actually returns the Module's value and triggers the "defined" event.
                        //It's actually transparent so the other modules just "feel" that the network's load time was a bit longer.
    },1000);

    return Module ; //This does not do anything because delay is active

});

由于这个异步定义,我现在可以扫描目录(异步请求),然后透明地加载所有模块。 修改只代表大约10行,所以如果有人感兴趣,我会在那里发布: https://github.com/jrburke/requirejs/pull/1078/files

显然,这不是第一次异步出口请求,但它仍然存在争议,所以我只是将它用于个人项目。