等待两个嵌套的Promise.all在PromiseJS中完成

时间:2018-09-21 15:41:08

标签: javascript promise

我有这段代码,我要在注释EXECUTION完成后等待Promise.all,然后继续执行其他任务。请注意,我使用的是PromiseJS,而不是BlueBird。我搜索了有关等待/异步的问题,但没有一个对我有用。如果您觉得代码很长,很抱歉,因为我想公开所有内容。也许不这样做,你们中的一些人可能会说“也许某个地方有错误”。

// ================ 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' }
========

EDIT 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 :(得分:1)

Promise.all(...)必须采用 Promise-type 变量的数组。并且应该紧跟.then(() => { //success code results},但我没有看到。

签出:Mozilla Developer Network: 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 Network: Async Function

第一种方法比较可取,因为它包含catch块,但是没有理由不能以各种方式组合这些块。

答案 1 :(得分:0)

我了解您是堆栈溢出的新手,并且可能使用javascript和promises。这是使用PromisePromise.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)
  })