【问题标题】:Waiting for an async HTTP request to complete等待异步 HTTP 请求完成
【发布时间】:2013-09-10 14:43:59
【问题描述】:

这里已经以各种方式提出了这个问题,我非常了解这个问题。一般的解决方案是调用回调来处理 HTTP 结果,但我特别想避免这种情况。

我想我可以使用“我们完成了吗”标志来保持工作正常,但这并没有按预期工作。

//
//  Test the IP the comment came-from.
//
exports.testJSON = function ( obj )
{
    var ip     = obj['ip'] || "";
    var result = null;
    var done   = false;

    //
    //  The URL request we're going to make
    //
    var options = {
        host: 'www.stopforumspam.com',
        port: 80,
        path: '/api?ip=' + ip
    };

    //
    // A GET request
    //
    var re = http.request(options, function(res) {
        var str = '';

        res.on('data', function(chunk) {
            console.log( "Got data " + chunk );
            str += chunk;
        });
        res.on('end', function() {
            console.log( "Got END" );
            result = "..... ";
            done = true;
        });
      }).on('error', function(e) {
         done = true;
         console.log("Got error: ", e);
     });

   re.end();

   while( ! done ) {
   }

   return( result );
};

遗憾的是,这不起作用 - 忙碌的样子只是无限期地旋转,而且我看不到控制台日志记录表明我正在接收数据。

在“while(!done){}”循环中添加“process.nextTick()”也没有区别。

当然,我不需要重新设计我的整个插件系统来应对不同的方法,并且更新“完成”标志的回调会起作用,不知何故?

【问题讨论】:

  • 你的整个插件系统是用 JavaScript 写的吗?
  • 很抱歉,但如果您尝试使用同步循环来检查异步结果,您就不太了解问题所在。您似乎正在尝试做的事情,return 异步调用的结果,在 javascript (afaik) 中是不可能的。任何同步代码要么阻塞整个线程(阻止发出请求),要么在发出请求之前返回。
  • 我想可以通过破解一些 process.binding 来使其工作,但我不推荐它。
  • 是的,我正在将一个系统从 perl + XML::RPC 移植到 HTTP-JSON 消费 node.js 服务器。安德烈亚斯——是的,你是对的。我的意思是我理解为什么事情是这样的,而且因为我使用的是一个幼稚的插件架构,所以我不能轻易地适应使用回调来返回结果。具体问题是在回调完成之前到达函数结束 - 这很明显,但我曾希望解决这个问题,但我发现我不能:(

标签: node.js


【解决方案1】:

如果您的整个插件系统都在使用 JavaScript,那么重新设计它可能不是一个坏主意。如果您不想使用回调处理异步代码,您可以将 Promise 作为另一种管理异步代码的解决方案。图书馆"q" 可能是一个很好的起点。

另一种方法是使用node-fibers。我以前从未使用过它,但示例很简单。以一个普通的回调模式为例:

console.log('waiting 2 seconds...');
setTimeout(function() {
    console.log('Finished!');
}, 2000);

使用节点光纤的类似示例:

var Fiber = require('fibers');

function wait(ms) {
    var fiber = Fiber.current;
    setTimeout(function() {
        fiber.run();
    }, ms);
    Fiber.yield();
}

Fiber(function() {
    console.log('waiting 3 seconds...');
    wait(1000);
    console.log('waiting 2 seconds...');
    wait(1000);
    console.log('waiting 1 seconds...');
    wait(1000);
    console.log('done!');
}).run();

为了让节点光纤发挥作用,需要进行一些包装,但现在您可以避免处理回调并以同步方式使用异步代码。

【讨论】:

  • 值得一提的是为什么他的解决方案不起作用——他的node.js代码在一个线程中运行,而while循环永远控制着线程,所以回调永远没有机会调用。
  • 确实如此。看来我必须查看一些 mpm 承诺/队列模块,看看是否能找到合适的。
  • 我过去使用过 async 库 - 可能也值得一看。