繁体   English   中英

回调函数Node JS

[英]Callback function Node JS

我最近正在研究nodejs(并使用nightmare.js)来解析网站,并且在回调函数和显示返回的结果方面遇到问题。 我正在尝试在另一个函数中调用一个单独的函数,但似乎无法返回任何结果。 它们都返回未定义。 在此方面的任何帮助将不胜感激。

 function getDetails(loadURL, callback){
    nightmare.goto(loadURL)
        .wait(2000)
        .evaluate(function(){
            var gigs = [];
            $('.hidden-xs .used-vehicle').each(function(){
                item = {}
                item["year"] = $(this).attr('data-year')
                item["make"] = $(this).attr('data-make')
                item["model"] = $(this).attr('data-model')
                item["body"] = $(this).attr('data-body')
                item["color"] = $(this).attr('data-ext-color')
                item["trim"] = $(this).attr('data-trim')
                item["mileage"] = $(this).attr('data-mileage')
                item["transmission"] = $(this).attr('data-transmission')
                item["vin"] = $(this).find(".vehicle-overview").attr('id')
                item["title"] = $(this).find(".vehicle-overview h2 a").text()
                item["link"] = $(this).find(".vehicle-overview h2 a").attr('href')
                item["price"] = $(this).find(".vehicle-content .price").text()
                gigs.push(item)
            })
            return gigs
        })
        .end()
        .then(function(result){
            var returnString = '';
            for(gig in result){
                returnString = returnString + result[gig].title + " " + result[gig].link + " " + result[gig].year + " " + result[gig].make + " " + result[gig].model + " " + result[gig].body + " " + result[gig].color + " " + result[gig].trim + " " + result[gig].transmission + " " + result[gig].vin + " " + result[gig].price + "\n"
            }
            callback(returnString)
        })  
}

    // We will need to get the total amount of pages that we need to parse
    function getInventory(sURL, callback){
        nightmare.goto(sURL)
            .wait(2000)
            .evaluate(function(){
                totals = [];
                items = {}
                totalCars = $('.total-found .count').text()
                carsOnPage = $('.hidden-xs .used-vehicle').size()
                items['carTotal'] = totalCars
                items['onPage'] = carsOnPage
                var pageCalc = (totalCars / carsOnPage)
                items['tPages'] = Math.ceil(pageCalc)
                totals.push(items)
                return totals
            })
            .end()
            .then(function(result){
                var totalCars = '';
                var totalPages = '';
                for (item in result){
                    totalPages = result[item].tPages
                    totalCars = result[item].carTotal               
                }
                counter = 0;
                newURL = '';
                returnDetails = '';
                for (i =0; i < totalPages; i++){
                    if (i == 0){
                        newURL = sURL;
                    } else {
                        counter = i + 1;
                        newURL = sURL + "#action=im_ajax_call&perform=get_results&_post_id=5&page=" + counter + "&show_all_filters=false";
                    }
                    //console.log(newURL)
                    getINV = getDetails(newURL, function(returnString){
                        callback(returnString)
                    })
                    returnDetails = returnDetails + getINV
                }
                callback(returnDetails)
            })
    }

    getInventory(startURL, function(result){
        console.log(result)
    })

我不会费心告诉您,不要将回调与这样的承诺混在一起。 但是,让我们现在来看问题。

情况1

您也如何检查错误? 也许您的脚本抛出了错误。 我可以看到您在.catch上调用了回调.then但是在.catch上没有.catch 也许那时永远不会获取任何数据。

情况二

让我们检查一下您的功能。 您每次都呼叫.end 您是否也在每次都创建新的Nightmare实例?

getInventory函数上,您不应调用.end getDetails函数上,您不应调用.end 它结束了噩梦实例,您正在丢失数据。

完成所有功能和工作后,调用nightmare.end() 要正确执行此操作,您将需要在下面了解有关Promise Check case 3的更多信息。

情况3

了解诺言如何运作。 在下面的行中,您无需等待函数完成。

getINV = getDetails(newURL, function(returnString){
 callback(returnString)
})

您应该等待诺言完成。 另外,请确保不要在噩梦中尝试同时浏览两个链接。

因此,继续学习Promises和异步等待的东西。

我将如何解决您的代码?

