Node.js 中的同步请求

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6048504/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 14:11:30  来源:igfitidea点击:

Synchronous request in Node.js

node.jssynchronization

提问by Howard

If I need to call 3 http API in sequential order, what would be a better alternative to the following code:

如果我需要按顺序调用 3 个 http API,那么以下代码的更好替代方法是什么:

http.get({ host: 'www.example.com', path: '/api_1.php' }, function(res) { 
  res.on('data', function(d) { 

    http.get({ host: 'www.example.com', path: '/api_2.php' }, function(res) { 
      res.on('data', function(d) { 

        http.get({ host: 'www.example.com', path: '/api_3.php' }, function(res) { 
          res.on('data', function(d) { 


          });
        });
        }
      });
    });
    }
  });
});
}

采纳答案by Raynos

Using deferreds like Futures.

使用像Futures.

var sequence = Futures.sequence();

sequence
  .then(function(next) {
     http.get({}, next);
  })
  .then(function(next, res) {
     res.on("data", next);
  })
  .then(function(next, d) {
     http.get({}, next);
  })
  .then(function(next, res) {
    ...
  })

If you need to pass scope along then just do something like this

如果您需要传递范围,那么只需执行以下操作

  .then(function(next, d) {
    http.get({}, function(res) {
      next(res, d);
    });
  })
  .then(function(next, res, d) { })
    ...
  })

回答by Josh

I like Raynos' solution as well, but I prefer a different flow control library.

我也喜欢 Raynos 的解决方案,但我更喜欢不同的流控制库。

https://github.com/caolan/async

https://github.com/caolan/async

Depending on whether you need the results in each subsequent function, I'd either use series, parallel, or waterfall.

根据您是否需要每个后续函数中的结果,我将使用串行、并行或瀑布。

Serieswhen they have to be serially executed, but you don't necessarily need the results in each subsequent function call.

当它们必须被串行执行时使用系列,但您不一定需要每个后续函数调用中的结果。

Parallelif they can be executed in parallel, you don't need the results from each during each parallel function, and you need a callback when all have completed.

Parallel如果它们可以并行执行,则在每个并行函数期间不需要每个结果,并且在所有完成后都需要回调。

Waterfallif you want to morph the results in each function and pass to the next

Waterfall如果你想改变每个函数中的结果并传递给下一个

endpoints = 
 [{ host: 'www.example.com', path: '/api_1.php' },
  { host: 'www.example.com', path: '/api_2.php' },
  { host: 'www.example.com', path: '/api_3.php' }];

async.mapSeries(endpoints, http.get, function(results){
    // Array of results
});

回答by Oleg

You could do this using my Common Node library:

你可以使用我的公共节点库来做到这一点:

function get(url) {
  return new (require('httpclient').HttpClient)({
    method: 'GET',
      url: url
    }).finish().body.read().decodeToString();
}

var a = get('www.example.com/api_1.php'), 
    b = get('www.example.com/api_2.php'),
    c = get('www.example.com/api_3.php');

回答by jemiloii

sync-request

同步请求

By far the most easiest one I've found and used is sync-requestand it supports both node and the browser!

到目前为止,我发现并使用的最简单的一种是同步请求,它同时支持节点和浏览器!

var request = require('sync-request');
var res = request('GET', 'http://google.com');
console.log(res.body.toString('utf-8'));

That's it, no crazy configuration, no complex lib installs, although it does have a lib fallback. Just works. I've tried other examples here and was stumped when there was much extra setup to do or installs didn't work!

就是这样,没有疯狂的配置,没有复杂的 lib 安装,尽管它有一个 lib 回退。只是工作。我在这里尝试了其他示例,但当有很多额外的设置要做或安装不起作用时被难住了!

Notes:

笔记:

The example that sync-requestuses doesn't play nice when you use res.getBody(), all get body does is accept an encoding and convert the response data. Just do res.body.toString(encoding)instead.

同步请求使用的示例在您使用时效果不佳res.getBody(),get body 所做的只是接受编码并转换响应数据。只是做res.body.toString(encoding)

回答by generalhenry

I'd use a recursive function with a list of apis

我会使用带有 apis 列表的递归函数

var APIs = [ '/api_1.php', '/api_2.php', '/api_3.php' ];
var host = 'www.example.com';

function callAPIs ( host, APIs ) {
  var API = APIs.shift();
  http.get({ host: host, path: API }, function(res) { 
    var body = '';
    res.on('data', function (d) {
      body += d; 
    });
    res.on('end', function () {
      if( APIs.length ) {
        callAPIs ( host, APIs );
      }
    });
  });
}

callAPIs( host, APIs );

edit: request version

编辑:请求版本

var request = require('request');
var APIs = [ '/api_1.php', '/api_2.php', '/api_3.php' ];
var host = 'www.example.com';
var APIs = APIs.map(function (api) {
  return 'http://' + host + api;
});

function callAPIs ( host, APIs ) {
  var API = APIs.shift();
  request(API, function(err, res, body) { 
    if( APIs.length ) {
      callAPIs ( host, APIs );
    }
  });
}

callAPIs( host, APIs );

edit: request/async version

编辑:请求/异步版本

