2013-08-20 1 views
0

새 차량을 시장에 나와 있습니다. 반복적으로 대리점 웹 사이트를 검색하는 대신, 나는 작은 노드와 몽고범을 배울 수있는 흥미롭고 재미있는 기회가 될 것이라고 생각 했으므로 관심있는 제조업체와 모델을 얻기 위해 현지 판매점의 웹 사이트를 긁어 모으고있다.DB를 업데이트해도 Node.js 콜백은 MongoDB 업데이트로 되돌아 오지 않습니다.

내가 겪고있는 문제는 최종 콜백이 끝난 후에 노드가 종료되지 않는다는 것입니다.

var cheerio = require('cheerio'); 
var request = require('request'); 
var db = require('mongodb'); 
var S = require('string'); 
var log = require('console').log; 
var async = require('async'); 

var links = []; 
var website = 'http://www.yahoo.com'; 

async.series(
    [ 
     function(){ 
      log('starting'); 
      db.connect('mongodb://127.0.0.1:27017/test', 
       function(err, base){ 
        if(err) throw err; 
        db = base; 
       }); 
     }, 
     request(website, start) 
    ], 
     function(){ 
      log('closing DB'); 
      db.close(); 
    }); 

function start(err,resp,body){ 
    var $ = cheerio.load(body); 
    var numPages = 2; 
    $('.gbps').each(function(i,elem) { 
     links.push('http://www.yahoo.com'); 
    }); 

    var pageURLS = []; 
    for (var i = 2; i<=numPages; i++){ 
     //create URLs for additional pages 
     pageURLS[i-2] = website; 
    } 
    var pages = 1; 
    log('getting page URLs'); 
    pageURLS.forEach(function(url, index, array){ 
     request(url, function(error,response,bodies) { 
      pages++; 
      var $ = cheerio.load(bodies); 
      $('.tab').each(function(i,elem) { 
       links.push('http://www.yahoo.com'); 
      }); 
      if (pages == numPages){ 
       getDetailInfo(); 
      }; 
     }); 
    }); 
} 

function getDetailInfo(){ 
    log(links.length); 
    links.forEach(function(link, index, array){ 
     request(link, doStuff); 
    }); 
} 

function doStuff(err, response, body){ 
    if(err){ 
     log(err); 
    } 
    parseDetailResponse(err,response,body, addToDB); 
} 

function parseDetailResponse(err,resp,body,callback){ 
    log('parsing'); 
    var $ = cheerio.load(body); 
    var specs = $('.specifications').children().map(function(i, elem){ 
     var key = 'key'; 
     var value = 'value'; 
     var ret = {}; 
     ret [ 'name' ] = key; 
     ret [ 'value' ] = value; 
     return ret; 
    }); 
    var makeAndModel = 'makeAndModel'; 
    callback(['picture url', 'vehicle description', 100, specs, makeAndModel]); 
} 

function getMakeAndModel(stuff){ 
    var $ = cheerio.load(stuff); 
    temp = $('.gbps').map(function(i, elem){ 
     var ret = {}; 
     switch(i){ 
      case 0: 
       ret['name'] = 'year'; 
       ret['value'] = $(this).text(); 
       break; 
      case 1: 
       ret['name'] = 'make'; 
       ret['value'] = $(this).text(); 
       break; 
      case 2: 
       ret['name'] = 'model'; 
       ret['value'] = $(this).text(); 
       break; 
      case 3: 
       ret['name'] = 'ignore'; 
       ret['value'] = $(this).text(); 
       break; 
      default: 
       ret['name'] = 'ignore'; 
       ret['value'] = 'ignore'; 
     } 
     return ret; 
    }); 
    return temp; 
} 

