异步JS开发使用setTimeout时执行逻辑不符合预期问题求助
问题根因与修复方案
1. HTML仅显示前两个帖子的问题
你在addPost的定时器回调逻辑中,先执行了遍历数组拼接HTML、写入页面的操作,之后才调用posts.push(post)插入新帖子,渲染阶段第三篇帖子还没有被加入数组,自然不会出现在页面上。只需要把posts.push(post)的调用时机挪到遍历渲染逻辑之前即可修复。
2. console.log异常提前显示3个对象的问题
这是浏览器控制台的原生特性导致的,和代码异步逻辑无关:
- 当你用
console.log打印对象、数组这类引用类型时,控制台保存的是该引用的地址,不是调用log这一刻的内容快照 - 当你手动点击展开控制台里打印的数组时,浏览器才会读取该引用当前的最新内容
- 如果展开操作发生在
addPost的5秒定时器执行完毕之后,你就会看到已经插入了第三个元素的数组,看起来就像log提前执行了一样
如果需要打印调用console.log那一刻的准确内容,改为打印数组的浅拷贝即可:console.log([...posts])
代码执行时序说明
你的代码实际执行顺序完全符合定时器的延迟设置,不存在逻辑异常:
- 同步执行最外层代码:打印初始posts数组、注册5秒延迟的addPost定时器、注册1秒延迟的getPosts定时器
- 1秒后触发getPosts回调:打印begin getpost、此时只有2个元素的posts数组、end getpost
- 再过4秒(总计时长5秒)触发addPost回调:打印begin addpost、遍历当前2个元素渲染页面、插入第三个元素、打印end addpost
修复后的代码
const posts = [{ body: "I am Post One", title: "Post One" }, { body: "I am post two", title: "Post Two" } ] function addPost(post) { setTimeout(function() { console.log("begin addpost"); // 先插入新帖子再渲染 posts.push(post); let output = "<p> "; posts.forEach(function(post) { output += (post.body + "<br/>"); }); output += "</p>"; document.body.innerHTML = output; console.log("end addpost"); }, 5000); } function getPosts() { setTimeout(function() { console.log("begin getpost"); // 打印浅拷贝得到当前时刻的快照 console.log([...posts]); console.log("end getpost"); }, 1000); } // 打印浅拷贝得到当前时刻的快照 console.log([...posts]); addPost({ body: "I am post Three", title: "Post Three" }); getPosts();
内容的提问来源于stack exchange,提问作者Mail
相关产品推荐
相关产品推荐

