Дождитесь окончания двух вложенных Promise.all в PromiseJS - PullRequest
0 голосов
/ 21 сентября 2018

У меня есть этот код, я хочу дождаться завершения Promise.all после комментария EXECUTION и затем перейти к выполнению другой задачи.Обратите внимание, что я использую PromiseJS, а не BlueBird.Я искал вопросы о await / async, но ни один из них не работает для меня.Извините, если вы чувствуете, что код длинный, так как я хочу раскрыть все это.Может быть, не делая этого, некоторые из вас могут сказать «возможно, где-то есть ошибка».

// ================ load the lib ================ 
const curl = require("curl");
const jsdom = require('jsdom');
const cheerio = require('cheerio');
const Promise = require("promise");


// ================ declare global constants ================ 
const domain = "https://www.bankmega.com";
var url = domain + "/ajax.promolainnya.php";
const categories = [1, 2, 3, 4, 5, 6]; // hard-code subcat but later can be changed
                                       // simply by loading the main page, then get all the subcat
                                       // and convert to an appropriate integer array representing the
                                       // categories
var visited = new Set(); // store visited links (not to scrap an item twice)


// ================  declare methods ================ 
function getItemLinksOfCat(url, subcat) {
    const subCatURL = url + "?product=&subcat=" + subcat;
    curl.get(subCatURL, null, (err, resp, body) => {
        const {JSDOM} = jsdom;
        const dom = new JSDOM(body);
        const $ = (require("jquery"))(dom.window);
        var tds = $("table[class=tablepaging] tr").children();
        var maxPage = getMaxPage(tds, $);
        var itemLinks = getItemLinks(maxPage, $, subcat);

        // itemLinks.forEach(itemLink => {
        //  if (!visited.has(itemLink)) {
        //      visited.add(itemLink);
        //      scrapItem(itemLink);
        //  }
        // });

        Promise.all(itemLinks.map(function(itemLink) {
            if (!visited.has(itemLink)) {
                visited.add(itemLink);
                scrapItem(itemLink);
            }
        }));
    });

}

function getItemLinks(maxPage, $, subcat) {
    var itemLinks = [];
    var product = "";
    for (var i = 1; i <= maxPage; ++i) {
        var page = i;
        $("#contentpromolain2").load("ajax.promolainnya.php?product="+product+"&subcat="+subcat+"&page="+page);
        var lis = $("ul#promolain").children();
        for (var j = 0; j < lis.length; ++j) {
            var itemLink = $(lis[j]).find("a").attr("href");
            itemLinks.push(itemLink);
        }
    }

    return itemLinks;
}

function getMaxPage(tds, $) {
    var maxPage = -1;

    for(var i = 0; i < tds.length; ++i ){
        var td = $(tds[i]);
        var page = parseInt(td.text());
        if (page != NaN && page > maxPage) {
            maxPage = page;
        }
    }

    return maxPage;
}

/*
Using wrapper method might be useful in the future
As we can redirect a call to an appropriate method
that can handle a specific type of item
 */
function scrapItem(itemLink) {
    if(itemLink.includes("promo_detail")) {
        scrapPromoDetail(itemLink);
    }
}

/*
Actual method to scrap promo item
We can have other methods to scrap other types of item
*/
function scrapPromoDetail(itemLink) {
    itemLink = domain + "/" + itemLink;
    curl.get(itemLink, null, (err, resp, body) => {
        if (resp != undefined && resp.statusCode == 200) {
            var s = parseItemHTMLToString(body, itemLink);
            console.log(s);
            console.log("========");
        }
    });

}

