Node.js中的同步请求

Kyl*_*iss 39 javascript node.js

我如何使Node.js中的'request'模块以同步方式加载?我看到的最好的建议是以某种方式使用回调来使函数在完成之前不返回自身.我试图在代码中内联使用'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 */
    }
Run Code Online (Sandbox Code Playgroud)

Ste*_*las 51

简短的回答是:不要.(...)你真的不能.这是一件好事

我想直截了当地记录下来:

的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) {}
Run Code Online (Sandbox Code Playgroud)

当您在'sync-request'库中打开引擎盖时,您可以看到它在后台运行同步子进程.正如在sync-request README中所解释的那样,它应该非常明智地使用.这种方法锁定主线程,这对性能不利.

但是,在某些情况下,通过编写异步解决方案几乎没有或没有优势(与通过编写难以阅读的代码所做的某些伤害相比).

这是许多其他语言(Python,Java,C#等)中的HTTP请求库所持有的默认假设,并且该哲学也可以传递给JavaScript.语言毕竟是解决问题的工具,有时候如果好处大于缺点,你可能不想使用回调.

对于JavaScript纯粹主义者来说,这可能是异端邪说,但我是一个实用主义者,所以我可以清楚地看到,如果您发现自己处于以下某些情况中,使用同步请求的简单性会有所帮助:

  1. 测试自动化(测试通常是同步的).

  2. 快速API混搭(即黑客马拉松,概念验证等).

  3. 帮助初学者(之前和之后)的简单示例.

请注意,上述代码应用于生产.如果要运行适当的API然后使用回调,使用异步库,使用promises或其他,但避免同步代码,除非您想在服务器上浪费大量的CPU时间.

  • 我知道这是超级陈旧的,但我无法相信没有人给你非常好的答案.老实说,关于节点开发人员(即使我是一个人)最让我感到愤怒的是近视人如何/应该如何使用它.同步执行是框中的工具(有时是重要的工具),就像其他任何东西一样. (13认同)
  • 感谢上帝我找到了这个答案。就我而言,我想在服务器崩溃之前调用另一台服务器。我根本无法在 `process.on('uncaughtException')` 中异步执行任何东西,因为事件循环似乎没有等待它完成,所以我希望我的服务器在 HTTP 请求之后崩溃并关闭完成的。 (3认同)
  • 如果同步代码真的这么糟糕,他们早就从节点的 fs 库中删除了 fs.readFileSync 和朋友。这些同步方法使某些代码变得更加简单,并且在适当的时候使用起来更有意义。我们不要把所有意识形态都强加在人们身上!有时我需要代码在继续之前等待结果。告诉提问者他们的 SO 问题无效只是一个糟糕的答案,应该被严重否决。难以置信。 (2认同)

Tim*_*imo 35

在2018年,您可以在Node.js中使用asyncawait编写"通常"样式.

下面是一个示例,它在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();
Run Code Online (Sandbox Code Playgroud)

  • 这并没有真正回答问题,即如何使用node.js同步加载数据。 (5认同)
  • 但这实际上并不等待请求的响应或错误,然后再继续属于它的功能... (2认同)

are*_*del 10

简短的回答是:不要.如果您想要线性读取的代码,请使用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.
}
Run Code Online (Sandbox Code Playgroud)

更新2018:node.js支持最新版本中的async/await关键字,并且使用表示异步进程作为promise的库,您可以等待它们.通过程序可以获得线性,顺序的流程,等待时可以继续进行其他工作.它构造得非常好,值得一试.

  • 我的一个很大的烦恼就是SO答案,说"简短的回答是:不要" (21认同)
  • 不是特别有用的答案IMO ...我正在验证用户输入,我需要根据API调用返回true或false,而CLI等待它是否可以继续.不确定如何从异步调用中受益,非常累人查找有效问题并让人们告诉你他们认为你应该在概念上做某事而不是回答问题只是没有增加价值. (3认同)
  • 这个答案应该被删除,它没有回答问题。 (3认同)
  • 运行一个循环,必须从API下载两个不同的值并对其进行操作.数学可以在回调中完成......但是循环会向前移动而没有在回调中计算的数据,这有点带来了新的问题. (2认同)
  • “不要”不是这个问题的解决方案。F (2认同)

9re*_*9re 7

尽管异步风格可能是 node.js 的本质,通常您不应该这样做,但有时您还是想这样做。

我正在编写一个方便的脚本来检查 API 并且不想将它与回调混淆。

Javascript 不能执行同步请求,但 C 库可以。

https://github.com/dhruvbird/http-sync

  • *最后* - 异步很棒,但回调地狱等待着那些需要顺序请求的人,这些请求的 url 取决于最后一个响应。尝试异步发出数百个 HTTP 请求!谢谢,我会在这个上传播这个词。 (4认同)

Ale*_*tic 6

你应该看一下名为async的

并尝试使用async.series调用您的问题.


the*_*ejh 5

Aredridels答案相对较好(upvoted it),但我认为它缺少循环等效.这应该可以帮到你:

同步代码等效:

while (condition) {
  var data = request(url);
  <math here>
}
return result;
Run Code Online (Sandbox Code Playgroud)

串行执行的异步代码:

function continueLoop() {
  if (!condition) return cb(result);
  request(url, function(err, res, body) {
    <math here>
    continueLoop()
  })
}
continueLoop()
Run Code Online (Sandbox Code Playgroud)