我在 JS Promises 方面遇到了一些基本问题。这是我的完整代码
'use strict'
const rp = require('request-promise');
const cheerio = require('cheerio');
var fs = require('fs');
var os = require('os');
const options = {
uri: url,
normalizeWhitespace: true,
transform: function (body) {
return cheerio.load(body);
}
};
let results = []
let results2 = []
rp(options)
.then(($) => {
$('.col-xs-4 .grid-item').each(function (i, elem) {
let temp = $(this).find(".prod-image").attr("style")
let productImageUrl = temp.substring(temp.indexOf("background-image:url('") + 22, temp.indexOf("')"))
let detailUrl = $(this).find(".prod-image").attr("href")
let title = $(this).find(".title").text()
let description = $(elem).children().eq(4).attr("content")
results.push({
"productImageUrl": productImageUrl,
"detailUrl": detailUrl,
"title": title,
"description": description
})
});
})
.then(() => {
results.forEach(item => {
const options1 = {
uri: item.detailUrl,
normalizeWhitespace: true,
transform: function (body) {
return cheerio.load(body);
}
};
rp(options1)
.then(($) => {
console.log(5)
let temp = $('#prod-title').text()
let unit = temp.substring(temp.indexOf('Size: ') + 6, temp.indexOf('mL') - 1)
let retail = temp.substring(temp.indexOf('Retail: $') + 9, temp.indexOf(' A'))
let wholesale = temp.substring(temp.indexOf('Wholesale: $') + 12, temp.indexOf(' A') + 21)
results2.push({
"productImageUrl": item.productImageUrl,
"detailUrl": item.detailUrl,
"title": item.title,
"description": item.description,
"unit": unit,
"retail": retail,
"wholesale": wholesale
})
})
.catch((err) => {
console.log(err);
});
})
})
.finally(() => {
console.log("FINALLY " + results2)
let header = "Handle,Title,Body" + os.EOL
fs.writeFile("./file.csv", header, function (err) {
if (err) {
return console.log(err);
}
});
for (let item of results2) {
console.log(2)
let hyphenateTitle = item.title.replace(/\s+/g, '-').toLowerCase();
let line = hyphenateTitle + "," + item.title + "," + item.description + "," + vendor + ',"","",true,Title,Default Title,,,,,SKU,10000,,1,deny,manual,' + item.retail + "," + item.wholesale + "," + 'true,true,"",' + item.productImageUrl + "," + ',1,,false,,,,,,,,,,,,,,,,,kg,' + os.EOL
fs.appendFile("./file.csv", line, function (err) {
if (err) {
return console.log(err);
} else {
// done
}
})
}
})
.catch((err) => {
console.log(err);
});
这个想法是,在第一个 then()
中,我将读取 HTML 页面并找到一些 URL。我会将这些信息推送到 results
数组中。
然后,在第二个 then
上,想法是迭代数组中的每个项目并转到第二页,提取更多信息并将其推送到 结果
最后
,在 csv 中获取全部信息。
这是控制台中的输出:
FINALLY
5
5
5
5
5
5
5
5
5
5
5
5
5
5
5
5
5
5
5
5
5
5
5
5
因此,正如您所看到的,最后一个 then
在中间的那个之前运行(但在最上面的那个之后。
我做错了什么? 谢谢
编辑 1 这是评论者之一建议的新代码:
'use strict'
const rp = require('request-promise');
const cheerio = require('cheerio');
var fs = require('fs');
var os = require('os');
const options = {
uri: url,
normalizeWhitespace: true,
transform: function (body) {
return cheerio.load(body);
}
};
let results = []
let results2 = []
rp(options)
.then(($) => {
console.log("FIRST THEN")
$('.col-xs-4 .grid-item').each(function (i, elem) {
let temp = $(this).find(".prod-image").attr("style")
let productImageUrl = temp.substring(temp.indexOf("background-image:url('") + 22, temp.indexOf("')"))
let detailUrl = $(this).find(".prod-image").attr("href")
let title = $(this).find(".title").text()
let description = $(elem).children().eq(4).attr("content")
results.push({
"productImageUrl": productImageUrl,
"detailUrl": detailUrl,
"title": title,
"description": description
})
});
})
.then(($) => {
console.log("SECOND THEN")
return Promise.all(results.map( item => {
console.log("SECOND THEN INNER")
const options1 = {
uri: item.detailUrl,
normalizeWhitespace: true,
transform: function (body) {
return cheerio.load(body);
}
};
rp(options1)
.then(($) => {
console.log("SECOND THEN INSIDE 'rp(options1)'")
let temp = $('#prod-title').text()
let unit = temp.substring(temp.indexOf('Size: ') + 6, temp.indexOf('mL') - 1)
let retail = temp.substring(temp.indexOf('Retail: $') + 9, temp.indexOf(' A'))
let wholesale = temp.substring(temp.indexOf('Wholesale: $') + 12, temp.indexOf(' A') + 21)
results2.push({
"productImageUrl": item.productImageUrl,
"detailUrl": item.detailUrl,
"title": item.title,
"description": item.description,
"unit": unit,
"retail": retail,
"wholesale": wholesale
})
})
.catch((err) => {
console.log(err);
});
}))
})
.finally(($) => {
console.log("FINALLY " + results2)
let header = "Handle,Title,Body" + os.EOL
fs.writeFile("./file.csv", header, function (err) {
if (err) {
return console.log(err);
}
});
for (let item of results2) {
console.log(2)
let hyphenateTitle = item.title.replace(/\s+/g, '-').toLowerCase();
let line = hyphenateTitle + "," + item.title + "," + item.description + "," + vendor + ',"","",true,Title,Default Title,,,,,SKU,10000,,1,deny,manual,' + item.retail + "," + item.wholesale + "," + 'true,true,"",' + item.productImageUrl + "," + ',1,,false,,,,,,,,,,,,,,,,,kg,' + os.EOL
fs.appendFile("./file.csv", line, function (err) {
if (err) {
return console.log(err);
} else {
// done
}
})
}
})
.catch((err) => {
console.log(err);
});
这是输出:
FIRST THEN
SECOND THEN
SECOND THEN INNER
SECOND THEN INNER
SECOND THEN INNER
SECOND THEN INNER
SECOND THEN INNER
SECOND THEN INNER
SECOND THEN INNER
SECOND THEN INNER
SECOND THEN INNER
SECOND THEN INNER
SECOND THEN INNER
SECOND THEN INNER
SECOND THEN INNER
SECOND THEN INNER
SECOND THEN INNER
SECOND THEN INNER
SECOND THEN INNER
SECOND THEN INNER
SECOND THEN INNER
SECOND THEN INNER
SECOND THEN INNER
SECOND THEN INNER
SECOND THEN INNER
SECOND THEN INNER
FINALLY
SECOND THEN INSIDE 'rp(options1)'
SECOND THEN INSIDE 'rp(options1)'
SECOND THEN INSIDE 'rp(options1)'
SECOND THEN INSIDE 'rp(options1)'
SECOND THEN INSIDE 'rp(options1)'
SECOND THEN INSIDE 'rp(options1)'
SECOND THEN INSIDE 'rp(options1)'
SECOND THEN INSIDE 'rp(options1)'
SECOND THEN INSIDE 'rp(options1)'
SECOND THEN INSIDE 'rp(options1)'
SECOND THEN INSIDE 'rp(options1)'
SECOND THEN INSIDE 'rp(options1)'
SECOND THEN INSIDE 'rp(options1)'
SECOND THEN INSIDE 'rp(options1)'
SECOND THEN INSIDE 'rp(options1)'
SECOND THEN INSIDE 'rp(options1)'
SECOND THEN INSIDE 'rp(options1)'
SECOND THEN INSIDE 'rp(options1)'
SECOND THEN INSIDE 'rp(options1)'
SECOND THEN INSIDE 'rp(options1)'
SECOND THEN INSIDE 'rp(options1)'
SECOND THEN INSIDE 'rp(options1)'
SECOND THEN INSIDE 'rp(options1)'
SECOND THEN INSIDE 'rp(options1)'
最佳答案
第二个then
你正在运行一个异步迭代,没有任何东西告诉包装 Promise 等待循环内的 Promise(在 forEach
中)。
你应该return
内部 Promise 链通知父 Promise 等待,由于您需要等待迭代中的所有 Promise,因此可以使用 Promise.all
.
.then( () => {
return Promise.all(results.map( item => {
//...
return rp(options1).then(($) => {
//..
});
}));
})
您可以 catch
根据您的需要,在本地(在内部 Promise 上)或在父 Promise 上。
关于javascript - then() 在 Promise 之前完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52608004/