节点.js中的同步请求
Synchronous Requests in Node.js
如何在 Node 中制作"请求"模块.js以同步方式加载内容?我见过的最好的建议是以某种方式使用回调来让函数在完成之前不返回自身。我正在尝试在代码中使用内联的"request"函数(需要根据无法放置在回调中的数据进行处理(。
那么我如何使用"request"模块的回调来防止它在完成加载资源之前返回自身呢?
我正在做的是运行一个循环,从 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 */
}
简短的回答是:不要。(...)你真的不能。这是一件好事
我想就此澄清一下:
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) {}
当您在"同步请求"库上打开引擎盖时,您可以看到它在后台运行同步子进程。正如同步请求自述文件中所解释的那样,应该非常明智地使用它。这种方法会锁定主线程,这对性能不利。
但是,在某些情况下,编写异步解决方案几乎没有或根本没有优势(与编写更难阅读的代码造成的某些危害相比(。
这是其他语言(Python,Java,C#等(的许多HTTP请求库所持有的默认假设,并且该哲学也可以带到JavaScript中。语言毕竟是解决问题的工具,有时如果优点大于缺点,您可能不想使用回调。
对于 JavaScript 纯粹主义者来说,这可能是异端邪说,但我是一个实用主义者,所以我可以清楚地看到,如果您发现自己处于以下某些情况下,使用同步请求的简单性会有所帮助:
- 测试
自动化(测试本质上通常是同步的(。
快速的 API 混搭(即黑客马拉松、概念验证工作等(。
帮助初学者的简单示例(之前和之后(。
请注意,上面的代码不应用于生产。如果你要运行一个合适的API,那么使用回调,使用承诺,使用async/await,或者其他什么,但避免同步代码,除非你想在服务器上浪费CPU时间而产生巨大的成本。
> 在 2018 年,您可以使用 Node.js 中的 async
和 await
对"通常"样式进行编程。
下面是一个示例,它将请求回调包装在承诺中,然后使用 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();
尽管异步样式可能是 node 的本质.js通常您不应该这样做,但有时您需要这样做。
我正在编写一个方便的脚本来检查 API,并且不想用回调弄乱它。
Javascript 不能执行同步请求,但 C 库可以。
https://github.com/dhruvbird/http-sync
Aredridels 的答案相对较好(赞成它(,但我认为它缺乏循环等效项。这应该可以帮助您:
同步代码等效:
while (condition) {
var data = request(url);
<math here>
}
return result;
串行执行的异步代码:
function continueLoop() {
if (!condition) return cb(result);
request(url, function(err, res, body) {
<math here>
continueLoop()
})
}
continueLoop()
你应该看看名为异步的库
并尝试使用Async.series调用来解决您的问题。
请参阅同步请求:https://github.com/ForbesLindesay/sync-request
例:
var request = require('sync-request');
var res = request('GET', 'http://example.com');
console.log(res.getBody());
如今,如果你想按顺序做事,你会做这样的事情:
for (const task of tasks) {
const response = await request(...);
}
此代码(如上(按顺序运行请求,但不是同步的(这意味着它不会阻塞主线程(。如果你真的需要同步,那么这些库中的大多数都归结为:
const child = require('child_process');
const buffer = child.execSync(`curl https://example.com/foo.json`);
const data = JSON.parse(buffer.toString('utf8'));
retus
进行跨平台同步 HTTP 请求。这是一个基于 sync-request
的库,但我添加了一些舒适功能:
const retus = require("retus");
const { body } = retus("https://google.com");
//=> "<!doctype html>..."
就是这样!
你可以对请求库做一些完全相同的事情,但这是使用 const https = require('https');
或 const http = require('http');
进行同步,这应该随 node 一起提供。
这里有一个例子,
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();
我为自己想出的最简单的解决方案是使用该节点的本机"child_request",并在内部使用简单的 curl 命令简单地调用 exec。对于我只想"将 http 响应保存到节点中的变量"的简单罕见情况
class="answers"来说,所有依赖和异步性都让我太麻烦了>在撰写本文时,所有答案都是:
- 同步但使用控制流(例如使用异步库(
- 同步,但阻塞[这意味着Node上的所有其他线程都停止了,这在性能方面很糟糕],例如retus或sync-request。
- 已过时,例如 http-request。
查看基于取消同步的非阻塞同步请求。
或者查看此线程中的一些答案,例如直接使用 deasync 的答案。
简短的回答是:不要。如果你想要线性读取的代码,请使用像 seq 这样的库。但不要指望同步。你真的不能。这是一件好事。
几乎没有什么不能放在回调中。如果它们依赖于公共变量,请创建一个闭包来包含它们。手头的实际任务是什么?
您需要一个计数器,并且仅在数据存在时才调用回调:
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.
}
更新 2018:node.js 在最新版本中支持 async/await 关键字,并且使用将异步进程表示为 promise 的库,您可以等待它们。您可以通过程序获得线性、顺序的流程,并且在您等待时其他工作可以进行。它建造得很好,值得一试。
- 根据最新响应在 Node 中发送同步请求
- 同步请求谷歌地图地理编码
- 火狐插件 SDK 同步请求
- 以发送的相同顺序显示 AJAX 响应,而不使用同步请求
- jquery 1.4,同步请求
- 如何为JQuery$.ajax同步请求设置超时并执行某些操作
- 节点4.2.0 phantom stdout:NETWORK_ERR:XMLHttpRequest异常101:同步请求中
- 正在包装主干同步请求
- RequireJS:同步请求文本内容
- mongodb同步请求
- Marketo-Munchkin同步请求损害了JS的性能
- 节点.js中的同步请求
- 循环中与 ajax 的同步请求
- 用于缓存的Node.js同步请求
- js 1.10, jquery 2.1和同步请求
- AJAX同步请求和操作,同时等待
- 我如何在主干运行一个基本的GET /同步请求
- 为什么异步xmlhttprequest优于同步请求?
- 使用JavaScript同步请求图像
- HTTP同步请求阻止我的GIF在Chrome和IE中移动