/*
Helper function to parse item's html to string
Return a string contains item's property-value pairs
*/
function parseItemHTMLToString(html, itemLink) {
    const $ = cheerio.load(html);
    var promoSection = $("div#contentpromolain2");
    var promoProperties = promoSection.find("div");
    var dict = {};

    for (var i = 0; i < promoProperties.length; ++i) {
        var div = $(promoProperties[i]);
        var klass = div.attr("class");
        var text = div.text().trim();
        if (klass !== undefined) {
            if (klass === "titleinside") { // title
                dict[klass] = text;
            } else {
                if (klass === "periode" || klass === "area" ) { // other props
                    var token = text.split(":");
                    text = token[1];
                    if (klass === "periode") {
                        token = text.split("-");
                        for(var j = 0; j < token.length; ++j) {
                            token[j] = token[j].trim();
                        }
                        dict[klass] = token.join(" - ");
                    } else { // area
                        dict[klass] = text;
                    }
                } else if (klass === "keteranganinside") { // promo image
                    dict[klass] = domain + div.find("img").attr("src").trim();
                } else { // other props
                    dict[klass] = text;
                }
            }
        }
    }

    return dict;
}

// ================ EXECUTION ================ 
Promise.all(categories.map(function(subcat) {
    getItemLinksOfCat(url, subcat)

}));

// do other tasks after Promise.all

РЕДАКТИРОВАТЬ 1 Я пробовал это:

// ================ EXECUTION ================ 
async function ttt() {
    await Promise.all(categories.map(function(subcat) {
        getItemLinksOfCat(url, subcat)

    }));
    // do other tasks after Promise.allc
}

ttt().then( result => {
console.log("Finish");
});

но это не сработало.

Вот часть вывода:

Finish
{ titleinside: 'Mega Cellular - Free Tempered Glass',
  area: ' Pontianak',
  periode: '20 Juli 2018 - 18 Oktober 2018',
  keteranganinside:
   'https://www.bankmega.com/files/images/00-landing-page-MEGACELL.jpg' }
========

РЕДАКТИРОВАТЬ 2 Привет HoldOffHunder, вы имеете в виду это?

// ================ EXECUTION ================ 
async function test() {
    await Promise.all(categories.map(function(subcat) {
        getItemLinksOfCat(url, subcat)
    }));
    // do other tasks after Promise.allc

    console.log("???");
}

test();

Также распечатано "???"перед запуском.

Ответы [ 2 ]

0 голосов
/ 21 сентября 2018

Я понимаю, что вы новичок в переполнении стека и, возможно, работаете с JavaScript и обещаниями.Вот пример использования Promise и Promise.all()

var people = ["James", "John", "Aaron", "Lane", "Josh", "Isaac"];
let cars = ["Subaru", "Ford", "Chevrolet", "Mercedes", "Toyota"];


let getPeople = () => {
  let promise = new Promise((resolve, reject) => {
    if (people)
     resolve(people);
    else
      reject("People does not exist");
  })
  
  return promise;
}

let getCars = () => {
  let promise = new Promise((resolve, reject) => {
    if (cars)
     resolve(cars);
    else
      reject("cars does not exist");
  });
  
  return promise;
}

let promiseArr = [getPeople(), getCars()]

Promise.all(promiseArr)
  .then((resp) => {
    console.log(resp[0])
    console.log(resp[1])
  })
  .catch((err) => {
    console.log(err)
  })
0 голосов
/ 21 сентября 2018

Promise.all(...) должен принимать массив переменных типа Promise .И за ним должно следовать .then(() => { //success code results}, но я этого не вижу.

Проверьте это: Сеть разработчиков Mozilla: Promise.all ()

Обещаниебудет выглядеть как ...

var promise3 = new Promise(function(resolve, reject) {...});

И вы будете использовать Promise.all() как ...

var promisearray = [
    //somepromiseshere
];

Promise.all(
        promisearray
).then(() => {
        console.log("Promise all finished.");
}, () => {
        console.log("Promise all failed.");
});

Или другой метод, использующий await () -

Поскольку Promise.all () является асинхронным, вы также можете использовать await вместо этого, например, так ...

await Promise.all(promisearray);

Проверьте это: Mozilla DeveloperСеть: Асинхронная функция

Первый способ предпочтительнее, поскольку он содержит блоки перехвата, но нет причин, по которым вы не можете комбинировать их различными способами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...