function addToDB(arr){ 
    log('adding to DB'); 
    pic = arr[0]; 
    description = arr[1]; 
    price = arr[2]; 
    specs = arr[3]; 
    makeAndModel = arr[4]; 

    var obj = {}; 
    for (var i = specs.length - 1; i >= 0; i--) { 
     obj [specs[i].name] = specs[i].value; 
    }; 
    for (var i = makeAndModel.length - 1; i >= 0; i--){ 
     obj [makeAndModel[i].name] = makeAndModel[i].value; 
    }; 
    db.collection('carsTest').update(
     {VIN: obj.VIN}, 
     { 
      $set: { 
       VIN: obj.VIN, 
       make: obj.make, 
       model: obj.model, 
       year: obj.year, 
       price: price, 
       engine: obj.Engine, 
       interior: obj.Interior, 
       exterior: obj.Exterior, 
       'model code': obj['Model Code'], 
       'stock number': S(obj['Stock Number']).toInt(), 
       transmission: obj.Transmission, 
       mileage: obj.Mileage ? obj.Mileage : 0, 
       description: description, 
       picture: pic, 
      } 
     }, 
     {upsert: true, safe: true}, 
     function(err,result){ 
      if(err){ 
       throw err; 
      } 
     }); 
    log('finished with this one!'); 
} 

나는 생략하고 오류 검사 또는 아무것도를 많이하지 않고 여기에 증거로 상당한 양의 변경되었지만에도이 문서를 추가하지만 종료되지 않습니다했습니다. 노드는 거기에 앉아서 어떤 일이 생길 때까지 대기하고 최종 콜백을 호출하여 데이터베이스를 닫고 종료하지 않습니다.

> db.carsTest.find().pretty() 
{ 
    "_id" : ObjectId("52139aa7c9b7a39e0f1eb61d"), 
    "VIN" : null, 
    "description" : "vehicle description", 
    "engine" : null, 
    "exterior" : null, 
    "interior" : null, 
    "make" : null, 
    "mileage" : 0, 
    "model" : null, 
    "model code" : null, 
    "picture" : "picture url", 
    "price" : 100, 
    "stock number" : NaN, 
    "transmission" : null, 
    "year" : null 
} 

답변

2

나는 async.series이 어떻게 작동하는지 오해한다고 생각합니다.

async.series의 함수는 callback을 인수로 사용하지 않으며 호출하지 않습니다. 그리고 그 request(...) 물건은 아마도 전혀 기능이 아닙니다. 이것이 비동기 루프가 깨지는 이유입니다. 이 시도 : start를 호출 할 때 내가 callback 인수를 추가 한

async.series(
    [ 
     function(callback) { // <--- missing callback 
      log('starting'); 
      db.connect('mongodb://127.0.0.1:27017/test', 
       function(err, base){ 
        if(err) throw err; 
        db = base; 
        callback(); // <--- missing callback 
       }); 
     }, 
     function(callback) { // <--- missing function with callback 
      request(website, function(err,resp,body) { 
       start(err, resp, body, callback); 
      }) 
     } 
    ], 
    function(){ 
     log('closing DB'); 
     db.close(); 
    } 
); 

참고. 따라서 모든 기능이 완료되도록 callback을 받아 들일 수 있도록 코드를 리팩토링해야합니다. 모든 작업이 완료되었다는 것을 알았을 때 마지막에 호출 할 수 있습니다. 예를 들어, 당신은 start 내부 async.parallel을 추가 할 수 있으며이 기능은 다음과 같이 보일 수 있습니다 :

function start(err, resp, body, callback) { 
    // some stuff happens here 
    var jobs = [] 
    pageURLS.forEach(function(url, index, array){ 
     jobs.push(function(clb) { 
      request(url, function(error,response,bodies) { 
       // some stuff 
       clb(); // <--- this refers to the local callback for the job 
      }); 
     }); 
    }); 
    async.parallel(jobs, function() { 
     // all jobs are done, let's finilize everything 
     callback(); 
    }); 
}; 
+0

확실히 오해 방법 비동기 작동합니다. 미안하지만 며칠 만에 다시 당신에게 다가 갔지만, 부차적 인 프로젝트이기 때문에 많은 시간을 할애하지 못했습니다. –

관련 문제