如何在不锁定浏览器的情况下执行对服务器的 "synchronous" javascript 调用

How to execute "synchronous" javascript call to server without locking up the browser

这可能是个愚蠢的问题,但是....在 Javascript 中有没有办法在不锁定浏览器线程的情况下同步等待特定请求完成?

目标是使用 ajax 调用服务器端并在调用完成后执行一段代码并避免回调(地狱)。 像这样的一些简单的代码。

// some js code
var result = doServerCall(); // w/out (b)locking the browser thread -> browser must remain responsive
// some js code to process the result

请注意 setTimeoutsetInterval 不是可接受的解决方案,需要的是像上面那样直接执行。最终一个回调,之后执行将在对服务器的调用完成的地方继续执行也可以(见下文)。

我在 Firefox 附加组件中使用了以下内容(这不是我想要的,但仍然是一个可接受的解决方案)。

globalDone = false;
// some js code
doServerCall(); // asynchrnonous call here, the callback is below
var thread = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager).currentThread;
while ( globalDone === false ) {
    thread.processNextEvent(true);
}
// some js code to process the result

回调

function processResponse ( xhrResponse ) {
   globalResult = xhrResponse;
   globalDone = true;
}

通过 Internet、Whosebug 和论坛,每个人似乎都想要这个,但没有浏览器看起来可以实现它

this may be a stupid question, but....is there a way in Javascript to synchronously wait for a specific request to finish without locking the browser thread?

不,无法使用同步代码执行此操作。异步代码和 AJAX 的全部目的就是解决这个问题。

您可以通过 Webworker 发出请求来实现不阻塞 UI 线程的同步 HTTP 请求。但是,将结果传回 UI 线程仍然是异步的。此外,Webworker 的启动需要时间和内存成本,所以请记住这一点。

另一种可能性是使用 ES6 Generators to simulate non-blocking synchronous execution of async functions. See here。但是,浏览器对此的支持仍然有限。

网络工作者示例:

工人

self.onmessage = function (event) {
    if (event.data === "init") {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", "foo.com", false); // false means non-async
        xhr.send(null);
        var result = xhr.responseText;
        // do stuff with result...

        self.postMessage(result); // pass result
        self.close(); // terminate self
    }
};

主脚本

var worker = new Worker("myWorker.js");
worker.onmessage = function (event) {
    console.log(event.data);
};
worker.postMessage("init");

Webworkers 也可以在不需要单独文件的情况下使用,如 here 所述。