2014-09-03 106 views
0

我是新的Node.js和承諾(在這裏,我使用Q.js)。 我試圖使刮板出其具有如下結構的網站:JQuery與嵌套循環的異步承諾

  • main_page:已分類的列表,每個類別都有一個指向存儲頁面的列表的鏈接。
  • 商店列表頁面:有一個商店列表,每個商店都有一個指向商店詳細信息頁面的鏈接。
  • 商店詳細信息頁面:有我正在尋找的數據。

我做了第一個沒有承諾的工作方法,但結果代碼非常難看。所以我認爲這是使用承諾的好例子。

我不能得到這種方法的工作。當第二個循環完成時,應用程序不會繼續(它永遠不會執行end()方法)。另外,我不知道如何附加第三個循環。

我該怎麼辦?

function get(url) { 
    var deferred = Q.defer(); 
    requestify.get(url).then(function(response) { 
     deferred.resolve(cheerio.load(response.getBody())); 
    }); 
    return deferred.promise; 
} 

function process_main_page($) { 
    var promises = []; 
    $('.categories a').each(function(i) { 
     var deferred = Q.defer(); 
     var storesList = $('.store'); 
     get($(this).attr('href')).then(function($) { 
      deferred.resolve(process_stores_list(storesList)); 
     }); 
     promises.push(deferred); 
    }); 
    return Q.all(promises); 
} 

function process_stores_list(storesList) { 
    var promises = []; 
    storesList.each(function() { 

     // Here I need to make another ajax call for each store detail page, which has the data that I need. 

     promises.push(deferred); 
    }); 
    return Q.all(promises); 
} 

function end(res) { 
    var deferred = Q.defer(); 
    fs.writeFile('output.json', JSON.stringify(myGatheredData, null, 4), function(err) { 
     deferred.resolve(function() { 
      res.send('File successfully written! - Check your project directory for the output.json file'); 
     }); 
    }); 
    return deferred.promise; 
} 

app.get('/', function(req, res) { 
    get(url).then(process_main_page).then(end); 
}); 
+1

http:// jsfiddle。net/arunpjohny/v917j5ec/5/ – 2014-09-03 04:15:15

+2

你的代碼充滿了延期反模式:(考慮閱讀並修復它。 – 2014-09-03 06:00:47

回答

2

由於@BenjaminGruenbaum已經評論,你的代碼是散落着的deferred antipatternQ.defer()唯一(或多或少)合法使用的是fs.writeFile,但您忘記了在那裏處理錯誤。這只是簡單的promisify that API

我無法得到這種方法的工作。

整體結構似乎很好。然而,一些要點:

  • 你似乎從沒有從商店頁面獲取stores_list。您可以獲取該頁面,但通過類別頁面中的var storesList = $('.store');來解決承諾?
  • 您的end方法確實獲得了myGatheredData - 結果數組加入了Q.all - 作爲其參數傳遞。它沒有任何訪問ponse對象的權限。

當第二個循環完成時,應用程序不會繼續(它永遠不會執行end()方法)。另外,我不知道如何附加第三個循環。

我認爲這是原因 - 你可能已經在構建Q.all()數組的延期,但從未解決它們。這使得返回的承諾「掛起」(保持待定),並且從未調用過回調函數。

var write = Q.nbind(fs.writeFile, fs); 
function get(url) { 
    return requestify.get(url).then(function(response) { 
     return cheerio.load(response.getBody())); 
    }); 
} 

function process_main_page($_main) { 
    var promises = $_main('.categories a').map(function(i) { 
     // var storesList = $_main('.store'); // not sure what this did 
     return get($_main(this).attr('href')).then(process_storelist_page); 
    }).toArray(); 
    return Q.all(promises); 
} 
function process_storelist_page($_stores) { 
    return process_stores_list($_stores('a.store').map(function() { 
     return $_stores(this).attr('href'); // whatever? 
    }).toArray()); 
} 

function process_stores_list(storesList) { 
    var promises = $.map(storesList, function(store_url) { 
     // Here make another ajax call for each store detail page 
     return get(store_url).then(process_store_page);); 
    }); 
    return Q.all(promises); 
} 
function process_store_page($_store) { // which has the data that I need. 
    return /* select some data from the page */; 
} 
function save_data(myGatheredData) { 
    return write('output.json', JSON.stringify(myGatheredData, null, 4)).then(function() { 
     return 'File successfully written! - Check your project directory for the output.json file'; 
     }); 
    }); 
} 

app.get('/', function(req, res) { 
    get(url).then(process_main_page).then(save_data).then(function end(result) { 
     res.send(result); 
    }); 
}); 

當然,你也可以用函數表達式而不是我已經使用的函數聲明來嵌套所有東西。