在JavaScript中重构异步函数

时间:2019-11-21 11:56:04

标签: javascript node.js async-await axios

我编写了一个程序来提取链接以分三步下载照片:

  1. getPersons()函数获取要遍历的人员的完整列表。
  2. 从人员列表中获取照片下载链接。
  3. 从步骤2中创建的列表中下载。

我正在尝试将步骤2重构为异步功能。 有没有简单的方法可以将第二步重构为一个函数,以使代码更具可读性?

理想情况下,我想检索所有链接,然后才开始下载。

const axios = require("axios");
const cheerio = require("cheerio");

const url = "https://www.website.com";

const persons = [];

async function getPersons() {
  await axios.get(url).then(response => {
    const html = response.data;
    const $ = cheerio.load(html);
    const personList = $(".bio-btn");
    console.log(personList.length);

    personList.each(function() {
      const link_raw = $(this).attr("href");

      const link = url + link_raw;
      const name = link_raw.replace("/bio/", "");

      person.push({
        name,
        link
      });
    });
  });
}

getPersons().then(function() {
  persons.forEach(async function(person) {
    var personLink = person.link;
    await axios.get(personLink).then(response => {
      const html = response.data;
      const $ = cheerio.load(html);
      const snapshots = $(".ratio-4-3");
      snapshots.each(function() {
        const pic = $(this).attr("style");
        if (pic != undefined && pic.includes("biopicture")) {
          var bioPhoto = s[1];
        }
      });
    });
  });
});

2 个答案:

答案 0 :(得分:2)

随着您最终提出串行请求,您几乎不会从异步中获得很多好处。我会这样写(未经测试):

async function getPersons() {
  const response = await axios.get(url);
  const html = response.data;
  const $ = cheerio.load(html);
  const personList = $('.bio-btn');

  const persons = [];
  personList.each(function() {
    const link_raw = $(this).attr('href');

    const link = url + link_raw;
    const name = link_raw.replace("/bio/", "");

    persons.push({
      name,
      link,
    });
  });
  return persons;
};

async function getSnapshots() {
  const persons = await getPersons();
  const linkPromises = persons.map(person => axios.get(person.link));
  const linkResponses = await Promise.all(linkPromises);
  linkResults.forEach(response => {
    const html = response.data;
    const $ = cheerio.load(html);
    const snapshots = $(".ratio-4-3");
    // ...
  });
}

答案 1 :(得分:1)

我会这样重构它。删除匿名函数上的.then()方法和关键字function使代码看起来更简洁。
使用Promise.all()使您可以异步开始所有下载,这可能比逐个下载映像更好。

const axios = require('axios');
const cheerio = require('cheerio');

const url = 'https://www.website.com';


async function getPersons() {
  const response = await axios.get(url);
  return extractPersonList(response);
}

// Step 1
function extractPersonList(response) {
  const persons = [];
  const html = response.data;
  const $ = cheerio.load(html);
  const personList = $('.bio-btn');
  console.log(personList.length);
  personList.each(() => {
    const link_raw = $(this).attr('href');
    const link = url + link_raw;
    const name = link_raw.replace('/bio/', '');
    persons.push({
      name,
      link
    });
  });
  return persons;
}

async function getPhotos() {
  const persons = await getPersons();
  const promisies = persons.map(p => axios.get(p.link));
  // Step 2
  const responses = await Promise.all(promisies);

  // Step 3
  responses.forEach(response => {
    const html = response.data;
    const $ = cheerio.load(html);
    const snapshots = $('.ratio-4-3');
    snapshots.each(() => {
      const pic = $(this).attr('style');
      if (pic && pic.includes('biopicture')) {
        var bioPhoto = s[1];
      }
    });
  });
}

// Call getPhotos to start the process
getPhotos();