我会使用Promise.all,.map和其他新功能。 这是为您完成的一些示例代码,请勿复制粘贴或直接运行该代码,请尝试理解为什么它与您的代码不同以及它的结果是什么。

 const pLimit = require("promise-limit")(2); function getDetails(loadURL) { return nightmare .goto(loadURL) .wait(2000) .evaluate(() => { const gigs = []; $(".hidden-xs .used-vehicle").each(function() { item = {}; item["year"] = $(this).attr("data-year"); item["make"] = $(this).attr("data-make"); item["model"] = $(this).attr("data-model"); item["body"] = $(this).attr("data-body"); item["color"] = $(this).attr("data-ext-color"); item["trim"] = $(this).attr("data-trim"); item["mileage"] = $(this).attr("data-mileage"); item["transmission"] = $(this).attr("data-transmission"); item["vin"] = $(this) .find(".vehicle-overview") .attr("id"); item["title"] = $(this) .find(".vehicle-overview h2 a") .text(); item["link"] = $(this) .find(".vehicle-overview h2 a") .attr("href"); item["price"] = $(this) .find(".vehicle-content .price") .text(); gigs.push(item); }); return gigs; }) .then(result => { let returnString = ""; for (gig in result) { returnString = `${returnString + result[gig].title} ${result[gig].link} ${result[gig].year} ${result[gig].make} ${result[gig].model} ${result[gig].body} ${result[gig].color} ${result[gig].trim} ${result[gig].transmission} ${result[gig].vin} ${result[gig].price}\\n`; } return returnString; }) .catch(error => { throw new Error(error); }); } // We will need to get the total amount of pages that we need to parse function getInventory(sURL) { return nightmare .goto(sURL) .wait(2000) .evaluate(() => { totals = []; items = {}; totalCars = $(".total-found .count").text(); carsOnPage = $(".hidden-xs .used-vehicle").size(); items["carTotal"] = totalCars; items["onPage"] = carsOnPage; const pageCalc = totalCars / carsOnPage; items["tPages"] = Math.ceil(pageCalc); totals.push(items); return totals; }) .then(result => { let totalCars = ""; let totalPages = ""; for (item in result) { totalPages = result[item].tPages; totalCars = result[item].carTotal; } counter = 0; newURL = ""; urls = []; returnDetails = []; for (i = 0; i < totalPages; i++) { if (i == 0) { newURL = sURL; } else { counter = i + 1; newURL = `${sURL}#action=im_ajax_call&perform=get_results&_post_id=5&page=${counter}&show_all_filters=false`; } // push to the url array // use .map for cleaner code urls.push(newURL); } // return a new promise with concurrency limit return Promise.all( urls.map(url => { return limit(() => getDetails(newURL)); }) ); }) .catch(error => { throw new Error(error); }); } getInventory(startURL) .then(result => { console.log(result); }) .catch(error => { console.err(error); }); 

资源:

尝试使用回调而不是返回

function getDetails(loadURL, callback){
    nightmare.goto(loadURL)
        .wait(2000)
        .evaluate(function(callback){
            var gigs = [];
            $('.hidden-xs .used-vehicle').each(function(){
                item = {}
                item["year"] = $(this).attr('data-year')
                item["make"] = $(this).attr('data-make')
                item["model"] = $(this).attr('data-model')
                item["body"] = $(this).attr('data-body')
                item["color"] = $(this).attr('data-ext-color')
                item["trim"] = $(this).attr('data-trim')
                item["mileage"] = $(this).attr('data-mileage')
                item["transmission"] = $(this).attr('data-transmission')
                item["vin"] = $(this).find(".vehicle-overview").attr('id')
                item["title"] = $(this).find(".vehicle-overview h2 a").text()
                item["link"] = $(this).find(".vehicle-overview h2 a").attr('href')
                item["price"] = $(this).find(".vehicle-content .price").text()
                gigs.push(item)
            })
            callback(gigs)
        })
        .end()
        .then(function(result){
            var returnString = '';
            for(gig in result){
                returnString = returnString + result[gig].title + " " + result[gig].link + " " + result[gig].year + " " + result[gig].make + " " + result[gig].model + " " + result[gig].body + " " + result[gig].color + " " + result[gig].trim + " " + result[gig].transmission + " " + result[gig].vin + " " + result[gig].price + "\n"
            }
            callback(returnString)
        })  
}

    // We will need to get the total amount of pages that we need to parse
    function getInventory(sURL, callback){
        nightmare.goto(sURL)
            .wait(2000)
            .evaluate(function(){
                totals = [];
                items = {}
                totalCars = $('.total-found .count').text()
                carsOnPage = $('.hidden-xs .used-vehicle').size()
                items['carTotal'] = totalCars
                items['onPage'] = carsOnPage
                var pageCalc = (totalCars / carsOnPage)
                items['tPages'] = Math.ceil(pageCalc)
                totals.push(items)
                return totals
            })
            .end()
            .then(function(result){
                var totalCars = '';
                var totalPages = '';
                for (item in result){
                    totalPages = result[item].tPages
                    totalCars = result[item].carTotal               
                }
                counter = 0;
                newURL = '';
                returnDetails = '';
                for (i =0; i < totalPages; i++){
                    if (i == 0){
                        newURL = sURL;
                    } else {
                        counter = i + 1;
                        newURL = sURL + "#action=im_ajax_call&perform=get_results&_post_id=5&page=" + counter + "&show_all_filters=false";
                    }
                    //console.log(newURL)
                    getINV = getDetails(newURL, function(returnString){
                        callback(returnString)
                    })
                    returnDetails = returnDetails + getINV
                }
                callback(returnDetails)
            })
    }

    getInventory(startURL, function(result){
        console.log(result)
    })

