将噩梦包裹在承诺中/一次处理一个 url
Wrapping nightmare in a promise / Processing one url at a time
我正在尝试使用 nightmarejs 从一些网站上抓取信息。我 运行 遇到的问题是,我一次只想打开一个 window 并等待它关闭,然后再处理下一个 url。
// index.js
var urls = // an array of urls.
var l = 10; // urls.length;
while (l--) {
// g.findById(id).then()....
// y.findById(id).then()....
UrlProcessing.findById(id).then(function(results) {
console.log(results);
});
}
现在 findByid:
//UrlProcessing.js
class UrlProcessing {
findById(id) {
var address = id;
return new Promise(function (resolve, reject) {
vo(function*(address) {
var nightmare = new Nightmare({show: true});
var link = yield nightmare
.goto(address)
.wait(2000)
.evaluate(function() {
return document.getElementsByTagName('html')[0].innerHTML;
});
yield nightmare.end();
return yield link;
})(address, function(err, res) {
if(err) reject(err);
resolve(res);
});
});
}
module.exports = UrlProcessing;
}
关于如何实现这一点有什么建议吗?我想在 while 循环中执行每个 findById
。
无需修改 findById
,您可以使用 reduce
:
模拟类似系列或瀑布的行为
var urls = ['http://www.yahoo.com', 'http://example.com', 'http://w3c.org'];
urls.reduce(function(accumulator, url) {
return accumulator.then(function(results) {
return findById(url)
.then(function(result) {
results.push(result);
return results;
});
});
}, Promise.resolve([])).then(function(results){
//do what you need to do with the results
});
为了完整起见,并且因为我必须进行一些修饰,findById
方法经过我的(轻微)修改:
function findById(address) {
return new Promise(function(resolve, reject) {
vo(function * (address) {
var nightmare = new Nightmare({
show: true
});
var link = yield nightmare
.goto(address)
.wait(2000)
.evaluate(function() {
return document.getElementsByTagName('html')[0].innerHTML;
});
yield nightmare.end();
return link;
})(address, function(err, res) {
if (err) reject(err);
resolve(res);
});
});
}
...综上所述,我不确定这种方法是否最好。你为什么要在 单独的 噩梦实例中一次一个地使用它们?我意识到这并不完全适合您的原始实现,但这可能是您要考虑的事情 - 您可以更改 findById
以接受数组而不是单个 URL 并且(可选)使用同一个噩梦实例。调用 findById
:
var urls = ['http://www.yahoo.com', 'http://example.com', 'http://w3c.org'];
findById(urls)
.then(function(results) {
//do what you need to do with the results
});
... 和 findById
本身:
function findById(addresses) {
return new Promise(function(resolve, reject) {
vo(function * (addresses) {
var nightmare = new Nightmare({
show: true
});
var results = [];
for (var i = 0; i < addresses.length; i++) {
results.push(yield nightmare
.goto(addresses[i])
.wait(2000)
.evaluate(function() {
return document.getElementsByTagName('html')[0].innerHTML;
}));
}
yield nightmare.end();
return results;
})(addresses, function(err, res) {
if (err) reject(err);
resolve(res);
});
});
}
当然,如果你每次都想要新鲜的 Nightmare 实例,你可以将构造函数调用和对 .end()
的调用移动到 for
循环中。
你所做的一切几乎都是正确的,现在你需要做的就是对承诺进行排序,即链接它们,你可以看看this answer。
只需更改您的代码即可使用 reduce
:
// index.js
urls.reduce( function(promise, url){
return promise.then(function(){
return url.findById(id);
}).then(function(results){
console.log(results);
});
}, Promise.resolve())
.then(function(){
console.log('All done');
});
在更简洁的 ES6 形式中,它将是:
urls.reduce( (p, url) => p.then(() => url.findById(id)).then(r => console.log(r)), Promise.resolve())
.then(() => console.log('All done') );
我正在尝试使用 nightmarejs 从一些网站上抓取信息。我 运行 遇到的问题是,我一次只想打开一个 window 并等待它关闭,然后再处理下一个 url。
// index.js
var urls = // an array of urls.
var l = 10; // urls.length;
while (l--) {
// g.findById(id).then()....
// y.findById(id).then()....
UrlProcessing.findById(id).then(function(results) {
console.log(results);
});
}
现在 findByid:
//UrlProcessing.js
class UrlProcessing {
findById(id) {
var address = id;
return new Promise(function (resolve, reject) {
vo(function*(address) {
var nightmare = new Nightmare({show: true});
var link = yield nightmare
.goto(address)
.wait(2000)
.evaluate(function() {
return document.getElementsByTagName('html')[0].innerHTML;
});
yield nightmare.end();
return yield link;
})(address, function(err, res) {
if(err) reject(err);
resolve(res);
});
});
}
module.exports = UrlProcessing;
}
关于如何实现这一点有什么建议吗?我想在 while 循环中执行每个 findById
。
无需修改 findById
,您可以使用 reduce
:
var urls = ['http://www.yahoo.com', 'http://example.com', 'http://w3c.org'];
urls.reduce(function(accumulator, url) {
return accumulator.then(function(results) {
return findById(url)
.then(function(result) {
results.push(result);
return results;
});
});
}, Promise.resolve([])).then(function(results){
//do what you need to do with the results
});
为了完整起见,并且因为我必须进行一些修饰,findById
方法经过我的(轻微)修改:
function findById(address) {
return new Promise(function(resolve, reject) {
vo(function * (address) {
var nightmare = new Nightmare({
show: true
});
var link = yield nightmare
.goto(address)
.wait(2000)
.evaluate(function() {
return document.getElementsByTagName('html')[0].innerHTML;
});
yield nightmare.end();
return link;
})(address, function(err, res) {
if (err) reject(err);
resolve(res);
});
});
}
...综上所述,我不确定这种方法是否最好。你为什么要在 单独的 噩梦实例中一次一个地使用它们?我意识到这并不完全适合您的原始实现,但这可能是您要考虑的事情 - 您可以更改 findById
以接受数组而不是单个 URL 并且(可选)使用同一个噩梦实例。调用 findById
:
var urls = ['http://www.yahoo.com', 'http://example.com', 'http://w3c.org'];
findById(urls)
.then(function(results) {
//do what you need to do with the results
});
... 和 findById
本身:
function findById(addresses) {
return new Promise(function(resolve, reject) {
vo(function * (addresses) {
var nightmare = new Nightmare({
show: true
});
var results = [];
for (var i = 0; i < addresses.length; i++) {
results.push(yield nightmare
.goto(addresses[i])
.wait(2000)
.evaluate(function() {
return document.getElementsByTagName('html')[0].innerHTML;
}));
}
yield nightmare.end();
return results;
})(addresses, function(err, res) {
if (err) reject(err);
resolve(res);
});
});
}
当然,如果你每次都想要新鲜的 Nightmare 实例,你可以将构造函数调用和对 .end()
的调用移动到 for
循环中。
你所做的一切几乎都是正确的,现在你需要做的就是对承诺进行排序,即链接它们,你可以看看this answer。
只需更改您的代码即可使用 reduce
:
// index.js
urls.reduce( function(promise, url){
return promise.then(function(){
return url.findById(id);
}).then(function(results){
console.log(results);
});
}, Promise.resolve())
.then(function(){
console.log('All done');
});
在更简洁的 ES6 形式中,它将是:
urls.reduce( (p, url) => p.then(() => url.findById(id)).then(r => console.log(r)), Promise.resolve())
.then(() => console.log('All done') );