目前在做《Node.js 包教不包会》https://github.com/alsotang/node-lessons里的《使用 eventproxy 控制并发》这一课。在异步请求上有个疑问想请大家帮忙解答。 我没有用eventproxy来操作,一开始是用promise.all和async来操作的。发现后台报了很多503,不知道是不是我异步哪里写错了,就改成单纯遍历数组,在每个元素进行axios请求来操作。 我感觉出现问题的代码是在这部分,想问的问题是异步请求到的数组存入数组后为什么输出到页面是空数组。在后台打印却能正常输出??我这个代码要改的话要怎么改呢
let output =[]; //output数组是用来存放爬到的文章title,author和第一条评论
newArr.forEach(element => { //newArr是一个包含了很多个地址的数组,目前假定是存了3个地址
axios.get(element).then((res) => {
let $ = cheerio.load(res.data);
let result = [];
let title = $('.topic_full_title').text();
let author = $('.user_name a').text();
let comment1 = $('.reply_content').first().text();
result.push({
title,
author,
comment1
})
return result;
}).then((result) => {
output.push(result);
})
});
console.log(output);
res.send(output);
*** 我发现启动服务之后,在页面上输出的将会是空数组,但是后台打印出output数组却是正确的存放着3组数据,长度也是3. 另外,如果newArr如果长度超过十几个的话,后台会打印出503的error,是cnode论坛的防并发导致的吗??***
完整的代码是这样子的。
const express = require(‘express’); const app = express(); const cheerio = require(‘cheerio’); const axios = require(‘axios’); app.get(’/’, (req, res, next) => { axios.get(‘https://cnodejs.org/’).then((response) => { let $ = cheerio.load(response.data); let items = []; let urlList = []; $(’#topic_list .topic_title’).each((index, element) => { let $element = $(element); items.push({ title: $element.attr(‘title’), href: $element.attr(‘href’) }); urlList.push(‘https://cnodejs.org’ + $element.attr(‘href’)); }); return urlList; }).then((urlList) => { let newArr = urlList.slice(0, 3); let output =[]; newArr.forEach(element => { axios.get(element).then((res) => { let $ = cheerio.load(res.data); let result = []; let title = $(’.topic_full_title’).text(); let author = $(’.user_name a’).text(); let comment1 = $(’.reply_content’).first().text(); result.push({ title, author, comment1 }) return result; }).then((result) => { output.push(result); }) }); console.log(output); res.send(output); }).catch((err) => { console.error(err); });
})
app.listen(8000, () => { console.log(‘App listening on port 8000!’); });
1、newArr.forEach是同步,axios.get是异步,当返回output时,异步还没有完成 2、建议用p-map,可以控制并发数
const pMap = require('p-map');
// concurrency
const mapper = article => {
// render article
return this._renderArticle({ site, article });
};
await pMap(articles, mapper, { concurrency: 10 });
你可以试试async 跟await, 要么代码逻辑就得变,具体原因1楼已经说了。