0

我已经定义了一个模块(module1),它应该异步加载属性的值。我如何才能在我的应用程序中使用这个属性,一旦它被定义并且只有在它被定义之后?

我的设置(简化)

v1

应用程序.js

require(['module1'], function(mod) {
    document.getElementById("greeting").value = mod.getPersonName();
});

模块1.js

define(['jquery'], function($) {
    _person;

    $.get('values/person.json')
        .done(function(data) {
            _person = data
        });

    return {
        getPersonName: function() { return _person.name; }
    }

值/person.json

{ name: 'John Doe', age: 34 }    

这仅在 GET 几乎瞬间发生时才有效,否则它会失败,因为在调用 getPersonName 时 _person 未定义。

v2

为了解决这个问题,我想我会注册一个回调,以便在加载人员时通知应用程序。

应用程序.js

require(['module1'], function(mod) {
    mod.onPersonLoaded(function() {
        document.getElementById("greeting").value = mod.getPersonName();
    });
});

模块1.js

define(['jquery'], function($) {
    _person;
    _onLoaded;

    $.get('values/person.json')
        .done(function(data) {
            _person = data;
            _onLoaded();
        });

    return {
        getPersonName: function() { return _person.name; },
        onPersonLoaded: function(cb) { _onLoaded = cb; }
    }
}

如果 GET 很慢,这可以工作,但是,如果它很快 _onLoaded 在.done()被调用时是未定义的。

有没有一种好方法可以在定义后立即在 app.js 中使用 _person 值,并且仅在定义后才使用?

我正在使用 RequireJS,但我的问题通常适用于 AMD。

编辑

为了简化我的示例,我删除了一个可能很重要的层。我正在为 UI 使用 RactiveJS。

设置(稍微简化)

应用程序.js

require(['Ractive', 'module1'], function(Ractive, mod) {

    var ractive = new Ractive({
        ...
        data : {
            name: mod.getPersonName()
        }
    });

    ractive.observe(...);
    ractive.on(...);

});

编辑 2

我目前的解决方案,可能会发生变化。注册一个回调,在加载人员时通知 app.js。如果在注册回调时已加载人员,则立即调用回调。

应用程序.js

require(['Ractive', 'module1'], function(Ractive, mod) {

    var ractive = new Ractive({
        ...
        data : {}
    });

    mod.watchPerson(function() {
        ractive.set('person.name', mod.getPersonName());
    });

    ractive.observe(...);
    ractive.on(...);

});

模块1.js

define(['jquery'], function($) {
    _person;
    _onLoaded;

    $.get('values/person.json')
        .done(function(data) {
            _person = data;
            try {
                _onLoaded();
            } catch (e) {
                // that was fast!
                // callback will be called when it is registered
        });

    return {
        getPersonName: function() { return _person.name; },
        watchPerson: function(cb) { 
            _onLoaded = cb;
            if(_person != null) {
                _onLoaded();
            }
        }
    }
}
4

2 回答 2

2

Promise 在这里是一个不错的选择,因为回调总是_onLoaded()被异步调用——你永远不会遇到在设计之前就被调用的那种令人困惑的情况。

不幸的是,jQuery 的 Promise 实现不遵守Promises/A+ 规范,所以你没有得到保证。如果可能的话,您可以使用像Reqwest这样的替代 AJAX 库,并执行类似的操作

应用程序.js

define(['module1'], function (mod) {
  mod.then(function(person) {
    // do something with person.name
  }
});

模块1.js

define(['reqwest'], function (reqwest) {
  return reqwest('values/person.json');
});

使用文本加载器插件

另一种选择,因为您已经在使用 AMD,所以使用加载器插件,例如text

应用程序.js

define(['module1'], function (person) {
  // do something with person.name
});

模块1.js

define(['text!values/person.json'], function (personJSON) {
  return JSON.parse(personJSON);
});

使用文本加载器插件

事实上,甚至还有一个JSON 插件,因此您可以在此示例情况下完全取消 module1:

应用程序.js

define(['json!values/person'], function (person) {
  // do something with person.name
});
于 2014-01-28T01:25:49.437 回答
0

我就是这样做的。基本上,它和你的 V2 没有太大区别,但它增加了更多的封装性。

应用程序.js

require(['module1'], function(mod) {
    mod.loadPerson(function(person) {
        document.getElementById("greeting").value = person.getPersonName();
    });
});

模块1.js

define(['jquery'], function($) {
    return {
        loadPerson : function(callback) {
            $.get('values/person.json').done(function(data) {
                  _person = data;

                 callback({
                    getPersonName: function() { return _person.name; }
                 });
            });

        }
    }
}

你也可以使用 promises 来代替简单的回调。

于 2014-01-27T20:35:32.677 回答