2

我的项目包括以下文件:

./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/main.js文件如下:

var root = this;
define('jquery', ['http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.3.js'], function () { return root.$; });
define('ko', ['http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.1.0.js'], function (ko) { return ko; });

js/viewmodel/vm.js文件...

define(['jquery', 'ko'], 
    function($, ko) {
        return {
            subject: 'world',
            greeting: 'hello'
        }
    }
);

当您打开浏览器访问 index.html 时,浏览器会尝试加载一个名为js/ko.js而不是使用 .html 中定义的模块的文件main.js。似乎 data-main 属性指向的 js 文件不能保证在依赖解析之前运行。这对我来说似乎不正确,因为 data-main js 文件的一个目的是定义要求配置(即路径、垫片等)。我正在使用需要 v2.1.2。

如果我将main.js文件的内容复制到index.html. “完全没问题”是指它将 ko 解析为一个模块并找到适当的 CDN 链接来解析 ko 而不是尝试下载./js/ko.js.

4

3 回答 3

12

要使用该data-main属性来配置整个应用程序,它必须是所有代码的单一入口点。

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

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

于 2012-11-30T18:35:49.373 回答
7

那是因为 requirejs 设置了async。脚本上的属性。

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

这意味着两个脚本都是并行加载和评估的,因此两个脚本都不能访问另一个脚本的方法或函数。如果要在一个脚本中定义 requirejs 变量,则不能使用 require js 加载该脚本。

对我来说,解决这个问题的方法有三种:

  • 将 main.js 的内容添加到您的页面(如您所述)
  • 加载没有 requirejs 的 main.js 文件作为普通脚本
  • 在加载脚本之前定义 require 配置(链接到 requirejs 文档
于 2012-11-30T08:05:35.587 回答
1

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

索引.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>

js/main.js

require.config({
  // your config
});

require( [ 'AppLogic' ], function( AppLogic ){      
    AppLogic.Init();
    window.BeforeMainGuard.onMainLoaded();
} );
于 2014-10-16T12:19:11.990 回答