var request = require('request');
var async = require('async');
var APIs = [ '/api_1.php', '/api_2.php', '/api_3.php' ];
var host = 'www.example.com';
var APIs = APIs.map(function (api) {
  return 'http://' + host + api;
});

async.eachSeries(function (API, cb) {
  request(API, function (err, res, body) {
    cb(err);
  });
}, function (err) {
  //called when all done, or error occurs
});

回答by Nate

Another possibility is to set up a callback that tracks completed tasks:

另一种可能性是设置一个回调来跟踪已完成的任务:

function onApiResults(requestId, response, results) {
    requestsCompleted |= requestId;

    switch(requestId) {
        case REQUEST_API1:
            ...
            [Call API2]
            break;
        case REQUEST_API2:
            ...
            [Call API3]
            break;
        case REQUEST_API3:
            ...
            break;
    }

    if(requestId == requestsNeeded)
        response.end();
}

Then simply assign an ID to each and you can set up your requirements for which tasks must be completed before closing the connection.

然后只需为每个人分配一个 ID,您就可以设置要求,在关闭连接之前必须完成哪些任务。

const var REQUEST_API1 = 0x01;
const var REQUEST_API2 = 0x02;
const var REQUEST_API3 = 0x03;
const var requestsNeeded = REQUEST_API1 | REQUEST_API2 | REQUEST_API3;

Okay, it's not pretty. It is just another way to make sequential calls. It's unfortunate that NodeJS does not provide the most basic synchronous calls. But I understand what the lure is to asynchronicity.

好吧,它不漂亮。这只是进行顺序调用的另一种方式。很遗憾,NodeJS 没有提供最基本的同步调用。但我明白异步性的诱惑是什么。

回答by Alexey Petrushin

It seems solutions for this problem is never-ending, here's one more :)

这个问题的解决方案似乎永无止境,这里还有一个:)

// do it once.
sync(fs, 'readFile')

// now use it anywhere in both sync or async ways.
var data = fs.readFile(__filename, 'utf8')

http://alexeypetrushin.github.com/synchronize

http://alexeypetrushin.github.com/synchronize

回答by Andy Shin

use sequenty.

使用顺序。

sudo npm install sequenty

须藤 npm 安装顺序

or

或者

https://github.com/AndyShin/sequenty

https://github.com/AndyShin/sequenty

very simple.

很简单。

var sequenty = require('sequenty'); 

function f1(cb) // cb: callback by sequenty
{
  console.log("I'm f1");
  cb(); // please call this after finshed
}

function f2(cb)
{
  console.log("I'm f2");
  cb();
}

sequenty.run([f1, f2]);

also you can use a loop like this:

你也可以使用这样的循环:

var f = [];
var queries = [ "select .. blah blah", "update blah blah", ...];

for (var i = 0; i < queries.length; i++)
{
  f[i] = function(cb, funcIndex) // sequenty gives you cb and funcIndex
  {
    db.query(queries[funcIndex], function(err, info)
    {
       cb(); // must be called
    });
  }
}

sequenty.run(f); // fire!

回答by Ricardo Tomasi

Using the requestlibrary can help minimize the cruft:

使用请求库可以帮助最大程度地减少麻烦:

var request = require('request')

request({ uri: 'http://api.com/1' }, function(err, response, body){
    // use body
    request({ uri: 'http://api.com/2' }, function(err, response, body){
        // use body
        request({ uri: 'http://api.com/3' }, function(err, response, body){
            // use body
        })
    })
})

But for maximum awesomeness you should try some control-flow library like Step - it will also allow you to parallelize requests, assuming that it's acceptable:

但是为了获得最大的效果,你应该尝试一些像 Step 这样的控制流库 - 它也允许你并行化请求,假设它是可以接受的:

var request = require('request')
var Step    = require('step')

// request returns body as 3rd argument
// we have to move it so it works with Step :(
request.getBody = function(o, cb){
    request(o, function(err, resp, body){
        cb(err, body)
    })
}

Step(
    function getData(){
        request.getBody({ uri: 'http://api.com/?method=1' }, this.parallel())
        request.getBody({ uri: 'http://api.com/?method=2' }, this.parallel())
        request.getBody({ uri: 'http://api.com/?method=3' }, this.parallel())
    },
    function doStuff(err, r1, r2, r3){
        console.log(r1,r2,r3)
    }
)

回答by vdegenne

As of 2018 and using ES6 modules and Promises, we can write a function like that :

截至 2018 年,使用 ES6 模块和 Promises,我们可以编写这样的函数:

import { get } from 'http';

export const fetch = (url) => new Promise((resolve, reject) => {
  get(url, (res) => {
    let data = '';
    res.on('end', () => resolve(data));
    res.on('data', (buf) => data += buf.toString());
  })
    .on('error', e => reject(e));
});

and then in another module

然后在另一个模块中

let data;
data = await fetch('http://www.example.com/api_1.php');
// do something with data...
data = await fetch('http://www.example.com/api_2.php');
// do something with data
data = await fetch('http://www.example.com/api_3.php');
// do something with data

The code needs to be executed in an asynchronous context (using asynckeyword)

代码需要在异步上下文中执行(使用async关键字)