Node.js异步订单

时间:2015-12-03 00:55:08

标签: node.js asynchronous request cheerio

当我使用async模块和bookshelf.js orm时,重复记录(人员角色)正在添加到数据库中,即使我在添加它们之前检查,我也无法找出原因。

简而言之,这就是我想要实现的目标。

  • 访问一些网址(与此同时,它是一个网络抓取工具,每次访问10个网址,感谢http.globalAgent.maxSockets),抓取person idperson nameroles。< / LI>
  • 如果数据库中存在某个人(我使用人员ID检查它,它与我从网址中获取的ID相同),请添加他/她。如果记录存在,请不要做任何事情。
  • 获取此人的角色名称并查询数据库。如果数据库中不存在该角色,请先添加该角色,获取其ID,然后将其添加到数据透视表(多人关系,因为一个人可以拥有多个角色)如果角色存在,只需添加它与相关person_id的数据透视表。

我正在使用asyncrequestcheeriobookshelf.js

app.get('/async', function (req, res) {

  var urlArr = [];
  for (var i = 10; i < 100; i++) {
    urlArr.push("http://www.example.com/person/" + i + "/personname.html");
  }
  async.each(urlArr, function (url, callback) {
      request({
        url: url,
        headers: {
          'User-Agent': req.headers['user-agent'],
          'Content-Type': 'application/json; charset=utf-8'
        }
      }, function (err, resp, body) {
        if (err) {
          console.log(err);
        } else {
          if (cheerio.load(body)) {
            var $ = cheerio.load(body);
            var links = $('#container');
            var name = links.find('span[itemprop="name"]').html(); // name
            if (name == null) {
              console.log("null returned, do nothing");
            } else {
              name = entities.decodeHTML(name);
              var r = url.substring(33, 35);
              person.where('id', r).fetch({require: true}).then(function (p) {
                // person exists, don't do anything
              }).catch(function () {
                // person doesn't exist, proceed
                var numberOfRoles = links.find('span[itemprop="roletitle"]').length; // number of roles
                new person({id: r, name: name}).save(null, {method: 'insert'}).then(function (returnval) {
                  var rolesArr = [];
                  for (var b = 0; b < numberOfRoles; b++) {
                    rolesArr.push(b);
                  }
                  async.each(rolesArr, function (roles, callback) {
                    var personTypes = $('span[itemprop="roletitle"]').eq(roles).text();
                    var personTypes = entities.decodeHTML(personTypes);

                    personRole.where('role', personTypes).fetch().then(function (data1) {
                      // role exists, add the role_id and person_id to the pivot table
                      new personPersonRole({
                        person_id: r,
                        personrole_id: data1.id
                      }).save().then(function (data2) {
                        console.log("role has been added");
                      });
                    }).catch(function () {
                      // role doesn't exist, add it first
                      new personRole({
                        role: personTypes
                      }).save().then(function (data3) {
                        console.log("new added role_id is : " + data3.id);
                        // add person_id and role_id to the pivot table
                        new personPersonRole({
                          person_id: r,
                          personrole_id: data3.id
                        }).save();
                      });
                    });
                    callback();
                  });
                });
              });
            }
          }
          else {
            console.log("can't open");
          }
        }
      });
      callback();
    },
    function (err) {
      if (err) {
        console.log("err");
      } else {
        console.log("success");
      }
    });
});

1 个答案:

答案 0 :(得分:0)

它看起来像多线程或异步编程中的常见问题。可能发生的事情是:

  • Scraper被告知要抓取URL A
  • Scraper被告知要刮掉URL B
  • ...
  • 询问网址A中的角色X是否存在
  • 询问URL B中的角色X是否存在
  • 时间过去了; MySQL确定X不存在,触发对URL A处理程序的回调
  • 时间过去了; MySQL确定X不存在(再次),触发对URL B处理程序的回调
  • URL处理程序的回调弹出事件队列;告诉MySQL为URL A创建角色X
  • URL B处理程序的回调弹出事件队列;告诉MySQL为URL B创建角色X

您需要做的非常简单:在数据库中创建角色名UNIQUE。这不会阻止代码尝试两次创建角色,但它会使每次失败但只失败一次。然后不要检查角色是否存在;只是尝试每次创建它。

或者,有一个clever trick with SQL,如果它不存在,您可以在其中插入。它可能适用于书架,也可能不适用,但我没有勇气尝试。