Node.js异步请求导致返回数组为空问题:如何等待请求完成后再返回结果?
解决Node.js中异步请求导致返回空数组的问题
你猜的没错,问题确实出在request的异步特性上!当你的getWeather函数执行到return arr这一行时,网络请求还在后台跑,根本没来得及把解析到的title塞进数组里,所以返回的自然是空数组。下面给你几种常用的解决办法:
方法1:使用回调函数(传统异步处理方式)
修改函数,让它接受一个回调参数,在请求完成并解析完数据后,调用这个回调把结果传出去:
module.exports = function getWeather(country, callback) { var arr = []; var pageToVisit = "https://www.timeanddate.com/weather/" + country; console.log("Visiting page " + pageToVisit); request(pageToVisit, function(error, response, body) { if (error) { console.log("Error: " + error); return callback(error, null); // 把错误传递给回调 } console.log("Status code: " + response.statusCode); if (response.statusCode === 200) { var $ = cheerio.load(body); console.log("Page title: " + $('title').text()); $('div.bk-focus__qlook').each(function(index) { var title = $(this).find('div.h2').text().trim(); console.log('title: ' + title); arr.push(title); }); callback(null, arr); // 请求成功,返回填充好的数组 } else { callback(new Error(`请求失败,状态码:${response.statusCode}`), null); } }); } // 调用示例 getWeather('china', function(err, weatherData) { if (err) { console.error(err); return; } console.log(weatherData); // 这里就能拿到完整的天气数据数组了 });
方法2:使用Promise封装(现代异步处理方式,支持async/await)
把异步请求封装成Promise,这样可以用async/await语法让代码看起来更像同步逻辑,可读性更好:
module.exports = function getWeather(country) { return new Promise((resolve, reject) => { var arr = []; var pageToVisit = "https://www.timeanddate.com/weather/" + country; console.log("Visiting page " + pageToVisit); request(pageToVisit, function(error, response, body) { if (error) { console.log("Error: " + error); return reject(error); // 抛出错误 } console.log("Status code: " + response.statusCode); if (response.statusCode === 200) { var $ = cheerio.load(body); console.log("Page title: " + $('title').text()); $('div.bk-focus__qlook').each(function(index) { var title = $(this).find('div.h2').text().trim(); console.log('title: ' + title); arr.push(title); }); resolve(arr); // 返回成功的结果 } else { reject(new Error(`请求失败,状态码:${response.statusCode}`)); } }); }); } // 调用示例(使用async/await) async function fetchWeather() { try { const weatherData = await getWeather('china'); console.log(weatherData); // 拿到填充好的数组 } catch (err) { console.error(err); } } fetchWeather();
额外建议:使用request-promise简化代码
如果不想自己手动封装Promise,可以直接使用request-promise(它是request的Promise化版本),代码会更简洁:
首先安装依赖:
npm install request-promise cheerio
然后修改代码:
const rp = require('request-promise'); const cheerio = require('cheerio'); module.exports = async function getWeather(country) { var arr = []; var pageToVisit = "https://www.timeanddate.com/weather/" + country; console.log("Visiting page " + pageToVisit); try { const body = await rp(pageToVisit); console.log("Status code: 200"); // rp在请求失败时会自动抛出错误 const $ = cheerio.load(body); console.log("Page title: " + $('title').text()); $('div.bk-focus__qlook').each(function(index) { var title = $(this).find('div.h2').text().trim(); console.log('title: ' + title); arr.push(title); }); return arr; } catch (error) { console.log("Error: " + error); throw error; // 将错误抛给调用者处理 } } // 调用示例 async function fetchWeather() { try { const weatherData = await getWeather('china'); console.log(weatherData); } catch (err) { console.error(err); } } fetchWeather();
内容的提问来源于stack exchange,提问作者Liad Ben moshe
相关产品推荐
相关产品推荐

