在加载所需模块之前,RequireJS不运行数据主脚本

在加载所需模块之前,RequireJS不运行数据主脚本,requirejs,Requirejs,我的项目包括以下文件: ./index.html ./js/main.js ./js/vendor/require.js ./js/viewmodel/vm.js index.html包含以下相关代码段: <script data-main="js/main.js" src="js/vendor/require.js"></script> <script type="text/javascript"> require(['viewmodel/vm',

我的项目包括以下文件:

./index.html
./js/main.js
./js/vendor/require.js
./js/viewmodel/vm.js
index.html
包含以下相关代码段:

<script data-main="js/main.js" src="js/vendor/require.js"></script>
<script type="text/javascript">
    require(['viewmodel/vm', 'ko'], 
        function(viewmodel, ko) {
            ko.applyBindings(viewmodel);
        }
    );
</script>
js/viewmodel/vm.js
文件

define(['jquery', 'ko'], 
    function($, ko) {
        return {
            subject: 'world',
            greeting: 'hello'
        }
    }
);
打开index.html浏览器时,浏览器会尝试加载名为
js/ko.js
的文件,而不是使用
main.js
中定义的模块。看起来data main属性指向的js文件不能保证在依赖项解析之前运行。这在我看来并不正确,因为data main js文件的一个目的是定义所需的配置(即路径、垫片等)。我使用的是requirev2.1.2


如果我将
main.js
文件的内容复制到
index.html
中的脚本块中,这将非常有效。“非常好”是指它将ko解析为一个模块,并找到合适的CDN链接来解析ko,而不是尝试下载
/js/ko.js

,这是因为requirejs设置了。属性

脚本元素上的布尔异步属性允许外部 JavaScript文件在可用时运行,不会延迟页面加载 首先

这意味着两个脚本都是并行加载和计算的,因此这两个脚本都不能从另一个脚本访问方法或函数。 如果您想在一个脚本中定义requirejs变量,就不能用requirejs加载该脚本

对我来说,有三种可能性可以解决这个问题:

  • 将main.js的内容添加到页面(如您所述)
  • 作为普通脚本加载main.js文件而不使用requirejs
  • 在加载脚本()之前定义require配置

要使用
data main
属性来配置整个应用程序,必须将其作为所有代码的单个入口点

您的第二个脚本块通过提供第二个入口点来打破这一要求。由于这些入口点将相互独立(异步)解析,因此不能依赖一个入口点来影响另一个入口点


要解决这个问题,请以一种为应用程序提供单一入口点的方式重构代码,并通过该入口点进行配置。

我也遇到了同样的问题。我工作的站点的架构是在页面的每个部分异步加载的组件。 每个组件都有自己的html、css和js代码。 因此,我的解决方案是为所有必需的依赖代码保留一个保护函数,以防止它们在主javascript文件之前运行:

index.html

<head>
<script type="text/javascript">
    window.BeforeMainGuard = {
        beforeMainLoadedFunctions: [],
        hasMainLoaded: false,
        guard: function( func ) {
            console.assert( typeof func === 'function' );
            if( this.hasMainLoaded ) {
                func();
            }else {
                this.beforeMainLoadedFunctions.push( func );
            }
        },
        onMainLoaded: function() {
            for( var i = 0; i<this.beforeMainLoadedFunctions.length; ++i ) {
                var beforeMainLoadedFunction = this.beforeMainLoadedFunctions[i];
                  beforeMainLoadedFunction();
            }
            this.beforeMainLoadedFunctions = null;
            this.hasMainLoaded = true;
        }
    };
</script>
<script data-main="js/main.js" src="js/vendor/require.js"></script>
<script type="text/javascript">
    window.BeforeMainGuard.guard( function() {
        require(['viewmodel/vm', 'ko'], 
            function(viewmodel, ko) {
                ko.applyBindings(viewmodel);
            }
        );
    });
</script>
</head>

感谢您对浏览器异步执行的解释。我想问的问题大意是:“在完成数据主引用脚本之前,Requirejs没有阻止所有模块的执行,这正确吗?”并且@neonstalwart为我正确地回答了这个问题。这是否意味着如果我有很多页面,或者我需要很多js文件将它们合并到一个js文件中,这样才能工作?或者在每一页中重复require.config?这种单一入口点的做法仅与单个页面相关。如果应用程序跨越多个不同的URL,那么在一个URL加载的脚本不会影响在另一个URL使用的脚本的逻辑。是的,但我必须跨越每个页面上的
require.config()
config,对吗?有没有办法使它全球化?
<head>
<script type="text/javascript">
    window.BeforeMainGuard = {
        beforeMainLoadedFunctions: [],
        hasMainLoaded: false,
        guard: function( func ) {
            console.assert( typeof func === 'function' );
            if( this.hasMainLoaded ) {
                func();
            }else {
                this.beforeMainLoadedFunctions.push( func );
            }
        },
        onMainLoaded: function() {
            for( var i = 0; i<this.beforeMainLoadedFunctions.length; ++i ) {
                var beforeMainLoadedFunction = this.beforeMainLoadedFunctions[i];
                  beforeMainLoadedFunction();
            }
            this.beforeMainLoadedFunctions = null;
            this.hasMainLoaded = true;
        }
    };
</script>
<script data-main="js/main.js" src="js/vendor/require.js"></script>
<script type="text/javascript">
    window.BeforeMainGuard.guard( function() {
        require(['viewmodel/vm', 'ko'], 
            function(viewmodel, ko) {
                ko.applyBindings(viewmodel);
            }
        );
    });
</script>
</head>
require.config({
  // your config
});

require( [ 'AppLogic' ], function( AppLogic ){      
    AppLogic.Init();
    window.BeforeMainGuard.onMainLoaded();
} );