我是Node.js和promises的新手(在这里,我正在使用Q.js)。 我正在尝试从具有以下结构的站点中制作一个刮板:
我做了第一个没有承诺的工作方法,但结果代码非常难看。所以我认为这是使用promises的好例子。
我无法使用这种方法。第二个循环完成后,应用程序不会继续(它永远不会执行 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);
});
答案 0 :(得分:2)
正如@BenjaminGruenbaum已经评论过,你的代码充斥着deferred antipattern。 Q.defer()
的唯一(或多或少)合法使用是fs.writeFile
,但您忘记在那里处理错误。 promisify that API更容易。
我无法使用这种方法。
整体结构似乎很好。但是,有些观点:
stores_list
。您获取该页面,但是从类别页面解析了var storesList = $('.store');
的承诺?end
方法确实获得了myGatheredData
- Q.all
加入的结果数组 - 作为参数传递。它无法访问res
ponse对象。当第二个循环完成后,应用程序不会继续(它永远不会执行end()方法)。此外,我不知道如何附加第三个循环。
我认为原因是 - 您可能已经构建了Q.all()
数组的延迟,但从未解决过它们。这使得返回的承诺"挂起" (保持待定状态),并且从未调用过end
回调。
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);
});
});
当然你也可以用函数表达式而不是我用过的函数声明来嵌套所有东西。