也许以下方法会起作用,更改循环以减少和映射,取出jQuery并进行了一些小的更改。

最重要的是:

  1. 从html元素获取属性会返回一个字符串,您应该将其转换为数字。
  2. 摆脱了回调,并使函数返回promise。

这是代码:

const getDetails = loadURL =>
nightmare.goto(loadURL)//return promise here
.wait(2000)
.evaluate(
  ()=>
    Array.from(document.querySelectorAll('.hidden-xs .used-vehicle'))
    .reduce(
      (all,item)=>
        all.concat(
          [
            element.getAttribute('data-year'),
            element.getAttribute('data-make'),
            element.getAttribute('data-model'),
            element.getAttribute('data-body'),
            element.getAttribute('data-ext-color'),
            element.getAttribute('data-trim'),
            element.getAttribute('data-mileage'),
            element.getAttribute('data-transmission'),
            element.querySelector(".vehicle-overview").getAttribute('id'),
            element.querySelector(".vehicle-overview h2 a").innerText,
            element.querySelector(".vehicle-overview h2 a").getAttribute('href'),
            element.querySelector(".vehicle-content .price").innerText
          ].join(" ")
        ),
      []//the all array
    )
);

// We will need to get the total amount of pages that we need to parse
const getInventory = sURL =>
nightmare.goto(sURL)
  .wait(2000)
  .evaluate(
    ()=> {
      //there is only one item here, not sure why you push it into totals
      //  and call it items
      const item = {}
      //getAttribute returns a string, parse it to number
      totalCars = parseInt(document.querySelector('.total-found .count').innerText,10);
      carsOnPage = document.querySelectorAll('.hidden-xs .used-vehicle').length;
      item['carTotal'] = totalCars
      item['onPage'] = carsOnPage
      var pageCalc = (totalCars / carsOnPage)
      item['tPages'] = Math.ceil(pageCalc)
      return item;  
    }
  )
  .then(
    totalItem =>{
      var totalCars = '';
      var totalPages = '';
      totalPages = totalItem.tPages
      totalCars = totalItem.carTotal
      newURL = '';
      returnDetails = '';
      return Array.from(new Array(totalPages),(_,index)=>index+1)
      .reduce(
        (p,counter)=>
          p.then(
            results=>{
              if (counter === 1) {
                newURL = sURL;
              } else {
                newURL = sURL + "#action=im_ajax_call&perform=get_results&_post_id=5&page=" + counter + "&show_all_filters=false";
              }
              return getDetails(newURL)
              .then(
                result=>results.concat(result)
              );
            }
          ),
          Promise.resolve([])
      );
    }
  );

getInventory(startURL)
.then(
result=>
  console.log(result)
).catch(
err=>
  console.warn("Something went wrong:",err)
);

