JavaScript中使用replace方法时Promise返回[object Promise]问题
解决String.replace异步回调返回[object Promise]的问题
问题情况
在使用String.replace()处理字符串时,给回调函数添加了async关键字,意图通过调用Service.post接口获取数据后生成<img>或<div>标签,但实际输出结果是[object Promise],而非预期的HTML元素。
原代码示例:
str.replace(/!([^|!]*(?:jpe?g|png|gif|mp4|mp3|mkv|mov))(?:\|width=(\d*\.?\d+%?)(?:,height=(\d*\.?\d+%?))?)?!/gm, async (match, capture) => { let m, reg = /!([^|!]*(?:jpe?g|png|gif|mp4|mp3|mkv|mov))(?:\|width=(\d*\.?\d+%?)(?:,height=(\d*\.?\d+%?))?)?!/gm; let imageConfig = []; while ((m = reg.exec(str)) !== null) { imageConfig.push({ file: m[1], width: (m[2] || ''), height: (m[3] || '') }); } let payload = { 'columns': [ { 'id': columnMeta.id, 'values': [ { "type": "@thumbnail", "values": imageConfig.map(e => e?.file) }, ] } ] } payload.rowId = rowData?.id; let reolvedFile = []; let response = await Service.post( generateAPIURL({ boardId: TableHelper.getwrapperConfig?.boardId, tableId: TableHelper.getwrapperConfig?.tableId, columnId: columnMeta?.id, type: "getresolvedValue", }), null, JSON.stringify({ ...payload }) ) let values = response?.columns?.[0]?.values; imageConfig.map(e => e?.file)?.map(o => { let index = values?.findIndex(e => e?.name === o); if (index !== -1) { reolvedFile.push(values[index]); } }) //Find the matching entry var info = reolvedFile?.find(({ name }) => name === capture); let width = imageConfig.find((e) => e?.file === capture)?.width || 200; let height = imageConfig.find((e) => e?.file === capture)?.height || 200; return info ? `<img src="${info?.thumbnail}" data-name="${info?.name}" width=${width} height=${height} style="width:'${width}px';height:'${height}px';display: inline-block;"/>` : `<div id="${capture}" data-name="${capture}" class="linear-background" style="width:'${width}px';height:'${height}px';display: inline-block;" ></div>`; })
问题根源
async函数的返回值是一个Promise对象,而String.replace()的回调函数是同步执行的,它不会等待Promise完成,直接把Promise对象转成了字符串[object Promise],所以得不到预期的HTML结果。
另外原代码存在冗余:每次回调里都重复执行正则匹配整个字符串,完全没必要,应该提前一次性提取所有匹配项。
解决方案
步骤如下:
- 提前一次性提取字符串中所有匹配的文件配置,避免重复执行正则
- 批量请求接口获取所有文件的解析数据,减少请求次数
- 完成异步请求后,再同步替换字符串
修改后的代码:
// 1. 提前提取所有匹配项的完整配置 const reg = /!([^|!]*(?:jpe?g|png|gif|mp4|mp3|mkv|mov))(?:\|width=(\d*\.?\d+%?)(?:,height=(\d*\.?\d+%?))?)?!/gm; const imageConfigList = []; let match; while ((match = reg.exec(str)) !== null) { imageConfigList.push({ fullMatch: match[0], // 保存完整匹配串,用于后续替换 fileName: match[1], width: match[2] || '200', height: match[3] || '200' }); } // 2. 批量请求接口获取所有文件的解析数据 const payload = { rowId: rowData?.id, columns: [ { id: columnMeta.id, values: [ { "type": "@thumbnail", "values": imageConfigList.map(item => item.fileName) }, ] } ] }; const response = await Service.post( generateAPIURL({ boardId: TableHelper.getwrapperConfig?.boardId, tableId: TableHelper.getwrapperConfig?.tableId, columnId: columnMeta?.id, type: "getresolvedValue", }), null, JSON.stringify(payload) ); const resolvedFiles = response?.columns?.[0]?.values || []; // 3. 构建文件映射表,快速查找对应解析数据 const fileMap = new Map(); resolvedFiles.forEach(file => fileMap.set(file.name, file)); // 4. 同步替换字符串 let resultStr = str; imageConfigList.forEach(item => { const fileInfo = fileMap.get(item.fileName); const replacement = fileInfo ? `<img src="${fileInfo.thumbnail}" data-name="${fileInfo.name}" width=${item.width} height=${item.height} style="width:${item.width}px;height:${item.height}px;display: inline-block;"/>` : `<div id="${item.fileName}" data-name="${item.fileName}" class="linear-background" style="width:${item.width}px;height:${item.height}px;display: inline-block;"></div>`; resultStr = resultStr.replace(item.fullMatch, replacement); }); // 最终使用处理后的resultStr即可 console.log(resultStr);
关键优化点
- 把异步操作从
replace回调中抽离,先完成所有异步请求,再做同步替换,避免Promise被转成字符串 - 提前提取所有匹配项,避免重复执行正则,提升性能
- 用
Map构建文件映射表,快速查找对应文件的解析数据,比每次用find效率更高
内容的提问来源于stack exchange,提问作者Man
相关产品推荐
相关产品推荐

