多次调用异步函数

时间:2018-04-06 23:06:23

标签: javascript node.js express

所以我有一个方法,我想在循环中多次调用。这是功能:

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, );
}

如您所见,这是一个调用PageSpeed API的异步函数。然后它会得到callback的响应,并在视图中呈现它。现在我如何让它在for / while循环中工作?例如

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);
}

我想为每个网站获取一个raport。数组的长度将根据用户的操作而改变。

我正在使用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,
        });
    }
});

我试图使用承诺链,但由于某种原因,我不能把它放在我脑海里。这是我的尝试。

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)
});

我试过这样做:

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)
});

但节点只是说它很愚蠢。

如果我不想将网站和迭代器传递给函数,这将有效。知道如何解决这个问题吗?

回顾一下。到目前为止,这些功能适用于单个网站。我希望他们为一系列网站工作。

我基本上不确定如何调用它们,以及如何返回响应。

3 个答案:

答案 0 :(得分:5)

如果您使用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));

Promise.all

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

答案 1 :(得分:3)

Starting on Node 7.5.0你可以使用native 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:

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))
  })
}

答案 2 :(得分:1)

使PageSpeedCall成为承诺,并根据需要将该承诺推送到数组,例如myArray.push(PageSpeedCall(foo))然后myArray.push(PageSpeedCall(foo2))等等。然后你Promise.all数组。

如果后续的异步调用需要先前异步调用的结果,那就是.then的用途。

Promise.all()

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