【问题标题】:how do I use curl.js to load an object?如何使用 curl.js 加载对象?
【发布时间】:2013-02-14 00:27:26
【问题描述】:

Curl 0.7.3

我从这里得到了一些 AMD/CommonJS 适配器代码: supporting both CommonJS and AMD

(function (name, definition) {
      if (typeof module != 'undefined') {
        module.exports = definition();
      }
      else if (typeof define == 'function' && typeof define.amd == 'object') {
        define(name, [], definition);
      }
      else {
        this[name] = definition();
      }
    }('modXyz', {
          sayHi:function (name) {
            console.log('Hi ' + name + '!');
          }
        }
    ));

我想将该代码与 Curl 一起使用,以使我的所有代码与 AMD/CommonJS 兼容。我期望能够做到的是:

greeter = curl(['modXyz']); 
greeter.sayHi("Gracie"); 

但是curl 返回的对象不是我期望的对象。我能得到的最接近的是:

curl(['modXyz'], function(mod) { window.greeter = mod; }); 
greeter.sayHi("Gracie");

这似乎违背了 AMD 的目的。 curl 有能力做这样的事情吗?我必须使用require.js 来实现它吗?

【问题讨论】:

    标签: javascript module requirejs amd curl.js


    【解决方案1】:

    因为浏览器远离它的资源,它要么在获取这些资源时阻塞主线程,要么必须异步获取它们。由于我们永远不应该阻塞主线程(实际上使浏览器无响应),我们必须异步获取资源。 (任何 AMD loader、RequireJS、dojo 等都一样)

    因此,像下面这样的事情是行不通的:

    var foo = require('lib/foo');
    

    好吧,它不能在您可能习惯于在浏览器中使用的通常的全局空间中工作。但是,它可以在受控环境中工作,例如在 AMD 模块内部。

    第 1 步:在模块内编写代码。

    第 2 步:编写引导模块来启动您的应用。

    <script src="lib/curl/src/curl.js"><script>
    <script src="myapp/run.js"><script>
    

    run.js 内部:

    // curl 0.7.x requires a named module here ('myapp/run')
    define('myapp/run', ['curl'], function (curl) {
        curl.config(
            baseUrl: '',
            packages: [ /* configure your 3rd-party packages */ ],
            paths: { /* configure any non-package 3rd-party libs here */ },
            preloads: [ /* put modules that *must* be loaded first here (e.g. shims) */ ],
            main: 'myapp/main'
        });
    });
    

    “myapp/main”可能看起来像这样:

    define(function (require) {
        var view1 = require('myapp/view1/controller');
        view1.render();
        view1.placeAt('body');
    });
    

    在主模块(或任何 AMD 模块)内,require 的行为更像我认为您所期望的。请注意,这是一个特殊的 AMD 签名。您不能在 define 中指定依赖项并期望 require 表现得像这样。您必须以一种方式指定您的依赖项。这不起作用:

    define(['myapp/view1'], function (view1) {
        var foo = require('foo');
    });
    

    希望这会有所帮助。

    -- 约翰

    【讨论】:

    • 感谢您的详细记录。我认为我花了一段时间才“得到”这个 AMD 东西。现在说得通了。
    • 太棒了!从非模块到模块需要转变思维。异步部分使它更难。
    【解决方案2】:

    CurlJS 和 RequireJS 都支持 AMD AND CommonJS require 调用模式:

    CJS 和 AMD 的区别在于使用 Array 作为依赖列表的包装器。另请注意,在 CurlJS 的配置中,您可以将 curl 别名为 require 以使您的代码与 AMD 规范完全兼容。观察:

    CJS 需要调用模式:

    var a = require('name')
    

    CurlJS AMD 需要调用模式:

    var promise = require(['name'])
    promise.then(callbackFunction)
    

    这通常可以缩写为:

    require(['name']).then(callbackFunction)
    

    注意,CurlJS 返回 Promise 对象不是 AMD 规范的一部分。 AMD 规范似乎没有规定 AMD 风格的 require 调用的返回值。

    RequireJS 和 CurlJS 都支持标准 AMD 要求调用模式:

    require(['name'], callbackFunction)
    

    再次,注意使用 Array 作为标志,这是 AMD 风格的要求。这会触发不同的返回值逻辑。

    为了让你的东西如你所愿,在 CurlJS 上,你的代码必须在一个模块中,就像它是一个 CommonJS 模块一样,使用:

    define(function(require) { ... });
    

    有人告诉我,在这种情况下,require 的行为类似于 CommonJS 样式 require - 同步。实际上,在幕后发生的事情是加载器扫描工厂函数以查找您需要的东西,并将它们折叠到该定义的需求列表中。然后,在工厂内部你可以这样做:

    var greeter = require('modXyz'); 
    greeter.sayHi("Gracie");
    

    请注意,“同步”行为仍然是一种错觉,因为实际发生的是预加载了检测到的所需资源。

    在 RequireJS 上,甚至全局 require 也可以称为 CJS 样式:var resource = require('resource/path'),但只有 您之前已经加载过它。

    换句话说,在工厂函数运行之前,CurlJS 和 RequireJS 中的加载总是异步进行的,但是在 RequireJS 中你几乎可以在任何地方使用它,而在 CurlJS 中这是非常非常小众的场景。

    【讨论】:

    • 非常彻底的回应,谢谢。我在 OP 中解决了一些问题:“但是 curl 返回的对象不是我期望的对象。”我刚才用var greeter = curl(['mod']); (对象加载正确)和greeter.sayHi再次尝试了它,并得到了未定义的回复。 curl 返回的对象具有confignextthen 函数。看起来 curl 并没有返回我告诉它加载的对象。
    • @jcollum 以防你不确定我所说的缺少或存在“数组括号”是什么意思,例如:require(/*no bracket*/'a'/*no bracket*/)require(/*bracket!!! -&gt;*/['a']/*&lt;-- bracket!!!!!*/) 相比
    • 两种方法我都试过了,curl在两种情况下都返回相同的对象。
    • 你能检查一下你使用的是什么版本的 curl 吗?
    • @jcollum 道歉。 var a = require('o') 的用例在 CurlJS 中确实非常狭窄。只有特殊类型的本地 require 似乎支持 CJS 样式调用。该模块必须以该模式包装到define(function(require) { ... }) require。我的记忆对我起了作用,我把这与 RequireJS 方面的工作方式混淆了。 :(
    【解决方案3】:

    curl 函数是异步的,并返回一个承诺。因此,您只能将结果作为传递给 curl 的回调,或者通过传递给 then 的回调(一旦 promise 被实现就调用。

    curl(['dep1', 'dep2', 'dep3' /* etc */], callback);
    

    curl(['dep1', 'dep2', 'dep3' /* etc */])
        .then(callback, errorback);
    

    【讨论】:

    • 嗯,这似乎与 require 的做法有些不同。如果我想在回调之外使用它,是否必须将结果对象附加到窗口?我尝试在回调中返回它,但它不起作用。
    • 这与require无关,而是curl.js是如何实现的。您最好使用异步变体,例如 jQuery.ajax,并将 async 设置为 false。
    • 这只是让我更加困惑。 require.js 似乎不是同步的。
    • require.js 只加载代码。一旦代码被加载并且你可以执行它,require.js 就不再涉及了。那么这只是你如何使用curl的问题。完全不相关。
    • curl.js 和 RequireJS 都有 async 的全局变量。一旦您进入 AMD 封装的CJS 模块或已经列出其依赖项的经典AMD 模块,就可以使用local require 变量同步。 (注意“全局”和“本地”之间的区别。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-24
    • 2013-08-16
    • 2021-05-03
    • 2019-06-17
    • 2018-01-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多