简体   繁体   English

多次调用异步函数

[英]Calling async function multiple times

So I have a method, which I want to call multiple times in a loop.所以我有一个方法,我想在循环中多次调用它。 This is the function:这是函数:

function PageSpeedCall(callback) {
    var pagespeedCall = `https://www.googleapis.com/pagespeedonline/v4/runPagespeed?url=https://${websites[0]}&strategy=mobile&key=${keys.pageSpeed}`;
    // second call
    var results = '';
    https.get(pagespeedCall, resource => {
        resource.setEncoding('utf8');
        resource.on('data', data => {
            results += data;
        });
        resource.on('end', () => {
            callback(null, results);
        });
        resource.on('error', err => {
            callback(err);
        });
    });
    // callback(null, );
}

As you see this is an async function that calls the PageSpeed API.如您所见,这是一个调用 PageSpeed API 的异步函数。 It then gets the response thanks to the callback and renders it in the view.然后它通过callback获得响应并将其呈现在视图中。 Now how do I get this to be work in a for/while loop?现在我如何让它在 for/while 循环中工作? For example例如

function PageSpeedCall(websites, i, callback) {
    var pagespeedCall = `https://www.googleapis.com/pagespeedonline/v4/runPagespeed?url=https://${websites[i]}&strategy=mobile&key=${keys.pageSpeed}`;
    // second call
    var results = '';
    https.get(pagespeedCall, resource => {
        resource.setEncoding('utf8');
        resource.on('data', data => {
            results += data;
        });
        resource.on('end', () => {
            callback(null, results);
        });
        resource.on('error', err => {
            callback(err);
        });
    });
    // callback(null, );
}

var websites = ['google.com','facebook.com','stackoverflow.com'];
for (let i = 0; i < websites.length; i++) {
    PageSpeedCall(websites, i);
}

I want to get a raport for each of these sites.我想为这些网站中的每一个获得一份报告。 The length of the array will change depending on what the user does.数组的长度将根据用户的操作而变化。

I am using async.parallel to call the functions like this:我正在使用async.parallel来调用这样的函数:

let freeReportCalls = [PageSpeedCall, MozCall, AlexaCall];

async.parallel(freeReportCalls, (err, results) => {
    if (err) {
        console.log(err);
    } else {
        res.render('reports/report', {
            title: 'Report',
            // bw: JSON.parse(results[0]),
            ps: JSON.parse(results[0]),
            moz: JSON.parse(results[1]),
            // pst: results[0],
            // mozt: results[1],
            // bw: results[1],
            al: JSON.parse(results[2]),
            user: req.user,
        });
    }
});

I tried to use promise chaining, but for some reason I cannot put it together in my head.我尝试使用承诺链,但由于某种原因,我无法将它放在我的脑海中。 This is my attempt.这是我的尝试。

return Promise.all([PageSpeedCall,MozCall,AlexaCall]).then(([ps,mz,al]) => {
    if (awaiting != null)
        var areAwaiting = true;
    res.render('admin/', {
        title: 'Report',
        // bw: JSON.parse(results[0]),
        ps: JSON.parse(results[0]),
        moz: JSON.parse(results[1]),
        // pst: results[0],
        // mozt: results[1],
        // bw: results[1],
        al: JSON.parse(results[2]),
        user: req.user,
    });
}).catch(e => {
    console.error(e)
});

I tried doing this:我尝试这样做:

return Promise.all([for(let i = 0;i < websites.length;i++){PageSpeedCall(websites, i)}, MozCall, AlexaCall]).
then(([ps, mz, al]) => {
    if (awaiting != null)
        var areAwaiting = true;
    res.render('admin/', {
        title: 'Report',
        // bw: JSON.parse(results[0]),
        ps: JSON.parse(results[0]),
        moz: JSON.parse(results[1]),
        // pst: results[0],
        // mozt: results[1],
        // bw: results[1],
        al: JSON.parse(results[2]),
        user: req.user,
    });
}).catch(e => {
    console.error(e)
});

But node just said it's stupid.但是节点只是说它很愚蠢。

And this would work if I didn't want to pass the websites and the iterator into the functions.如果我不想将网站和迭代器传递给函数,这将起作用。 Any idea how to solve this?知道如何解决这个问题吗?

To recap.回顾一下。 So far the functions work for single websites.到目前为止,这些功能适用于单个网站。 I'd like them to work for an array of websites.我希望他们为一系列网站工作。

I'm basically not sure how to call them, and how to return the responses.我基本上不知道如何调用它们,以及如何返回响应。

It's much easier if you use fetch and async/await如果你使用fetchasync/await容易多了

const fetch = require('node-fetch');

async function PageSpeedCall(website) {
    const pagespeedCall = `https://www.googleapis.com/pagespeedonline/v4/runPagespeed?url=https://${website}&strategy=mobile&key=${keys.pageSpeed}`;
    const result = await fetch(pagespeeddCall);
    return await result.json();
}


async function callAllSites (websites) {
  const results = [];
  for (const website of websites) {
    results.push(await PageSpeedCall(website));
  }
  return results;
}

callAllSites(['google.com','facebook.com','stackoverflow.com'])
  .then(results => console.log(results))
  .error(error => console.error(error));

Which is better with a Promise.all Promise.all 哪个更好

async function callAllSites (websites) {
  return await Promise.all(websites.map(website => PageSpeedCall(website));
}

Starting on Node 7.5.0 you can use native async/await:从 Node 7.5.0 开始,您可以使用本机 async/await:

async function PageSpeedCall(website) {
  var pagespeedCall = `https://www.googleapis.com/pagespeedonline/v4/runPagespeed?url=https://${website}&strategy=mobile&key=${keys.pageSpeed}`;
  return await promisify(pagespeedCall);
}

async function getResults(){
  const websites = ['google.com','facebook.com','stackoverflow.com'];

  return websites.map(website => {
    try {
      return await PageSpeedCall(website);
    }
    catch (ex) {
      // handle exception
    }
  })
}

Node http "callback" to promise function: 节点http“回调”到promise函数:

function promisify(url) {
  // return new pending promise
  return new Promise((resolve, reject) => {
    // select http or https module, depending on reqested url
    const lib = url.startsWith('https') ? require('https') : require('http');
    const request = lib.get(url, (response) => {
      // handle http errors
      if (response.statusCode < 200 || response.statusCode > 299) {
          reject(new Error('Failed to load page, status code: ' + response.statusCode));
        }
      // temporary data holder
      const body = [];
      // on every content chunk, push it to the data array
      response.on('data', (chunk) => body.push(chunk));
      // we are done, resolve promise with those joined chunks
      response.on('end', () => resolve(body.join('')));
    });
    // handle connection errors of the request
    request.on('error', (err) => reject(err))
  })
}

Make PageSpeedCall a promise and push that promise to an array as many times as you need, eg myArray.push(PageSpeedCall(foo)) then myArray.push(PageSpeedCall(foo2)) and so on.使PageSpeedCall成为一个承诺,并根据需要多次将该承诺推送到数组,例如myArray.push(PageSpeedCall(foo))然后myArray.push(PageSpeedCall(foo2))等等。 Then you Promise.all the array.然后你 Promise.all 数组。

If subsequent asynch calls require the result of a prior asynch call, that is what .then is for.如果后续的异步调用需要先前异步调用的结果,那就是.then的用途。

Promise.all() Promise.all()

 Promise.all([promise1, promise2, promise3]).then(function(values) { console.log(values); });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM