我是Promises的新人。
我使用Bookshelf.js作为ORM。
我从这些网页上获取了一些网页,获取了人物信息(关于演员),如果他们不存在,则将其添加到我的数据库中。
但是有一个问题,即使console.log(name)
以正确的顺序返回演员姓名,我的查询只会检查一个演员,最新的演员是9。
这里有什么问题?
var entities = require("entities");
var request = require('request');
var cheerio = require('cheerio');
// create promisified version of request()
function requestPromise(options) {
return new Promise(function (resolve, reject) {
request(options, function (err, resp, body) {
if (err) return reject(err);
resolve(body);
});
});
}
var person = require('./models').person;
app.get('/fetch', function (req, res) {
var promises = [];
var headers = {
'User-Agent': req.headers['user-agent'],
'Content-Type': 'application/json; charset=utf-8'
};
for (var i = 1; i < 10; i++) {
promises.push(requestPromise({url: "http://www.example.com/person/" + i + "/personname.html", headers: headers}));
}
Promise.all(promises).then(function (data) {
// iterate through all the data here
for (var i = 0; i < data.length; i++) {
if ($ = cheerio.load(data[i])) {
var links = $("#container");
var name = links.find('span[itemprop="name"]').html(); // name
if (name == null) {
console.log("null name returned, do nothing");
} else {
name = entities.decodeHTML(name);
console.log(name); // returns names in the right order
// does this person exist in the database?
person.where('id', i).fetch().then(function (result) {
if (result) {
console.log(i + "exists");
} else {
console.log(i + " doesn't exist");
// returns "9 doesn't exists" 9 times instead of
// checking each ID individually, why?
}
});
}
} else {
console.log("can't open");
}
}
}, function (err) {
// error occurred here
console.log(err);
});
});
编辑#2
现在订单已经破损,我的ID与我从中获取数据的网站不一样。我看到ID就像11和13,即使我从1迭代到5,它似乎否决了一些东西,因为它增加了重复的条目。
这就是我要简单地尝试做的事情。 &#34;按顺序访问这些网址,并将您获取的数据(例如名称)以相同的顺序(id1 = name1; id2 = name2等)添加到数据库&#34;。
app.get('/fetch', function (req, res) {
var promises = [];
var headers = {
'User-Agent': req.headers['user-agent'],
'Content-Type': 'application/json; charset=utf-8'
};
for (var i = 1; i < 5; i++) {
promises.push(requestPromise({url: "http://example.com/person/ + i + "/personname.html", headers: headers}));
}
Promise.all(promises).then(function (data) {
// iterate through all the data here
data.forEach(function (item, i) {
var $ = cheerio.load(item);
var name = $("#container span[itemprop='name']").text();
if (!name) {
console.log("null name returned, do nothing");
} else {
// name exists
person.where('id', i).fetch({require: true}).then(function (p) {
console.log(i + " exists");
}).catch(function () {
console.log(i + " does not exist");
new person({id: i, name: name}).save(null, {method: 'insert'}).then(function () {
console.log("success" + i);
});
});
}
}, function (err) {
// error occurred here
console.log(err);
});
});
});
答案 0 :(得分:2)
当您通过jshint运行代码时,您会看到一条警告
不要在循环中创建函数。
在这段代码中,then
内的回调不会与封闭的for
循环同步运行。它会在数据库提取结果时运行。
person.where('id', i).fetch().then(function (result) {
if (result) {
console.log(i + "exists");
} else {
console.log(i + " doesn't exist");
}
});
因此,当该回调最终运行时,循环已经很久完成了。您的回调函数包含对循环计数器i
的引用 - 到目前为止,其值为9.
使用接受参数的函数比引用循环计数器更好。
幸运的是节点使这很简单,你可以使用forEach
数组函数:
data.forEach(function (item, i) {
var $ = cheerio.load(item);
var name = $("#container span[itemprop='name']").text();
if (!name) {
console.log("null name returned, do nothing");
} else {
console.log("successfully scraped name: " + name);
person.where('id', i).fetch({require: true}).then(function (p) {
console.log(i + " exists");
}).catch(function () {
console.log(i + " does not exist");
});
}
});
请注意,您可以抛出Bookshelf.js而不是使用{require: true}
静默传递不存在的记录。
更一般地说,我没有看到从网站上抓取名称和从数据库中检索模型之间存在真正的联系。这两件事可能应该在单独的函数中完成,每个函数都返回相应事物的个体承诺。这样,对数据库的请求可以与对Web服务器的请求并行运行。
答案 1 :(得分:1)
看起来你需要person.where('id', i).fetch()
的封闭。
也使用node-fetch代替手动request-promise。