支持 AMD 的库中的异步请求

Async request in library which support AMD

由于使用 XMLHttpRequest 发出的异步请求,我想要构建的库出现问题。我会用一些代码来解释:

(function(root,factory){
    if( typeof define === "function" && define.amd ){
        // AMD module
        define([], factory);
    }else{
        global.tof = factory();
    }
})(this, () => {
    const obj = {
        datas: {},
        get: function(){}
        ...
    }
    const url = "...";
    let request = new XMLHttpRequest();
    request.open('GET',url);
    request.responseType = 'json';
    request.send();
    request.onload= function(){
        obj.datas = request.response;
    }
    return obj;
});

我使用回调来确保我收到数据并在数据加载时定义我的模块,但是当我使用 requireJS 加载 "library" 时它仍然会在我的模块真正定义之前触发。

(function(root,factory){

    function myCallback(r){

        if( typeof define === "function" && define.amd ){
            // AMD module
            define('tof',[], factory(function(r){
                return r;
            }));
        }
    }
    factory(myCallback);

})(this, function foo(callback){
    const obj = {
        datas: {},
        get: function(){}
        ...
    }
    const url = "...";
    let request = new XMLHttpRequest();
    request.open('GET',url);
    request.responseType = 'json';
    request.send();
    request.onload= function(){
        obj.datas = request.response;
        callback(obj);
    }
});

我用来用 requireJS 测试我的模块的另一个脚本:

require(['tof'], function(tof){
    // return undefined because of my async request
    console.log(tof);
});

我该如何解决这个问题?

我相信您很快就发现您的第一次尝试是行不通的,因为您不能使用同步 return 到 return 异步获得的值。

你的第二次尝试也不行。看起来您希望传递给 define 的工厂函数 异步定义模块 但 RequireJS 不允许这样做。您需要做的是以提供允许模块用户异步检索 XMLHTTPRequest 结果的功能的方式设计模块。

这是一些可能性的草图。我强调这是一个草图。我打了这个即兴的。至少,您需要添加错误处理代码:

define(function () {
    const promise =  new Promise((resolve, reject) => {
        const request = new XMLHttpRequest();
        request.open('GET',url);
        request.responseType = 'json';
        request.send();
        request.onload = () => {
            obj.datas = request.response;
            resolve(obj);
        };
    });

    return {
        getResult: () => promise,
    };
});

然后您可以在其他地方使用它,例如:

require(['tof'], function (tof) {
    tof.getResult().then((result) => console.log(result));
});