在这种情况下对Node.js中的函数进行阻塞调用? [英] Make a blocking call to a function in Node.js required in this case?

查看:59
本文介绍了在这种情况下对Node.js中的函数进行阻塞调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我开始学习node.js.我在这里遇到了问题。我正在呼叫一个返回JSON的天气服务(下面的网址)。

I am starting to learn node.js. I am stuck with a problem here. I am calling a weather service which returns a JSON(url below).

http://api.wunderground.com/api/Your_key/conditions/q/CA/San_Francisco.json

我想显示来自的结果HTML页面上的api。

I want to display the results from the api on an HTML page.

我编写了以下代码(getInfo模块)来检索并返回JSON。

I have written the following code(getInfo module) to retrieve and return the JSON.

var fbResponse; 

module.exports = function (url) {

var http=require('http');


http.get(url, function(res) {
    var body = '';

    res.on('data', function(chunk) {
        body += chunk;
    });

    res.on('end', function() {
        fbResponse = JSON.parse(body);  
        console.log("Got response: ", fbResponse.response);


    });

}).on('error', function(e) {
      console.log("Got error: ", e);
});


return fbResponse;
};

为了使用这个模块,我创建了一个test.js文件,如下所示:

So to use this module I created a test.js file as follows:

var relay = require('./getInfo');
var url = 'http://api.wunderground.com/api/Your_key/conditions/q/CA/San_Francisco.json';
var response;
var x=relay(url);

console.log (x);

输出如下:

undefined                //  console.log(x) from test.js
Got response:  { version: '0.1',
  termsofService: 'http://www.wunderground.com/weather/api/d/terms.html',
  features: { conditions: 1 } }

测试代码中的控制台输出首先运行,其中没有数据。 HTTP get稍后竞争并显示我需要的实际输出。

The console output in the test code runs first with no data in it. The HTTP get competes later and displays the actual output I need.

如何修改测试代码以进行阻塞调用,以使测试代码中的var x实际上具有JSON输出而不是未定义?

How can I modify the test code to make a blocking call such that var x in the test code actually have the JSON output instead of undefined?

我是否可以在没有对getInfo模块进行阻塞调用的情况下实现所需的结果?

Can I achieve the desired result without a blocking call to the getInfo module?

推荐答案

如您所知,node是异步的,因此回调 http.get res.on('end',.. 将在执行 relay 函数后触发并返回。所以通常你不能从中返回结果。

As you know, node is asynchronous, so the callback of http.get and res.on('end', .. will fire after relay function is executed and it is returned. So normally you can't return the result from it.

您有几个选择:


  • 将回调传递给 relay 并使用:

module.exports = function (url, cb) {
    http.get(url, function(res) {

        var body = '';
        res.on('data', function(chunk) {
            body += chunk;
        });

        res.on('end', function() {
            cb(null, JSON.parse(body));
        });

    }).on('error', cb);
};

然后像这样使用它:

var relay = require('./getInfo');
relay(url, function (err, x) {
    if (err) {
        console.error('oohh i got a error: ', err)    
    }
    console.log('oohh i got a response: ', x)    
});


  • 使用promises。这与传递回调几乎相同。稍微不那么轻巧,但在组合不同的异步操作时,您将了解它们有多棒。对于一个异步调用,可能没有任何区别。在这里,我使用 q 。您也可以使用 bluebird ,这种方式性能更高,但缺少一些q的糖。你可以阅读这篇文章了解为什么promises在某些情况下比回调更清晰。

  • Use promises. This is almost same as passing callbacks. A little less lightweight, but when combining different asynchronous operations, you will understand how awesome they are. For just one asynchronous call there might not be any difference. Here I use q. You can also use bluebird which is way more performant but lacks some of the sugar of q. You can read this article to understand why promises are cleaner than callbacks in some cases.

    module.exports = function (url) {
        var deferred = Q.defer();
        http.get(url, function(res) {
            var body = '';
            res.on('data', function(chunk) {
                body += chunk;
            });
    
            res.on('end', function() {
                deferred.resolve(JSON.parse(body));
            });
    
        }).on('error', function(e) {
            deferred.reject(e);
        });
        return deferred.promise;
    };
    
    
    
    var relay = require('./getInfo');
    relay(url).then(function responseHandler(x) {
        console.log('my awesome response')
    }, function errorHandler(err) {
        console.error('got an error', err);
    });
    


  • 使用生成器。它是Ecmascript 6规范的一部分,它仅存在于节点v0.11.x及更高版本中。但它几乎就是你想要的。

  • Use generators. It is part of Ecmascript 6 specification it only exists in node v0.11.x and later. But it would be almost what you want.

    有了过去的承诺,我们可以做到这一点:

    With that past promise example we can do this:

    Q.async(function *() {
        var relay = require('./getInfo');
        var x = yield relay(url);
        console.log('my awesome response', x)
    });
    

    这几乎就是你想要的。你也可以使用 co library

    This is almost what you want. You can also achieve it using the callback solution with co library:

    co(function *() {
        var relay = require('./getInfo');
        var x = yield relay.bind(null, url);
        console.log('my awesome response', x);
    });
    

    您还可以使用节点纤维在上面的例子中几乎是类似工具的生成器。

    You can also use node-fibers in above example which is almost a similar tool like generators.

    如果你想使用出血边缘Javascript,您可以使用 Async / Await 而不是承诺的发电机。

    If you want to use bleeding edge Javascript, you can use Async/Await instead of generators with promises.

    这篇关于在这种情况下对Node.js中的函数进行阻塞调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