jQuery AJAX.done()执行正常但阻塞聊天消息拉取功能,该如何解决?
问题原因
- 核心诱因是PHP会话(Session)锁定:PHP默认使用文件存储Session,同一个客户端发起的同Session请求会被服务端排队,第一个请求会锁定Session文件,后续同Session的请求必须等前一个请求执行完毕释放锁后才能执行。你的chat-mail.php执行发邮件逻辑需要5-10秒,全程持有Session锁,导致同期的get-chat.php拉取请求全部被阻塞在服务端排队,看起来就像前端定时任务被卡住。
- 次要原因是浏览器同域名并发请求限制:主流浏览器对同一个域名的并发请求数限制通常为6-8个,长耗时的发邮件请求占住连接后,也可能导致后续拉取请求被浏览器端排队。
解决方案
按照改造成本和生效速度排序如下:
1. 提前释放会话锁(改造成本最低,立即生效)
在不需要操作Session的脚本开头提前释放Session锁即可:
- chat-mail.php全程没有用到Session操作,直接在代码第一行加
session_write_close();,脚本拿到请求参数后立即释放Session锁,后续拉取聊天的请求不会再被阻塞。 - chat.php在完成Session相关操作(比如你用到的
sessionUser()是读Session逻辑)后,也可以提前调用session_write_close(),再执行后续的数据库查询、返回响应逻辑。
示例代码(chat-mail.php开头新增):
<?php session_write_close(); // 新增行,提前释放Session锁 // 原有代码不变 $name = (!empty($_POST['name']))?$_POST['name']:null; $email = (!empty($_POST['email']))?$_POST['email']:null; // ...
2. 异步队列处理邮件(彻底解决问题,长期最优)
不要让前端请求同步等待邮件发送,把邮件逻辑改成后台异步执行:
- 新增邮件任务表,字段包含收件人邮箱、邮件标题、邮件内容、发送状态、创建时间即可。
- chat.php判断需要发邮件时,直接把邮件参数插入任务表,立即返回接口响应,不需要等待邮件发送。
- 配置crontab定时任务,每分钟执行一次脚本消费任务表中的待发送邮件,后台异步完成发送。
3. 前端体验优化
- 发送消息成功后直接在前端拼接消息到聊天框,不需要等待定时拉取,用户可以立即看到自己发送的内容,完全规避等待问题:
success: function(json){ inputField.val(''); // 主动拼接自己发送的消息,不用等拉取返回 const myMsg = `<div class="outgoing-msg">${inputField.val()}</div>`; chatBox.append(myMsg); $('html,body').animate({scrollTop: document.body.scrollHeight}, "fast"); }
- 优化定时拉取逻辑,避免请求堆积:每次拉取请求完成后再发起下一次,而不是固定500ms发一次,避免网络差时请求堆积占满并发数:
let isLoadingChat = false; function getChat() { if (isLoadingChat) return; isLoadingChat = true; $.ajax({ // 原有请求配置不变 complete: function() { isLoadingChat = false; setTimeout(getChat, 500); } }) } getChat(); // 初始化调用替代原setInterval
内容的提问来源于stack exchange,提问作者Relaxing Music
相关产品推荐
相关产品推荐

