如何与NodeJS同步运行两个函数?

时间:2017-08-02 12:59:07

标签: javascript node.js

我对NodeJS很新,并且迷失了异步机制。

我有一个代码应该向第一个URL发送HTTP post请求(例如 - https://example.com/first),然后当它得到状态代码200的回答时,向同一个服务器发送另一个请求,检查是否服务器完成处理第一个请求(例如 - https://example.com/statusCheck)。

服务器应该返回一个text / plain响应包含" true"如果它很忙,"假"如果它准备好了。 我用一个while循环编写它,每2秒查询一次服务器,最多10次迭代。

var request = require('request');

var firstURL = "https://example.com/first";
var serverCheck = "https://example.com/statusCheck";

// Sends up to 10 requests to the server
function checkServerStatus(){
    var serverReady = false;
    var count = 0;
    while (!serverReady && count < 10) {
        count++;
        setTimeout(function(){
            request.get(serverCheck, function(err, resp, body){
                if (err){
                    console.log(err);
                } else if (body == "false") {
                    generatorReady = true;
                }
            })
        }, 2000);
    }
    return generatorReady;
}

// Sends the first request and return True if the response equals to 200
function sendFirstRequest(){
    var req = request.post(firstURL, function (err, resp, body) {
        if (err) {
            console.log(err);
            return false;
        } else if (resp.statusCode === 200){
            return true;
        } else {
            return false;
        }
    });
};


module.exports = function (){
    // Sends the first request
    var firstRequestStatus = sendFirstRequest();
    if (firstRequestStatus) {
        return checkServerStatus();
    }
};

换句话说,我想首先运行sendFirstRequest,等待响应,如果响应是true,我想运行checkServerStatus并让他返回值。如果可以在每次迭代之间进行休眠,那么它会很棒(因为setTimeout对我来说也不起作用。)

编辑:我听说我可以使用function* with yieldasync-await来避免回调地狱 - 在这种情况下如何实施?

4 个答案:

答案 0 :(得分:4)

你应该使用Promise来做到这一点。下面是使用bluebird的一些代码,它们可以执行您想要的操作。 Promise.any方法将从10次尝试中返回Array中第一次成功调用。

const Promise = require('bluebird');
var request = Promise.promisifyAll(require('request'));

var firstURL = "https://example.com/";
var serverCheck = "https://example.com/statusCheck";

request.postAsync(firstURL).then(res => {
  if (res.statusCode === 200) return true;
  throw new Error('server not ready');
}).then(() =>  
  Promise.any(new Array(10).fill(request.getAsync(serverCheck)))
).then(res => {
  console.log(res);
}).catch(err => console.log(err));

答案 1 :(得分:1)

您必须了解异步操作无法在调用后立即返回结果。它们在执行时会触发一些处理程序。您可以/应该使用该入口点来启动或继续您​​的逻辑流程。

http.post(params, handler(err, resp, body){
      if(err){
        failFlow(err);
      }else if(resp.statusCode === 200) {
        successFlow(resp); 
      }
});

您可以根据需要链接尽可能多的此类异步调用,但不能以这种方式返回响应。

您也可能对Promise的概念感兴趣。

&#13;
&#13;
var request = require('request');

var firstURL = "https://example.com/first";
var serverCheck = "https://example.com/statusCheck";
var count = 0;

// Sends up to 10 requests to the server
function checkServerStatus() {
  if (count++ > 10) return;

  request.get(serverCheck, function(err, resp, body) {
    if (err) {
      console.log(err);
      checkServerStatus();
    } else if (body == "false") {
      // go further
    }
  });
}

// Sends the first request and return True if the response equals to 200
function sendFirstRequest(cb) {
  var req = request.post(firstURL, function(err, resp, body) {
    if (err) {
      console.log(err);
      return false;
    } else if (resp.statusCode === 200) {
      cb();
    } else {
      return false;
    }
  });
};


module.exports = function() {
  // Sends the first request
  sendFirstRequest(checkServerStatus);
};
&#13;
&#13;
&#13;

答案 2 :(得分:0)

您可以使用async库。

你不需要为此做一个setInterval或任何计时器,只需等待响应。

具体来说,您可以使用async.waterfall,例如:

<div class="container">
  <h2>Select a Console</h2>
  <div class="col-lg-4 consoleRed">
    <div class="consoleIcon"><img width="64" height="64" src="images/3ds.png"></div>
    <div class="consoleDesc">Little Text is fine</div>
    <div class="clearfix"></div>
  </div>
  <div class="col-lg-4 consoleRed">
    <div class="consoleIcon"><img width="64" height="64" src="images/3ds.png"></div>
    <div class="consoleDesc">When i add too much text it ends up pushing the whole div onto the new line When i add too much text it ends up pushing the whole div onto the new line When i add too much text it ends up pushing the whole div onto the new line When i add too much text it ends up pushing the whole div onto the new line</div>
    <div class="clearfix"></div>
  </div>
  <div class="col-lg-4 consoleRed">
    <div class="consoleIcon"><img width="64" height="64" src="images/3ds.png"></div>
    <div class="consoleDesc">Not sure why</div>
    <div class="clearfix"></div>
  </div>
</div>

答案 3 :(得分:0)

async function main() {
  console.log('First call started');
  let response1 = await $.ajax({url: "https://api.stackexchange.com/2.2/questions/269754/answers/?order=desc&site=meta.stackoverflow&client_id=3519&callback=?"})
  console.log('First call finished', response1);
  console.log('Second call started');
  let response2 = await $.ajax({url: "https://api.stackexchange.com/2.2/questions/269754/answers/?order=desc&site=meta.stackoverflow&client_id=3519&callback=?"})
  console.log('Second call finished',response2);
}

main();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

在较新版本的nodejs中,您可以像上面的示例一样使用async await

请注意,$ .ajax不是节点功能。它仅用于演示

您可以对任何返回promise的函数使用await。 对于下一个示例,您需要安装请求包并使用Node&gt; = 8来使用promisify

const {promisify} = require('util');
const request = require('request')

async function main() {
    let get = promisify(request);
    let response1 = await get('https://www.random.org/integers/?num=1&min=1&max=100&col=1&base=10&format=plain&rnd=new');
    console.log('first random: ',response1.body)
    let response2 = await get('https://www.random.org/integers/?num=1&min=1&max=100&col=1&base=10&format=plain&rnd=new');
    console.log('second random: ',response2.body)
}

main();

http://2ality.com/2017/05/util-promisify.html

https://github.com/request/request