如何调用3个异步请求?

时间:2019-06-24 17:35:05

标签: javascript node.js promise

我必须执行一项功能来测试3个API是否正在运行。 因此,用户将单击“测试API”按钮,它将返回每个API的状态(状态:200、500、404等)。如果API返回错误,则应显示错误堆栈。 屏幕示例:

API       Status      Detail
url1.com   200          -
url2.com   200          -
url3.com   500     internal server error

我的问题是,如何并行调用这3个请求并返回异步结果,我的意思是如何在不等待所有请求结果的情况下更新API请求状态的屏幕

我基于该How do I call three requests in order?,但它会同步返回结果。

*******编辑*****

那是我当前的代码

app.get('/testDependencies', function (req, res, next) {    

    let objTestsResul = {}        
    var urls = ['url1', 'url2', 'url3'];
    let index = 0
    while(urls.length > 0) {
      let url = urls.shift();
      objTestsResult[index++] = testURL(url)

   }

    res.send(objTestsResult)
});

每个URL的功能相同:

function testURL(URL){

   fetch(URL, {
        method: 'GET'      
    })
        .then(res => {
            res.json()            
        })
        .then(json => {
            console.log(json)
            return json      
         })
        .catch(error => {            
            return error
          })
}

3 个答案:

答案 0 :(得分:3)

Promisesmdn)似乎是您想要的。从本质上讲,它们是回调的可读性更高的版本,它使您可以在发生其他情况时执行代码,而不必在恢复执行之前等待该触发器发生。

let endpoint1 = () => new Promise(resolve => setTimeout(() => resolve('200'), 1000));
  let endpoint2 = () => new Promise(resolve => setTimeout(() => resolve('201'), 2000));
  let endpoint3 = () => new Promise(resolve => setTimeout(() => resolve('500'), 1500));

  document.getElementById('test').addEventListener('click', () => {
    document.getElementById('status').textContent = 'test running...';
    Promise.all([
      endpoint1().then(a => document.getElementById('result1').textContent = a),
      endpoint2().then(a => document.getElementById('result2').textContent = a),
      endpoint3().then(a => document.getElementById('result3').textContent = a),
    ]).then(() => document.getElementById('status').textContent = 'test complete');
  });
<button id="test">test</button>
<div>status: <span id="status">not running</span></div>
<div>endpoint 1: <span id="result1"></span></div>
<div>endpoint 2: <span id="result2"></span></div>
<div>endpoint 3: <span id="result3"></span></div>

答案 1 :(得分:1)

如果您可以使用Bluebird,这实际上非常简单:

const { Promise } = require('bluebird');

app.get('/testDependencies', function (req, res, next) {    
  Promise.map(['url1', 'url2', 'url3'], url => testURL(url)).then(results => {
     res.send(results);
  });
});

您只需要确保您的promise函数实际上返回了promise:

function testURL(URL) {
  let start_time = new Date().getTime();   

  return fetch(URL, {
    method: 'GET'      
  }).then(res => {
    res.json()            
  }).then(json => {
    console.log(json)
    return json      
  }).catch(error => {            
    return error
  })
}

除非已从链接所涉及的函数中显式返回它们,否则不能将依赖关系链接为依赖项。

如果您能够使用asyncawait,我还建议您这样做,这样可以大大简化原本很复杂的代码。

答案 2 :(得分:1)

Express无法发送多个响应。您将必须完成所有呼叫或使用WebSockets来传输数据。

function testURL(URL) {
  return new Promise((resolve, reject) => {
    if (URL === 'url2') {
      reject(new Error('Internal Server Error'));
      return;
    }
    resolve({ status: 200 });
  });
}

const main = async () => {
  const urls = ['url1', 'url2', 'url3'];

  // return resolved and rejected Promises because if one fails in Promise.all
  // the function will throw and we won't have any access to any resolved Promises.
  const results = await Promise.all(urls
    .map(url => testURL(url).then(response => response).catch(error => error)));

  // every error have a stack property, Set the status to whatever you want
  // based on the error and store the stack and the message
  const objTestsResul = results.reduce((result, cur, i) => {
    result[urls[i]] = cur.stack
      ? { status: 500, message: cur.message, stack: cur.stack }
      : cur;
    return result;
  }, {});

  console.log(objTestsResul);
};

main();