Promise内循环修改对象属性后resolve返回值未更新问题
问题描述
在Promise逻辑中通过循环为多个对象属性赋值时,执行函数并调用.then(() => console.log(r))打印结果,返回的r没有被修改为预期的赋值结果。
原实现代码
function assignSentenceImageDescription () { return new Promise((resolve, reject) => { assigningWordsPartOFSpeech().then((r) => { JSON.parse(r).sentences.forEach((sentence) => { let adjectiveBeforeNoun = []; let sentenceImageDescription = []; sentence.words.forEach((wordInSentence) => { try { if (wordInSentence.partOfSpeech[0].wordtype === "n.") { let imageDescription = adjectiveBeforeNoun.join('') + wordInSentence.partOfSpeech[0].word; sentenceImageDescription.push(imageDescription) adjectiveBeforeNoun = []; } else if (wordInSentence.partOfSpeech[0].wordtype === "superl.") { adjectiveBeforeNoun.push(wordInSentence.partOfSpeech[0].word + " ") } } catch (e) { console.log("===NOT IN DICTIONARY===") } }) sentence.imageDescription = sentenceImageDescription; } ) resolve(r); } ); } ); }
问题根因
- 核心错误:
JSON.parse(r)每次执行都会生成一个全新的独立JavaScript对象,遍历、赋值操作都是在这个临时生成、没有被任何变量保存的对象上执行的,操作完成后临时对象会被直接回收,修改根本不会同步到原始的r值上。 - 冗余写法:外层额外包了一层
new Promise,属于Promise嵌套反模式,没有实际意义还容易引入逻辑错误。 - 最后
resolve(r)传递的还是原始的、未做任何修改的r字符串,打印结果自然看不到新增的imageDescription属性。
修复后代码
function assignSentenceImageDescription () { return assigningWordsPartOFSpeech().then((r) => { // 先把JSON解析结果存到变量,所有修改都在这个对象上操作 const parsedData = JSON.parse(r); parsedData.sentences.forEach((sentence) => { let adjectiveBeforeNoun = []; let sentenceImageDescription = []; sentence.words.forEach((wordInSentence) => { try { if (wordInSentence.partOfSpeech[0].wordtype === "n.") { let imageDescription = adjectiveBeforeNoun.join('') + wordInSentence.partOfSpeech[0].word; sentenceImageDescription.push(imageDescription) adjectiveBeforeNoun = []; } else if (wordInSentence.partOfSpeech[0].wordtype === "superl.") { adjectiveBeforeNoun.push(wordInSentence.partOfSpeech[0].word + " ") } } catch (e) { console.log("===NOT IN DICTIONARY===") } }) sentence.imageDescription = sentenceImageDescription; }) // 如果后续需要JSON字符串就返回JSON.stringify(parsedData),需要对象直接返回parsedData即可 return parsedData; }); }
修复要点
- 把JSON解析的结果存入固定变量,所有属性修改操作都针对这个持久引用的对象执行,避免修改临时对象导致修改丢失
- 移除多余的外层Promise包装,直接返回Promise链的结果,简化逻辑层级
- 最终返回的是已经完成属性赋值的完整数据,而非原始未修改的入参r
内容的提问来源于stack exchange,提问作者Xavi Font
相关产品推荐
相关产品推荐

