如何在nodejs同步中进行此请求调用?

时间:2012-03-27 06:31:18

标签: javascript node.js request

我的nodejs应用程序中有一个名为get_source_at的函数。它需要一个uri作为参数,其目的是从该uri返回源代码。我的问题是我不知道如何使函数同步调用请求,而不是给它回调函数。我希望控制流停止加载uri所需的几秒钟。我怎样才能做到这一点?

function get_source_at(uri){
    var source;
    request({ uri:uri}, function (error, response, body) {
        console.log(body);
    });
    return source;
}

此外,我已经阅读过关于'事件'以及节点是如何'偶像'的,我应该在编写代码时尊重它。我很高兴这样做,但我必须有一种方法来确保我在继续我的应用程序的控制流之前从uri获得源代码 - 所以如果不是通过使函数同步,那怎么办呢? ?

6 个答案:

答案 0 :(得分:16)

您可以使用deasync

function get_source_at(uri){
    var source;
    request({ uri:uri}, function (error, response, body) {
        source = body;
        console.log(body);
    });
    while(source === undefined) {
      require('deasync').runLoopOnce();
    }
    return source;
}

答案 1 :(得分:14)

您应该避免同步请求。如果您想要同步控制流程,可以使用async

async.waterfall([
    function(callback){
        data = get_source_at(uri);
        callback(null, data);
    },
    function(data,callback){
        process(data, callback);
    },
], function (err,result) {
    console.log(result)
});

process承诺在 get_source_at返回后运行。

答案 2 :(得分:8)

这是使用deasync的更好方法。

var request = require("request")
var deasync = require("deasync")

var getHtml = deasync(function (url, cb) {
   var userAgent = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36"}
   request({
      url: url, 
      headers: userAgent
   },
   function (err, resp, body) {
      if (err) { cb(err, null) }
      cb(null, body)
   })
})

var title = /<title>(.*?)<\/title>/

var myTitle = getHtml("http://www.yahoo.com").match(title)[1]
console.log(myTitle)

请参阅documentation of deasync,您会发现可以使用desync(function (n params, cb) {})
使cb(err, data)一起出现的功能。因此fs.readFile()类函数可以使用deasync函数轻松包装。但对于像request这样的函数,cb(err, data)不会再回来。您可以使用自定义cb(err, data)回调格式创建自己的函数(命名或匿名),就像我在上面的代码中所做的那样。通过这种方式,您可以通过等待回调cb(err, data)返回到不同的javascript层来强制几乎所有异步函数执行同步(如文档所述)。另外,请确保已通过cb(err, data)回调取消同步来解决所有退出功能的方法,否则程序将阻止。

希望,它可以帮助那里的人!

<强>更新
不要使用这种方式进行同步请求。使用Async / Await写入基于同步查找代码的promises。您可以使用request-promise-native npm模块来避免使用promises包装请求模块。

答案 3 :(得分:2)

具有简单的阻止功能是交互式开发的一大福音! sync函数(在下面定义)可以同步任何承诺,大大减少了使用API​​并学习它所需的语法量。例如,以下是如何将它与puppeteer库一起用于无头Chrome:

var browser = sync(puppeteer.connect({ browserWSEndpoint: "ws://some-endpoint"}));
var pages = sync(browser.pages())
pages.length
1
var page = pages[0]
sync(page.goto('https://duckduckgo.com', {waitUntil: 'networkidle2'}))
sync(page.pdf({path: 'webpage.pdf', format: 'A4'}))

最好的部分是,这些行中的每一行都可以进行调整,直到它完成您想要的操作,而无需在每次要测试时重新运行或重新键入所有以前的行。这是有效的,因为您可以直接访问顶级的browserpages变量。

以下是它的工作原理:

const deasync = require("deasync");
const sync = deasync((promise, callback) => promise.then(result) => callback(null, result)));

它使用其他答案中提到的deasync包。 deasync创建一个匿名函数的部分应用程序,它将callback作为最后一个参数添加,并阻塞直到callback被调用。 callback接收错误条件作为其第一个参数(如果有),结果作为第二个参数(如果有的话)。

答案 4 :(得分:1)

  

在继续我的应用程序的控制流之前,我必须有一种方法来确保我有来自uri的源代码 - 所以如果不是通过使函数同步,那怎么办呢?

鉴于您的申请入口点:

function app(body) {
    // Doing lots of rad stuff
}

你通过取身来踢它:

request({ uri: uri }, function (error, response, body) {
    if(err) return console.error(err);

    // Start application
    app(body);
}

这是在编写node.js(和一般的javascript)时必须习惯的东西。有像async这样的控制流模块(我也推荐),但你必须习惯继续传递样式,因为它被称为。

答案 5 :(得分:0)

好的,首先,要保持代码异步,您只需将相关代码放在请求函数的回调中,这意味着它将在请求完成后运行,但不会阻止处理器处理应用程序中的其他任务。如果您需要多次,我建议您查看Synchronous request in Node.js,其中概述了各种方法,以便更加简化并讨论各种控制流程库。