JavaScript 点赞/点踩计数器逻辑错误排查与修复记录
点赞/点踩计数器Bug修复记录
已修复该Bug并做代码记录,方便后续参考。之前开发点赞/点踩计数器时碰到逻辑错误:脚本原本要实现点击按钮可点赞/点踩或取消操作,且点赞后点踩(或反之)时对应计数器正常增减,但连续点击两个按钮后,其中一个计数器会被重置为0。
原问题代码
<script type="text/javascript"> var dislike_b = like_b = false; var num1 = 0; var like = parseInt("{{post.like_votes}}"); var num2 = 0; var dislike = parseInt("{{post.dislike_votes}}"); function likeHandler() { const xhr = new XMLHttpRequest(); if (dislike_b == true){ dislikeHandler(); //dislike_b = false ; } // like iterator like = like + (-1)**num1 ; num1 = (num1 + 1)%2; document.getElementById("like").innerHTML = like; like_b = !like_b; console.log( like , num1); $.ajax( { type: "POST", url: "/likepost/", data: { votes : like , csrfmiddlewaretoken: '{{ csrf_token }}' }, success: function (data) { $('#message').text(data); } }) } function dislikeHandler() { const xhr2 = new XMLHttpRequest(); if (like_b == true){ likeHandler(); } // like iterator dislike = dislike + (-1)**num2 ; num2 = (num2 + 1)%2; document.getElementById("dislike").innerHTML = dislike; dislike_b = !dislike_b; console.log( dislike , num1); $.ajax( { type: "POST", url: "/dislikepost/", data: { votes : dislike , csrfmiddlewaretoken: '{{ csrf_token }}' }, success: function (data) { $('#message').text(data); } }) } </script>
问题分析
- 递归调用引发状态混乱:当用户已点踩后点击点赞,
likeHandler会调用dislikeHandler,而dislikeHandler若检测到点赞状态又会回调likeHandler,导致状态被多次无规则修改,计数器计算逻辑彻底混乱。 - 计数依赖的中间变量未重置:切换点赞/点踩时,对方操作依赖的
num1/num2未被重置,后续再次操作时会基于错误的中间值计算,导致计数器异常重置。 - 状态标志更新时机错误:调用对方handler后才更新自身状态标志,逻辑判断的时序出现偏差,进一步加剧状态混乱。
修复后的代码
<script type="text/javascript"> let isLiked = false; let isDisliked = false; let likeCount = parseInt("{{post.like_votes}}"); let dislikeCount = parseInt("{{post.dislike_votes}}"); // 抽离DOM更新逻辑 function updateLikeDisplay() { document.getElementById("like").innerHTML = likeCount; } function updateDislikeDisplay() { document.getElementById("dislike").innerHTML = dislikeCount; } function likeHandler() { // 若当前有点踩状态,先取消点踩 if (isDisliked) { dislikeCount++; isDisliked = false; updateDislikeDisplay(); // 发送取消点踩请求 $.ajax({ type: "POST", url: "/dislikepost/", data: { votes: dislikeCount, csrfmiddlewaretoken: '{{ csrf_token }}' }, success: function (data) { $('#message').text(data); } }); } // 处理当前点赞操作:取消/添加 if (isLiked) { likeCount--; isLiked = false; } else { likeCount++; isLiked = true; } updateLikeDisplay(); // 发送点赞请求 $.ajax({ type: "POST", url: "/likepost/", data: { votes: likeCount, csrfmiddlewaretoken: '{{ csrf_token }}' }, success: function (data) { $('#message').text(data); } }); } function dislikeHandler() { // 若当前有点赞状态,先取消点赞 if (isLiked) { likeCount++; isLiked = false; updateLikeDisplay(); // 发送取消点赞请求 $.ajax({ type: "POST", url: "/likepost/", data: { votes: likeCount, csrfmiddlewaretoken: '{{ csrf_token }}' }, success: function (data) { $('#message').text(data); } }); } // 处理当前点踩操作:取消/添加 if (isDisliked) { dislikeCount--; isDisliked = false; } else { dislikeCount++; isDisliked = true; } updateDislikeDisplay(); // 发送点踩请求 $.ajax({ type: "POST", url: "/dislikepost/", data: { votes: dislikeCount, csrfmiddlewaretoken: '{{ csrf_token }}' }, success: function (data) { $('#message').text(data); } }); } </script>
修复说明
- 移除递归调用:不再通过调用对方handler处理切换,直接在当前函数内完成对方状态的清理,避免状态混乱。
- 简化状态管理:用
isLiked/isDisliked清晰标记当前状态,替代原有的模糊变量命名,逻辑更直观。 - 重构计数逻辑:直接通过增减操作更新计数器,去掉易混淆的
num1/num2中间变量,彻底避免计数重置错误。 - 拆分DOM更新:把显示更新逻辑抽成独立函数,代码结构更整洁,便于后续维护。
- 明确操作顺序:切换操作时先处理对立状态的清理,再执行当前操作,确保数据和状态的一致性。
内容的提问来源于stack exchange,提问作者Shaswat
相关产品推荐
相关产品推荐

