map函数内使用setTimeout时Done提前执行的问题求解
问题解决:异步任务导致"Done"提前弹出
问题原因
JavaScript中setTimeout属于异步任务,会被放入事件队列等待同步代码执行完毕后才触发。你的代码里,map会立刻遍历完数组所有元素并创建setTimeout任务,但这些任务还没执行时,同步代码alert("Done")已经先运行了,所以"Done"会比索引弹窗先出现。另外你代码里的if (index === 5)没有意义,因为arrayImages[0]只有3个元素,索引最大是2,永远不会触发这个判断。
解决方案1:用async/await按顺序执行
将clickMe改为异步函数,通过Promise包装setTimeout,配合for...of遍历实现顺序等待,最后再弹出"Done":
const arrayImages = [ [ { url: 'img/man.jpg' }, { url: 'img/bike.jpg' }, { url: 'img/sun.jpg' } ] ] async function clickMe(){ for (const [index] of arrayImages[0].entries()) { await new Promise(resolve => { setTimeout(() => { alert(index); resolve(); }, 2000); }); } alert("Done"); }
解决方案2:收集Promise等待全部完成
如果想保留map的写法,可以把每个setTimeout包装成Promise,用Promise.all等待所有异步任务完成后再弹出"Done":
const arrayImages = [ [ { url: 'img/man.jpg' }, { url: 'img/bike.jpg' }, { url: 'img/sun.jpg' } ] ] function clickMe(){ const promises = arrayImages[0].map((element, index) => { return new Promise(resolve => { setTimeout(() => { alert(index); resolve(); }, 2000 * index); }); }); Promise.all(promises).then(() => { alert("Done"); }); }
两种方案都能保证所有索引弹窗完成后才弹出"Done",第一种是严格按顺序等待每个弹窗关闭后再执行下一个,第二种是按预设时间触发弹窗,最后等所有弹窗都处理完再显示"Done"。
内容的提问来源于stack exchange,提问作者user122222
相关产品推荐
相关产品推荐

