1

我想允许我的 JavaScript 数据包请求(同步 ajax 调用)其他 JavaScript 数据包:

// 2 sequential synchronous calls
framework.require('packet1'); // time1 ms
framework.require('packet2'); // time2 ms
// use packets

这 2 个请求将处理 time1+time2 毫秒。所以还有一个想法:让这些请求每个都异步,但要保证整堆请求都会被同步处理:

// 2 parallel asynchronous calls, synchronous in total
framework.require([
    'packet1', // time1 ms
    'packet2'  // time2 ms
]);
// use packets

据我了解,这应该更快。现在让我们看看我的实现:

framework = {
    require_counter:0,
    require: function(arr)
    {
        framework.require_counter = arr.length;

        var success = function(data, textStatus, jqXHR)
        {
            framework.require_counter -= 1;
        }
        var error = function(jqXHR, textStatus, errorThrown)
        {
            framework.require_counter -= 1;
            // some error notification
        }

        // asynchronous calls
        for (var i = 0; i < arr_js.length; i++)
            $.ajax({
                url: arr_js[i],
                success: success,
                error: error
            });

        // wait
        while (framework.require_counter > 0)
            framework.wait();

        // finally return
    }
}

最棘手的部分是实现 wait() 函数。JavaScript 不提供;应该找到另一种解决方案。异步 setTimeout() 不是答案。那是我的问题:如何实现 wait() 函数?或者也许还有另一种通用解决方案?

我试过这种方法: http: //narayanraman.blogspot.com/2005/12/javascript-sleep-or-wait.html。也许您会指出没有服务器依赖性的更“简洁”的解决方案。

4

1 回答 1

1

如果确实需要同步请求,通常可以直接使用底层的 AJAX 机制来实现。例如,在 jQuery 中,您将async 设置设置为 false。使用 XMLHttpRequest 时,您将 false 作为第三个参数传递给open(这是 Ramansleep在您链接到的博客文章中实现的方式)。但是,SJAX 通常是一件坏事,因为它会阻止 JS 在当前浏览器中执行。更好的是使用延续传递样式,传递一个代表其余计算运行的函数:

framework = {
    require: function(urls, done)
    {
        function success(data, textStatus, jqXHR)
        {
            //...
        }
        function error(jqXHR, textStatus, errorThrown)
        {
            //...
        }

        urls.unshift('');
        function load() {
            urls.shift();
            if (urls.length) {
                $.ajax({
                    url: urls[0],
                    // here are some continuations
                    complete: load,
                    success: success,
                    error: error
                });
            } else {
                // here's a continuation invocation
                done();
            }
        }
    }
};

如果在加载所有给定资源时需要执行某些操作而不是同步性,则可以对操作使用延续,但不用于资源加载。相反,您只需应用一个事件处理模型,记录每个加载的完成情况,并在所有资源请求完成时调用相关操作。

framework = {
    require: function(urls, done)
    {
        var remaining = urls.length;
        var failed=[];
        // The following implementation is vulnerable to race conditions.
        // Good thing JS isn't generally multithreaded. If (when) it is,
        // and if the browser doesn't offer some form of synchronization,
        // then Peterson's algorithm should work correctly if inefficiently.
        function success(data, textStatus, jqXHR) {
            if (!--remaining) { // critical section
                done(failed);
            }
        }
        function makeErrorHandler(url) {
            return function (jqXHR, textStatus, errorThrown) {
                failed.push(url);
                if (!--remaining) { // critical section
                    done(failed);
                }
            }
        }

        for (var i=0; i < urls.length; ++i) {
            $.ajax({
                url: urls[i],
                success: success,
                error: makeErrorHandler(urls[i])
            });
        }
    }
};
于 2011-02-17T01:52:37.000 回答