简体   繁体   中英

Refactoring async functions in javascript

I have written a program to extract links to download photos in three steps:

  1. The getPersons() function get the complete list of people to traverse.
  2. Get the photos download links from the list of persons.
  3. Download from the list created in step 2.

I am trying to refactor step 2 into an async function. Is there an easy way to refactor second step into a function to make the code more readable?

Ideally, I would like to retrieve all the links and only then, start the download.

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

You are hardly getting much benefit out of your asynchronicity, as you end up making serial requests. I'd write it this way (untested):

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");
    // ...
  });
}

I would refactor it like this. Removing .then() methods and the function keyword on anonymous functions makes the code look cleaner.
Using Promise.all() enables you to start all the downloads asynchronously which could be better than downloading images one by one.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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