2012-03-27 113 views
17

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

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

另外,我已经阅读了关于“事件”以及节点是如何“放弃”的,我应该在编写我的代码时尊重它。我很乐意这样做,但是我必须有一种方法来确保我有一个来自uri的源代码,然后才能继续控制应用程序的流程 - 所以如果这不是通过使该功能同步,那该如何做?

+0

虽然赖的答案在技术上是正确的(所以我将其标记为答案),但我最终的解决方案需要更多的工作。如果您有不确定数量的呼叫请求,则可以使用https://gist.github.com/2234466 – Trindaz 2012-03-29 08:53:01

回答

16

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

+16

中找到的示例代码中的模式“您应该避免同步请求”不是准确的总括声明。您应该避免在应用程序的主线程上执行同步请求,否则会导致您的UI被阻塞。但在说的情况下,一个无头Web服务,其唯一目的是委托给其他Web服务并报告结果?有一个同步请求是非常好的,事实上,对于异步请求来说,它更好/更清晰。了解您的使用情况并选择最适合的解决方案非常重要。这不是一个永远只有一个,永远不会是另一个的情况。 – aroth 2017-04-20 05:49:25

+1

同意@aroth - 我使用nodejs脚本进行自定义复杂部署任务,我需要按严格顺序执行每个命令。我可以使用承诺,但是如果你有超过10个任务按照严格的顺序运行,那么即使'then()'链接也会变得有些难看。 – JustAMartin 2017-11-17 16:42:59

+0

这不是这个问题的答案。 – 2017-12-03 20:11:50

0

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

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)。有喜欢异步控制流模块(我也一样,建议),但你必须要习惯延续传递风格,因为它被称为。

14

您可以用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; 
} 
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)回调进行deasync包装的功能中脱身,否则你的程序将被阻止。

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

更新:
不要使用这种做同步请求的方式。使用Async/Await写入基于同步代码的promise。您可以使用request-promise-native npm模块来避免自己承诺包装请求模块。

+1

请让我们开启您隐藏的知识。在评论中表达你对downvote的理由。谢谢! – 2016-11-20 21:58:53

+1

这是很好的解决方案。 deasync是更好,更优雅的同步呼叫方式。 – Shad 2016-12-10 07:57:00

1

拥有一个简单的阻塞函数对交互式开发来说是一个很大的福音! 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接收错误条件作为其第一个参数(如果有),并将结果作为第二个参数(如果有的话)。

+0

这对于不支持异步/等待的较早节点版本有帮助。 – 2018-01-26 02:18:52