【问题标题】:How can I wrap up an asynchronous call to behave synchronously?如何包装异步调用以同步运行?
【发布时间】:2011-10-14 02:38:33
【问题描述】:

目前,这是我使用 node-mysql 执行查询的方式

client.query( sql, function( error, result ) {
  console.dir( result );
});

我想同步地做这个,像这样

var result = client.querySync( sql );
console.dir( result );

我明白为什么阻塞在节点中是不好的,但我(几乎)已经长大了,知道什么时候可以,什么时候不行。我只打算在初始化阶段进行同步调用,在任何事件循环之外。

请问有谁知道我是怎么做到的?

编辑...

类似于...的东西

client.querySync = function( sql )
{
    var called = false;
    var result;

    while ( typeof result == 'undefined' ) {
        if ( ! called ) {
            called = true;
            this.query( sql, function( error, _result ) {
                result = { error: error, result: _result };
            });
        };
    }

    return result;
};

【问题讨论】:

标签: javascript mysql node.js


【解决方案1】:

您提出的解决方案(在您的编辑中)将不起作用,因为您永远不会放弃线程(因此永远无法调用回调,因此永远无法设置变量,因此您的循环永远不会中断)。 Node 不是多线程的——任何时候只有一个线程执行 javascript。除非从正在运行的任何代码返回,否则无法产生该线程。

所以,你不能做你想做的事。您可以尝试使用一些在幕后将同步代码重写为异步的解决方案,但我个人发现这种方法并不值得付出努力——最好还是硬着头皮去做一切都有回调(随着时间的推移,痛苦会消退:)。

【讨论】:

  • 好的,现在我们到了某个地方。或不。 :)
  • 我使用的心智模型是由 1 的线程池服务的作业队列。任何 i/o 完成都会创建新作业,其中作业是适当的回调。作业持有线程,直到它从其入口函数返回。我还发现将应用程序视为状态机有助于保持清晰(而不是一系列高度嵌套的回调)。
  • 我同意。我总是要自己去发现。从我的黑客攻击来看,感觉节点正在推迟 I/O 调用。我已经尝试在不同的地方放置无限循环,我看到了这种模式。我开始更清楚地看到它,但是,fs.readFileSync() 之类的东西正在搅浑我的水。
【解决方案2】:

node.js 无法让异步代码表现得像同步代码一样。

【讨论】:

  • 你看起来很确定。有什么证据?
  • 为了将异步调用转换为同步调用,您需要线程。调用者必须听到/锁定一个属性,并且异步回调必须在异步回调中设置数据。但是在node.js中线程是不可能的,所以真的没办法。
【解决方案3】:

你遇到了什么问题?

由于回调,您的示例本质上是程序性的。 如果你不想在所有这些东西都完成之前运行任何东西,那么只在所有回调完成后执行主代码:

client.query( sql, function( error, result ) {
  console.dir( result , function () {
      //now start your app code
  } );
});

一切仍然是异步的,你不会与你的环境作斗争,除非程序启动完成,否则什么都不会发生。 将整个事情包装在一个简单的函数中,并将回调作为参数,你应该很高兴。

至于同步执行这一切:Node.js 显然不允许您停止事件循环。这个概念不存在,你根本做不到。您可以将您的 querySync 编写为一个回调链,以使其同步运行。但它不会很漂亮。

【讨论】:

    【解决方案4】:

    我的猜测是,您可以添加队列系统,例如在命令的“客户端”中添加一个命令数组,然后通过每次调用客户端的同步方法以及任何 '阻止”动作。

    所以:

    client.mySyncMethod = function(command, callback)
    {
        commandArray.push({command, callback});
        runCommands();
    }
    
    client.runCommands = function()
    {
        for (var i in commandArray)
        {
            // run command
        }
    }
    

    【讨论】:

      【解决方案5】:

      不要。学习做异步编程。

      使用像futuresJS 这样的流控制来保持你的代码井井有条

      【讨论】:

      • 好的,谢谢,我去看看。你知道我将如何创建 querySync。我相信我能够学习不止一种解决方案并做出自己的决定。
      • @tomwrong 您需要查看 API 并了解它们是否公开了 sync 调用。如果他们不这样做,那么你就不走运了
      • 感谢 Raynos,我添加了自己的解决方案。如果我们可以请暂时把是非放在一边,你会知道为什么它不起作用吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-19
      • 1970-01-01
      • 1970-01-01
      • 2012-10-15
      相关资源
      最近更新 更多