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

好了,我要怎么做才能:

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中是可能的。


当前回答

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

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

function foo() {    
  var fooVariable;

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

  return fooVariable;
}

var temp = foo();  
console.log(temp);

其他回答

你可以强制NodeJS中的异步JavaScript与sync-rpc同步。

It will definitely freeze your UI though, so I'm still a naysayer when it comes to whether what it's possible to take the shortcut you need to take. It's not possible to suspend the One And Only Thread in JavaScript, even if NodeJS lets you block it sometimes. No callbacks, events, anything asynchronous at all will be able to process until your promise resolves. So unless you the reader have an unavoidable situation like the OP (or, in my case, are writing a glorified shell script with no callbacks, events, etc.), DO NOT DO THIS!

但你可以这样做:

。/ calling-file.js

var createClient = require('sync-rpc');
var mySynchronousCall = createClient(require.resolve('./my-asynchronous-call'), 'init data');

var param1 = 'test data'
var data = mySynchronousCall(param1);
console.log(data); // prints: received "test data" after "init data"

。/ my-asynchronous-call.js

function init(initData) {
  return function(param1) {
    // Return a promise here and the resulting rpc client will be synchronous
    return Promise.resolve('received "' + param1 + '" after "' + initData + '"');
  };
}
module.exports = init;

限制:

这些都是sync-rpc实现的结果,即滥用require('child_process').spawnSync:

这将在浏览器中不起作用。 函数的参数必须是可序列化的。您的参数将传入和传出JSON。因此函数和不可枚举的属性(如原型链)将丢失。

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

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

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

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

function foo() {    
  var fooVariable;

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

  return fooVariable;
}

var temp = foo();  
console.log(temp);

使用Node 16的工作线程实际上使这成为可能,下面的例子是主线程正在运行异步代码,而工作线程正在同步地等待它。

这并不是说它非常有用,但它至少模糊地完成了同步等待异步代码所提出的最初问题。

const {
    Worker, isMainThread, parentPort, receiveMessageOnPort
} = require('worker_threads');
if (isMainThread) {
    const worker = new Worker(__filename);
    worker.on('message', async () => {
        worker.postMessage(await doAsyncStuff());
    });
} else {
    console.log(doStuffSync());
}

function doStuffSync(){
    parentPort.postMessage({fn: 'doStuff'});
    let message;
    while (!message) {
        message = receiveMessageOnPort(parentPort)
    }
    return message;
}

function doAsyncStuff(){
    return new Promise((resolve) => setTimeout(() => resolve("A test"), 1000));
}