我的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获得源代码 - 所以如果不是通过使函数同步,那怎么办呢? ?
答案 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'}))
最好的部分是,这些行中的每一行都可以进行调整,直到它完成您想要的操作,而无需在每次要测试时重新运行或重新键入所有以前的行。这是有效的,因为您可以直接访问顶级的browser
和pages
变量。
以下是它的工作原理:
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,其中概述了各种方法,以便更加简化并讨论各种控制流程库。