使用异步函数学习promise和回调是一项艰巨的任务。 我能够使它与以下对象一起使用。 谢谢大家的帮助和指导。 每个答案都将我送往另一个兔子洞,最终找到了解决方案。

    function getInventory(sURL){    
    nightmare.goto(sURL)
        .wait(2000)
        .evaluate(function(){
            totals = [];
            items = {}
            totalCars = $('.total-found .count').text()
            carsOnPage = $('.hidden-xs .used-vehicle').size()
            items['carTotal'] = totalCars
            items['onPage'] = carsOnPage
            var pageCalc = (totalCars / carsOnPage)
            items['tPages'] = Math.ceil(pageCalc)
            totals.push(items)
            return totals
        })
        .then(result => {
            var totalCars = '';
            var totalPages = '';
            for (item in result){
                totalPages = result[item].tPages
                totalCars = result[item].carTotal               
            }
            counter = 0;
            let links = [];
            let returnLinks = '';
            newURL = '';            
            for (i = 0; i < totalPages; i++){
                if (i == 0){
                    newURL = sURL;
                } else {
                    counter = i + 1;
                    newURL = sURL + "#action=im_ajax_call&perform=get_results&_post_id=5&page=" + counter + "&show_all_filters=false";
                }
                links.push(newURL);
            }
            return links;
        })
        .then(results => {
            var arrayLinks = results;
            arrayLinks.reduce(function(accumulator, url){
                return accumulator.then(function(newResults){
                    return nightmare.goto(url)
                        .wait(5000)
                        .evaluate(() => {
                            const gigs = [];
                            $(".hidden-xs .used-vehicle").each(function() {
                                item = {};
                                item["year"] = $(this).attr("data-year");
                                item["make"] = $(this).attr("data-make");
                                item["model"] = $(this).attr("data-model");
                                item["body"] = $(this).attr("data-body");
                                item["color"] = $(this).attr("data-ext-color");
                                item["trim"] = $(this).attr("data-trim");
                                item["mileage"] = $(this).attr("data-mileage");
                                item["transmission"] = $(this).attr("data-transmission");
                                item["vin"] = $(this).find(".vehicle-overview").attr("id");
                                item["title"] = $(this).find(".vehicle-overview h2 a").text();
                                item["link"] = $(this).find(".vehicle-overview h2 a").attr("href");
                                item["price"] = $(this).find(".vehicle-content .price").text();
                                gigs.push(item);
                            });
                            return gigs;
                        })
                        .then(detail => {                       
                            for (gig in detail) {
                                try {
                                    var carVin = detail[gig].vin;
                                    var carTitle = detail[gig].title;
                                    var carDescrip = detail[gig].year + " " + detail[gig].make + " " + detail[gig].model;
                                    var carURL = detail[gig].link;
                                    var carMake = detail[gig].make;
                                    var carModel = detail[gig].model;
                                    var carYear = detail[gig].year;
                                    var carMileageFull = detail[gig].mileage;
                                    var carMileage = carMileageFull.replace(',', '');
                                    var carTransmission = detail[gig].transmission;
                                    var carBody = detail[gig].body;
                                    var carPriceFull = detail[gig].price;
                                    var carPriceFull = carPriceFull.replace('$', '');               
                                    var carPriceFull = carPriceFull.replace('*', '');               
                                    var carPriceFull = carPriceFull.replace(',', '');               
                                    var carPrice = carPriceFull.trim();
                                    var dealerAddress = "{addr1: '"+ addressFull.addr1 +"', city: '"+ addressFull.city +"', region: '"+ addressFull.region +"', postal_code: '"+ addressFull.postal_code +"', country: '"+ addressFull.country +"'}";
                                    var dealerLat = latLongFull.latitude;
                                    var dealerLong = latLongFull.longitude;
                                    var carColor = detail[gig].color;

                                    arrSetup = [carVin, carTitle, carDescrip, carURL, carMake, carModel, carYear, carMileage, 'MI', '', '', 'AUTOMATIC', 'GASOLINE', 'OTHER', 'Other', carVin, 'OTHER', carPrice + " USD", dealerAddress, carColor, carPrice + " USD", 'AVAILABLE', 'USED', dealerLat, dealerLong];
                                    newResults.push(arrSetup);
                                }
                                catch(error){
                                    returnString += error;
                                }
                            }
                            return newResults;

                        })
                        .catch(error => {
                            throw new Error(error);
                        });

                });             
            }, Promise.resolve([]))
                .then(function(finalCall){

                    /*
                        We need to get the 3rd image on every vdp in the array. We will need to create a loop, go to the page, get the image and properly insert it into the proper array index
                    */

                    finalCall.reduce(function(accumulator, resultArray){
                        return accumulator.then(function(finalResults){
                            var vdp = resultArray[3];
                            return nightmare.goto(vdp)
                                .wait(500)
                                .evaluate(() => {
                                    var thirdIMG = $('.gallery-thumbs .owl-item:nth-of-type(3) img').attr('src');
                                    return thirdIMG;
                                })
                                .then(imgResult => {
                                    // 9
                                    resultArray.splice(9, 1, imgResult);
                                    console.log(resultArray);
                                    finalResults.push(resultArray);
                                    return finalResults;
                                })
                                .catch(error => {
                                    throw new Error(error);
                                });

                        });
                    }, Promise.resolve([]))
                        .then(finalInsert => {
                            const csvWriter = createCsvWriter({
                            header: ["vehicle_id", "title", "description", "url", "make", "model", "year", "mileage.value", "mileage.unit", "image[0].url", "image[0].tag[0]", "transmission", "fuel_type", "body_style", "drivetrain", "vin", "condition", "price", "address", "exterior_color", "sale_price", "availability", "state_of_vehicle", "latitude", "longitude"],
                                path: 'test.csv'
                            });

                            var records = finalInsert;
                            console.log(records)
                            csvWriter.writeRecords(records)
                            .then(() => {
                                nightmare.end();
                                console.log('...Done');
                            });
                        })
                });
        })      
        .catch(function(error){
            return error;
        })
}

    getInventory(startURL, function(response){
        try {
            console.log("This is the response" + response);
        }
        catch(error){
            console.log(error)
        }
    });

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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