首先,这是一个非常具体的情况,故意以错误的方式将异步调用改造到非常同步的代码库中,该代码库有数千行之长,目前时间无法提供进行更改以“正确执行”的能力。它伤害了我身体的每一根纤维,但现实和理想往往不相符。我知道这很糟糕。

好了,我要怎么做才能:

function doSomething() {

  var data;

  function callBack(d) {
    data = d;
  }

  myAsynchronousCall(param1, callBack);

  // block here and return data when the callback is finished
  return data;
}

示例(或缺少示例)都使用库和/或编译器,这两者都不适用于此解决方案。我需要一个具体的例子,如何使它块(例如不离开doSomething函数,直到回调被调用)而不冻结UI。如果这样的事情在JS中是可能的。


当前回答

你想要的现在实际上是可能的。如果你可以在service worker中运行异步代码,在web worker中运行同步代码,那么你可以让web worker向service worker发送同步XHR,当service worker执行异步操作时,web worker的线程将等待。这不是一个很好的方法,但它可以工作。

其他回答

在Node.js中,可以编写调用异步操作的同步代码。 节点光纤可以做到这一点。它是作为npm模块提供的第三方本地扩展。 它实现了光纤/协程,所以当一个特定的光纤被阻塞等待异步操作时,整个程序事件循环不会阻塞——另一个光纤(如果存在)继续它的工作。

使用纤维,你的代码看起来像这样:

var Fiber = require('fibers');

function doSomething() {
  var fiber = Fiber.current;

  function callBack(data) {
    fiber.run(data);
  }

  myAsynchronousCall(param1, callBack);

  // execution blocks here
  var data = Fiber.yield();
  return data;
}

// The whole program must be wrapped with Fiber
Fiber(function main() {

  var data = doSomething();
  console.log(data);

}).run();

注意,应该避免使用async/await。请看下面来自项目自述文件https://github.com/laverdet/node-fibers:的说明

NOTE OF OBSOLESCENCE -- The author of this project recommends you avoid its use if possible. The original version of this module targeted nodejs v0.1.x in early 2011 when JavaScript on the server looked a lot different. Since then async/await, Promises, and Generators were standardized and the ecosystem as a whole has moved in that direction. I'll continue to support newer versions of nodejs as long as possible but v8 and nodejs are extraordinarily complex and dynamic platforms. It is inevitable that one day this library will abruptly stop working and no one will be able to do anything about it. I'd like to say thank you to all the users of fibers, your support over the years has meant a lot to me.

promise的这种能力包括同步操作的两个关键特性,如下所示(or then()接受两个回调)。 当您获得结果时,调用resolve()并传递最终结果。 如果出现错误,调用reject()。

其思想是将结果通过.then()处理程序链传递。

const synchronize = (() => {
    let chain = Promise.resolve()
    return async (promise) => {
        return chain = chain.then(promise)
    }
})()

在http://taskjs.org/上有一个不错的解决方案

它使用了javascript的新生成器。所以目前大多数浏览器都没有实现它。我在firefox中测试了它,对我来说,这是包装异步函数的好方法。

下面是来自GitHub项目的示例代码

var { Deferred } = task;

spawn(function() {
    out.innerHTML = "reading...\n";
    try {
        var d = yield read("read.html");
        alert(d.responseText.length);
    } catch (e) {
        e.stack.split(/\n/).forEach(function(line) { console.log(line) });
        console.log("");
        out.innerHTML = "error: " + e;
    }

});

function read(url, method) {
    method = method || "GET";
    var xhr = new XMLHttpRequest();
    var deferred = new Deferred();
    xhr.onreadystatechange = function() {
        if (xhr.readyState === 4) {
            if (xhr.status >= 400) {
                var e = new Error(xhr.statusText);
                e.status = xhr.status;
                deferred.reject(e);
            } else {
                deferred.resolve({
                    responseText: xhr.responseText
                });
            }
        }
    };
    xhr.open(method, url, true);
    xhr.send();
    return deferred.promise;
}

你也可以把它转换成回调。

function thirdPartyFoo(callback) {    
  callback("Hello World");    
}

function foo() {    
  var fooVariable;

  thirdPartyFoo(function(data) {
    fooVariable = data;
  });

  return fooVariable;
}

var temp = foo();  
console.log(temp);
let result;
async_function().then(r => result = r);
while (result === undefined) // Wait result from async_function
    require('deasync').sleep(100);