5

我有一个函数,它接受一个参数并进行同步加载。

我将其更改为执行异步 jQuery.ajax 调用以检索数据并调用回调。旧代码(无法修改)使用相同的功能并失败。我需要能够以两种方式检索数据,以便异步代码可以继续运行,如果异步已经加载,旧同步代码可以检索缓存的数据,同步加载或等待任何已经运行的异步请求。

var ajaxQueries = {}
loadEngineData(fileId, callback) {
    var sync = callback == undefined;
    if (ajaxQueries[fileId]) {
        if (sync) {
            //Need to stop here and wait for ajaxQueries[fileId] to finish
            //Execution cannot continue! If we return before defered has ended here 3rd party scripts will fail.
            return data;
        }
        else {
            ajaxQueries[fileId].done(function(data){callback(data)});
        }
    }
    else {
        ajaxQueries[fileId] = $.ajax({
            async:!sync,
            type:'GET',
            url:fileId2Name(fileId),
            data:null,
            dataType:'text',
        });
        if (sync) {
            var _data = undefined;
            ajaxQueries[fileId].done(function(data){_data=data});
            return _data;
        }
        ajaxQueries[fileId].done(function(data){callback(data);});
    }
}

如果旧脚本调用该函数,则 ajax 查询将同步运行,所有后续调用都将使用延迟.done.fail一切都会好起来的。

var enginePhyData = loadEngineData('physics');
//Do stuff

如果一个新脚本首先调用该函数,并且在此加载过程中,一个旧脚本尝试从同一文件加载数据,我会遇到延迟 ajax 查询ajaxQueries[fileId]异步运行的情况,我必须等待它完成加载数据以避免破坏现有的库。

我简化loadEngineData以保持问题的集中。否则它会更复杂一些,并允许调用文件列表以并行加载

loadEngineData(['geometry', 'scripts'], function() {
    var phy = loadEngineData('physics');
    var geo = loadEngineData('geometry');
    var scr = loadEngineData('scripts');

    //run the async function;
});
loadEngineData('physics', function() {
    //run the async function;
});

//...
//in the scripts file

var phy = loadEngineData('physics');
//here phy might be undefined if this file went through eval() before `loadEngineData('physics',...)` was called;

我可以对代码进行现代化改造,但问题是某些文件在项目之间共享并在不同的环境中运行。如果不分叉依赖项,我目前无法修改旧脚本。

4

2 回答 2

5

在等待某些异步 ajax 调用完成时,您不能停止执行 javascript。Javascript 根本不能那样工作。

相反,您必须重新编写编程方式,以便希望等待异步 ajax 调用完成的代码将通过回调函数执行,而不是在 ajax 调用执行后同步执行。

于 2013-01-21T18:10:03.917 回答
1

你很接近,如果它是一个同步请求,你只需要返回 responseText 。

return data

变成

return ajaxQueries[fileId].responseText;

由于请求是同步的,因此无需等待,浏览器已经等待响应。

var ajaxQueries = {}
loadEngineData(fileId, callback) {
    var sync = callback == undefined;
    if (ajaxQueries[fileId]) {
        if (sync) {
            return ajaxQueries[fileId].responseText;
        }
        else {
            ...
于 2013-01-21T18:54:36.253 回答