为什么Promise中的承诺仍然悬而未决?

这是我重组我的代码,以正确使用承诺。 整个程序是一个基本的webscraper。

这个挑战是试图确保lastStep可以访问每个页面的HTML和URL,所以我试图在nextStep()返回一个对象。

我是控制台日志logging的HTML,它被正确地返回,但由于某种原因,承诺被logging如下: Promise { <pending> } 。 为什么会发生这种情况,我该如何解决?

谢谢!

 //Modules being used: var cheerio = require('cheerio'); var json2csv = require('json2csv'); var request = require('request'); var moment = require('moment'); var fs = require('fs'); //harcoded url var url = 'http://shirts4mike.com/'; //url for tshirt pages var urlSet = new Set(); var remainder; var tshirtArray = []; const requestPromise = function(url) { return new Promise(function(resolve, reject) { request(url, function(error, response, html) { if(error) return reject(error); if(!error && response.statusCode == 200){ return resolve(html); } }); }); } function scrape (url) { return requestPromise(url) .then(function(html) { var $ = cheerio.load(html); var links = []; //get all the links $('a[href*=shirt]').each(function(){ var a = $(this).attr('href'); //add into link array links.push(url + a); }); // return array of links return links; }); } function nextStep (arrayOfLinks) { var promiseArray = []; for(var i = 0; i < arrayOfLinks.length; i++){ promiseArray.push(requestPromise(arrayOfLinks[i])); var promises = Promise.all(promiseArray); console.log(promises); } return {arrayOfHtml: promises , arrayOfUrls: arrayOfLinks}; } function lastStep (obj){ for(var i = 0; i < obj.arrayOfHtml.length; i++){ var $ = cheerio.load(obj.arrayOfHtml[i]); //if page has a submit it must be a product page if($('[type=submit]').length !== 0){ //add page to set urlSet.add(obj.arrayOfUrls[i]); console.log(obj.arrayOfUrls[i]); } else if(remainder == undefined) { //if not a product page, add it to remainder so it another scrape can be performed. remainder = obj.arrayOfUrls[i]; console.log("remainder: " + remainder); } } } scrape(url) .then(nextStep) .then(lastStep) .catch(function(err) { // handle any error from any request here console.log(err); }); 

你可以尝试一些事情。 首先,在您的requestPromise函数中,当您调用“resolve()”和“ reject() ”时不需要返回。 我不知道这是否会有所作为,但至less可以尝试。

接下来,如评论所述,您应该改变拒绝和解决请求承诺的方式。 最简单的:

 if(error) { reject(error); } else { resolve(html); } 

假设没有错误(错误只会发生在4xx或5xx状态码),但状态码不是200? 您可以在2xx或3xx范围内获得任何内容,并且不会出现错误,在这种情况下,您的requestPromise将永远不会被解决或拒绝。 这肯定会导致你的问题,因为所有的承诺必须结束一个或另一个。

下一个问题在nextStep 。 我会重构如下:

 function nextStep (arrayOfLinks) { var promiseArray = []; for(var i = 0; i < arrayOfLinks.length; i++){ promiseArray.push(requestPromise(arrayOfLinks[i])); } return Promise.all(promiseArray) .then(function (arrayOfHtml) { return {arrayOfHtml: promises , arrayOfUrls: arrayOfLinks}; }); } 

有了Promise.all ,你Promise.all填充你的promise数组,然后在完成所有的asynchronous调用之后,就是在你调用Promise.all(promisesArray)thenall的结尾将采取从您的承诺数组产生的HTML,然后作为承诺连同arrayOfLinks到承诺链中的下一个步骤,在这种情况下是您的lastStep

如果这些都不能解决您的问题,您将需要回顾状态代码问题,状态代码为202之前,我有问题,这意味着请求被接受,但请求处理不完整。 (您可以在这里阅读更多关于HTTP状态码的信息 )。 这是一个非常相似的情况,我们有一大堆我们要求的url。 我们最终把所有得到202的url都放回到tryAgain数组中,然后试着再次敲击它们。

就你而言,你有一个可以解决这个问题的方法。 最简单的办法是拒绝所有状态代码的保证,除了200,这将是一个有点严格。 你可以做的另一件事是,如果没有错误,并且状态码不是200,那么你可以用一些特殊的值来解决承诺,或者只是非200状态码,这将表明你需要再试一次。 然后在nextStep之后,您可以过滤所有使用非200代码解决的结果,并尝试再次敲击它们。 之后,你可以完成lastStep 。 如果您尝试了其他方法,而且没有任何方法可行,那么我会尝试其中一种解决scheme。 这需要一些努力。

希望这可以帮助。 如果您有任何问题,请告诉我。

你的代码中还有一个未处理的else

 if(error) return reject(error); if(!error && response.statusCode == 200){ return resolve(html); } 

让我们重新安排一下,以便更清楚。 由于return上面的代码是完全一样的:

 if(error) { reject(error); } else if (response.statusCode == 200) { resolve(html); } else { // keep this promise pending FOREVER!! } 

你还没有处理最后的其他。 根据你的意图,你可以做的最小的修改是:

 if(error) return reject(error); if(!error && response.statusCode == 200){ return resolve(html); } reject(new Error('Not code 200')); 

要么

 if(error) return reject(error); if(!error && response.statusCode == 200){ return resolve(html); } resolve(html); 

不过,我个人重写逻辑更清楚(你错过了最后的事实certificate代码是不清楚的)。