Javascript Node.js 中的同步请求
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8775262/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Synchronous Requests in Node.js
提问by Kyle Hotchkiss
How could I make the 'request' module in Node.js load things in a synchronous fashion? The best advice I've seen is to somehow use the callback to get the function to not return itself until it is done. I am trying to use the 'request' function inline in code (things need to be processed based on that data that can't be placed in callbacks).
我怎样才能让 Node.js 中的“请求”模块以同步方式加载东西?我见过的最好的建议是以某种方式使用回调来让函数在完成之前不返回自身。我正在尝试在代码中使用内联的“请求”函数(需要根据无法放置在回调中的数据来处理事情)。
So how could I use the callback of the 'request' module to keep it from returning itself until it is finished with loading the resource?
那么我如何使用“请求”模块的回调来防止它在加载资源完成之前返回自身?
What I'm doing is running a loop that downloads two values from an API, and then has to do some math based on those values. While the math could be done in callbacks... the loop would advance without the values it needs to perform the next operation. (So stopping the loop from advancing until the data is ready would solve the issue)
我正在做的是运行一个循环,从 API 下载两个值,然后必须根据这些值进行一些数学运算。虽然数学可以在回调中完成......循环将在没有执行下一个操作所需的值的情况下前进。(所以停止循环前进直到数据准备好将解决问题)
/* loop */ {
/* URL Generation */
request( {url: base + u_ext}, function( err, res, body ) {
var split1 = body.split("\n");
var split2 = split1[1].split(", ");
ucomp = split2[1];
});
request( {url: base + v_ext}, function( err, res, body ) {
var split1 = body.split("\n");
var split2 = split1[1].split(", ");
vcomp = split2[1];
});
/* math which needs to be after functions get variables and before loop advances */
}
采纳答案by Timo
In 2018, you can program the "usual" style using async
and await
in Node.js.
在 2018 年,您可以使用Node.js 中的async
和await
编写“通常”样式。
Below is an example, that wraps request callback in a promise and then uses await
to get the resolved value.
下面是一个示例,它将请求回调包装在一个 Promise 中,然后用于await
获取解析值。
const request = require('request');
// wrap a request in an promise
function downloadPage(url) {
return new Promise((resolve, reject) => {
request(url, (error, response, body) => {
if (error) reject(error);
if (response.statusCode != 200) {
reject('Invalid status code <' + response.statusCode + '>');
}
resolve(body);
});
});
}
// now to program the "usual" way
// all you need to do is use async functions and await
// for functions returning promises
async function myBackEndLogic() {
try {
const html = await downloadPage('https://microsoft.com')
console.log('SHOULD WORK:');
console.log(html);
// try downloading an invalid url
await downloadPage('http:// .com')
} catch (error) {
console.error('ERROR:');
console.error(error);
}
}
// run your async function
myBackEndLogic();
回答by Steven de Salas
The short answer is: don't. (...) You really can't. And that's a good thing
简短的回答是:不要。(...) 你真的不能。这是一件好事
I'd like to set the record straight regarding this:
我想就此澄清一下:
NodeJS doessupport Synchronous Requests. It wasn't designed to support them out of the box, but there are a few workarounds if you are keen enough, here is an example:
NodeJS确实支持同步请求。它的设计初衷不是为了支持它们,但是如果您足够敏锐,有一些解决方法,以下是一个示例:
var request = require('sync-request'),
res1, res2, ucomp, vcomp;
try {
res1 = request('GET', base + u_ext);
res2 = request('GET', base + v_ext);
ucomp = res1.split('\n')[1].split(', ')[1];
vcomp = res2.split('\n')[1].split(', ')[1];
doSomething(ucomp, vcomp);
} catch (e) {}
When you pop the hood open on the 'sync-request' library you can see that this runs a synchronous child processin the background. And as is explained in the sync-request READMEit should be used veryjudiciously. This approach locks the main thread, and that is bad for performance.
当您在“同步请求”库上打开引擎盖时,您可以看到它在后台运行一个同步子进程。正如在同步请求自述文件中所解释的那样,应该非常明智地使用它。这种方法锁定主线程,这对性能不利。
However, in some cases there is little or no advantage to be gained by writing an asynchronous solution (compared to the certain harm you are doing by writing code that is harder to read).
但是,在某些情况下,编写异步解决方案几乎没有优势(与编写更难阅读的代码所造成的某些危害相比)。
This is the default assumption held by many of the HTTP request libraries in other languages (Python, Java, C# etc), and that philosophy can also be carried to JavaScript. A language is a tool for solving problems after all, and sometimes you may not wantto use callbacks if the benefits outweigh the disadvantages.
这是许多其他语言(Python、Java、C# 等)的 HTTP 请求库所持有的默认假设,并且这种理念也可以应用于 JavaScript。语言毕竟是解决问题的工具,如果利大于弊,有时您可能不想使用回调。
For JavaScript purists this may rankle of heresy, but I'm a pragmatist so I can clearly see that the simplicity of using synchronous requests helps if you find yourself in some of the following scenarios:
对于 JavaScript 纯粹主义者来说,这可能是异端邪说,但我是一个实用主义者,所以我可以清楚地看到,如果您发现自己处于以下某些场景中,使用同步请求的简单性会有所帮助:
Test Automation(tests are usually synchronous by nature).
Quick API mash-ups(ie hackathon, proof of concept works etc).
Simple examples to help beginners(before and after).
测试自动化(测试通常本质上是同步的)。
快速 API 混搭(即黑客马拉松、概念验证等)。
帮助初学者的简单示例(之前和之后)。
Be warned that the code above should notbe used for production. If you are going to run a proper API then use callbacks, use the async library, use promises or whatever, but avoid synchronous code unless you want to incur a significant cost for wasted CPU time on your server.
请注意,上面的代码不应用于生产。如果您要运行适当的 API,则使用回调、使用异步库、使用 Promise 或其他任何东西,但避免同步代码,除非您想因浪费服务器上的 CPU 时间而产生大量成本。
回答by aredridel
The short answer is: don't. If you want code that reads linearly, use a library like seq. But just don't expect synchronous. You really can't. And that's a good thing.
简短的回答是:不要。如果您想要线性读取的代码,请使用像 seq 这样的库。但不要指望同步。你真的不能。这是一件好事。
There's little or nothing that can't be put in a callback. If they depend on common variables, create a closure to contain them. What's the actual task at hand?
很少或没有东西不能放在回调中。如果它们依赖于公共变量,则创建一个闭包来包含它们。手头的实际任务是什么?
You'd want to have a counter, and only call the callback when the data is there:
你想要一个计数器,并且只有在数据存在时才调用回调:
var waiting = 2;
request( {url: base + u_ext}, function( err, res, body ) {
var split1 = body.split("\n");
var split2 = split1[1].split(", ");
ucomp = split2[1];
if(--waiting == 0) callback();
});
request( {url: base + v_ext}, function( err, res, body ) {
var split1 = body.split("\n");
var split2 = split1[1].split(", ");
vcomp = split2[1];
if(--waiting == 0) callback();
});
function callback() {
// do math here.
}
Update 2018: node.js supports async/await keywords in recent editions, and with libraries that represent asynchronous processes as promises, you can await them. You get linear, sequential flow through your program, and other work can progress while you await. It's pretty well built and worth a try.
2018 年更新:node.js 在最近的版本中支持 async/await 关键字,并且使用将异步进程表示为承诺的库,您可以等待它们。您可以通过程序获得线性的、顺序的流程,并且在您等待的同时其他工作可以进行。它构建得非常好,值得一试。
回答by Aleksandar Vucetic
回答by thejh
Aredridels answer is relatively good (upvoted it), but I think it lacks the loop equivalent. This should help you:
Aredridels 的回答比较好(赞成),但我认为它缺少等效的循环。这应该可以帮助您:
Sync code equivalent:
同步代码等效:
while (condition) {
var data = request(url);
<math here>
}
return result;
Async code for serial execution:
串行执行的异步代码:
function continueLoop() {
if (!condition) return cb(result);
request(url, function(err, res, body) {
<math here>
continueLoop()
})
}
continueLoop()
回答by 9re
Though asynchronous style may be the nature of node.js and generally you should not do this, there are some times you want to do this.
尽管异步风格可能是 node.js 的本质,通常您不应该这样做,但有时您还是想这样做。
I'm writing a handy script to check an API and want not to mess it up with callbacks.
我正在编写一个方便的脚本来检查 API 并且不想将它与回调混淆。
Javascript cannot execute synchronous requests, but C libraries can.
Javascript 不能执行同步请求,但 C 库可以。
回答by Richie Bendall
回答by user2262111
You can do something exactly similar with the request library, but this is sync using const https = require('https');
or const http = require('http');
, which should come with node.
你可以用 request 库做一些完全相似的事情,但这是使用const https = require('https');
or同步的const http = require('http');
,它应该与 node.js 一起使用。
Here is an example,
这是一个例子,
const https = require('https');
const http_get1 = {
host : 'www.googleapis.com',
port : '443',
path : '/youtube/v3/search?arg=1',
method : 'GET',
headers : {
'Content-Type' : 'application/json'
}
};
const http_get2 = {
host : 'www.googleapis.com',
port : '443',
path : '/youtube/v3/search?arg=2',
method : 'GET',
headers : {
'Content-Type' : 'application/json'
}
};
let data1 = '';
let data2 = '';
function master() {
if(!data1)
return;
if(!data2)
return;
console.log(data1);
console.log(data2);
}
const req1 = https.request(http_get1, (res) => {
console.log(res.headers);
res.on('data', (chunk) => {
data1 += chunk;
});
res.on('end', () => {
console.log('done');
master();
});
});
const req2 = https.request(http_get2, (res) => {
console.log(res.headers);
res.on('data', (chunk) => {
data2 += chunk;
});
res.on('end', () => {
console.log('done');
master();
});
});
req1.end();
req2.end();