如何在 nodejs 中同步请求这个调用?

IT技术 javascript node.js request
2021-02-25 01:20:48

我的 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个回答

您可以使用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;
}

您应该避免同步请求。如果你想要类似同步控制流的东西,你可以使用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的回报。

你如何在下一个回调中使用“数据”?我试过了,但它没有显示任何东西。
2021-04-24 01:20:48
同意@aroth - 我将 nodejs 脚本用于自定义复杂部署任务,我需要按严格顺序执行每个命令。我可以使用 Promise,但then()如果你有 10 个以上的任务要严格按照顺序运行,那么即使是链接也会变得有些难看。
2021-04-29 01:20:48
“您应该避免同步请求”并不是一个准确的概括性声明。您应该避免在应用程序的主线程上执行同步请求,或者避免在会导致 UI 阻塞的情况下执行同步请求。但是在这种情况下,一个无头 Web 服务的唯一目的是委托给其他一些 Web 服务并报告结果?同步请求非常好,实际上比异步请求更可取/更干净。了解您的用例并选择最适合的解决方案很重要。这不是一个总是一个而不是另一个的情况。
2021-05-15 01:20:48
这不是这个问题的答案。
2021-05-17 01:20:48

这是使用 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)

请参考deasync的文档,你会发现,你可以使用
desync(function (n params, cb) {})
,使功能在那里cb应该回来与(err, data)所以fs.readFile()像函数可以很容易地用deasync函数包装但对于功能,如request不回来用cb(err, data)您可以使用自定义cb(err, data)回调格式创建自己的函数(命名或匿名),就像我在上面的代码中所做的那样。通过这种方式,您可以通过等待回调cb(err, data)返回到不同的 javascript 层(如文档所述)来强制几乎所有异步函数执行同步还要确保您已经涵盖了从使用 deasync 包装的函数中退出的所有方法cb(err, data)回调,否则你的程序将被阻塞。

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

更新:
不要使用这种方式进行同步请求。使用 Async/Await 编写基于 Promise 的同步查找代码。您可以使用request-promise-nativenpm module来避免自己Promise 包装请求module。

这是一个很好的解决方案。deasync 是更好和优雅的同步调用方式。
2021-05-07 01:20:48
请用你隐藏的知识让我们开悟。在评论中表达你反对的理由。谢谢!
2021-05-09 01:20:48

拥有一个简单的阻塞功能对于交互式开发来说是一个巨大的福音!sync函数(定义如下)可以同步任何Promise,显着减少使用 API 和学习 API 所需的语法数量。例如,以下是如何将它与无头 Chromepuppeteer一起使用

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接收错误条件作为其第一个参数(如果有),并将结果作为第二个参数(如果有)。

这对于不支持 async/await 的早期节点版本很有帮助。
2021-05-18 01:20:48

在继续我的应用程序的控制流之前,我必须有一种方法来确保我拥有来自 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 这样的控制流module(我也推荐它),但是你必须习惯continuation 传递 style,正如它所说的那样。