使用Axios循环请求服务端数据并按调用顺序存入数组的实现问题
问题说明
需求为在循环逻辑中从服务端拉取数据,严格按照请求发起的顺序将响应结果存入数组。此前先后尝试递归、Promise、async/await、同步请求等多种实现方案,累计调整7版代码,均未实现按顺序存储响应的效果,当前基于Axios编写的递归实现代码如下:
let currentPhraseWordAssign = []; function addPartOfSpeechAndWordPhrasesToFullScript () { assignPartOfSpeechAndAddToPhraseArray(["phrase", "run"]).then(() => {console.log(currentPhraseWordAssign)}); } async function assignPartOfSpeechAndAddToPhraseArray (phrase) { if(currentPhraseWordAssign.length >= phrase.length) { console.log(currentPhraseWordAssign); currentPhraseWordAssign = []; return; } let word = phrase[currentPhraseWordAssign.length]; axios({ method: 'get', url: `http://localhost:9200/english_minus_verbs/_search`, headers: { 'Content-Type': 'application/json' }, data: { _source: ["part_of_speech"], query: { term: { word: word, } } } }).then((r) => { try { currentPhraseWordAssign.push({word: word, partOfSpeech: r.data.hits.hits[0]._source.part_of_speech}); }catch (e) { currentPhraseWordAssign.push({word: word, partOfSpeech: 'verb'}); } }).then(()=>{ assignPartOfSpeechAndAddToPhraseArray(phrase); }); }
现有代码逻辑问题
- 标记为
async的函数内部没有对axios异步请求做await或返回Promise实例,外层调用的.then会在函数刚启动、第一个请求还没返回时就触发,此时结果数组还未填充完成,打印时机完全错误。 - 结果存在全局变量
currentPhraseWordAssign中,多次触发函数时会出现数据互相污染的问题,且递归终止时直接清空全局数组,外层拿到的引用会指向空数组。 - 没有对axios请求本身做异常捕获,单个请求报错会直接打断整个递归链,没有兜底处理。
修复方案
要严格保证结果顺序和请求发起顺序一致,有两种可落地的实现:
方案1:串行请求(逻辑最直观)
等上一个请求拿到结果存入数组后,再发起下一个请求,全程用async/await控制异步流程,不依赖全局变量存结果。
async function assignPartOfSpeechAndAddToPhraseArray(phrase) { const result = []; for (const word of phrase) { try { const r = await axios({ method: 'get', url: `http://localhost:9200/english_minus_verbs/_search`, headers: { 'Content-Type': 'application/json' }, data: { _source: ["part_of_speech"], query: { term: { word } } } }); result.push({ word, partOfSpeech: r.data.hits.hits[0]._source.part_of_speech }); } catch (e) { // 接口报错、返回结构不符合预期都走兜底逻辑 result.push({ word, partOfSpeech: 'verb' }); } } return result; } function addPartOfSpeechAndWordPhrasesToFullScript() { assignPartOfSpeechAndAddToPhraseArray(["phrase", "run"]).then(res => { console.log(res); // 拿到的结果严格和输入词顺序一致 }); }
方案2:并行请求(性能更高)
同时发起所有请求,通过Promise.all等待所有请求返回,Promise.all返回的结果顺序和传入的Promise数组顺序严格一致,完全满足顺序要求,请求耗时为所有请求中最长的单个请求耗时,比串行方案快很多。
async function assignPartOfSpeechAndAddToPhraseArrayParallel(phrase) { const requestPromises = phrase.map(async (word) => { try { const r = await axios({ method: 'get', url: `http://localhost:9200/english_minus_verbs/_search`, headers: { 'Content-Type': 'application/json' }, data: { _source: ["part_of_speech"], query: { term: { word } } } }); return { word, partOfSpeech: r.data.hits.hits[0]._source.part_of_speech }; } catch (e) { return { word, partOfSpeech: 'verb' }; } }); return Promise.all(requestPromises); }
内容的提问来源于stack exchange,提问作者Xavi Font
相关产品推荐
相关产品推荐

