我正在尝试创建一个类似Facebook的发布系统。所以我做了一些关于Facebook是如何做到这一点的研究,Facebook使用长轮询,所以我四处搜索如何实现它,我实现了它。我终于完成了,我打开了Firefox和Chrome来测试它。在2到3次发布后,它工作了,但随后会复制结果。如下所示:
顺便说一下,这是第一封信
这是我的网络选项卡,在此过程中:
它发出3个请求,而不是一个
最后是我的代码:
init.js,它包含我所有的JavaScript代码
函数getNewPosts(时间戳){
变量t;
$.ajax({
url:’stream.php’,
数据:“时间戳=”+时间戳,
数据类型:“JSON”,
})
.完成(功能(数据){
净间隔(t);
//有没有结果
//在这两种情况下,我们在1秒后启动另一个AJAX请求进行长时间轮询
if(data.message_content==’results’| | data.message_content==’no results’){
t=设置超时(函数(){
getNewPosts(data.timestamp);
}, 1000);
//如果有结果,我们将把它附加到post div
如果(data.message_content==’results’){
//循环浏览每个帖子并将其输出到屏幕
$.each(data.posts,函数(index,val){
$(“<;div class=’post’>;+val.post\u content+”<;div class=’post\u datePosted’>;+val.posted\u date+”<;/div>;<;br>;“+”<;/div>;)。前缀(’.posts’);
});
}
}
})
}
$(文档).ready(函数(){
//启动自动调整大小功能
$(’textarea’).autosize();
//第一次向服务器创建AJAX请求以获取帖子
$.ajax({
async:false,
url:’stream.php?完整页面\重新加载=1’,
键入:“GET”,
数据类型:“JSON”,
})
.完成(功能(数据){
//将此变量分配给服务器时间戳
//这是由PHP脚本给出的
serverTimestamp=data.timestamp;
$.each(data.posts,函数(index,val){
$(“<;div class=’post’>;+val.post\u content+”<;div class=’post\u datePosted’>;+val.posted\u date+”<;/div>;“+”<;/div>;”).prependTo(’.posts’);
});
})
.fail(函数(){
警报(“发生错误!”);
})
//提交表格时
$(’post#u form’)。关于(’submit’,函数(事件){
$.ajax({
url:’ajax/post.php’,
键入:“POST”,
数据类型:“JSON”,
数据:$(’#post_form’)。序列化()
})
.完成(功能(数据){
//重置表单值
$(’#post_form’)[0].reset();
})
.fail(函数(){
//当发生错误时
警报(“发生错误”);
})
//阻止默认操作
event.preventDefault();
});
//在DOM就绪时启动实际的长轮询
getNewPosts(服务器时间戳);
});
和mystream.php
<;?php
标题('Content-type:application/json');
//如果它是一个完整的页面重新加载
$lastId=isset($\u GET['lastId'])&&!空($\u GET['lastId'])$_获取['lastId']:0;
如果(isset($\u GET['full\u page\u reload'])和($\u GET['full\u page\u reload']==1){
$first_ajax_call=(int)$\u GET['full_page_reload'];
//创建数据库连接
$pdo=new-pdo('mysql:host=localhost;dbname=test','akar','raparen');
$sql=“从“帖子”中选择*”;
$stmt=$pdo->;准备($sql);
$stmt->;执行();
$posts=$stmt->;fetchAll(PDO::FETCH_ASSOC);
//输出自满页重新加载后的时间戳
echo json_编码(数组(
“fullPageReload”=>;“true”,
“时间戳”=>;time(),
“posts”=>;$posts
));
}else if(isset($\u GET['timestamp'])){
//浪费的时间
$time_wasted=0;
//数据库连接
$pdo=new-pdo('mysql:host=localhost;dbname=test','akar','raparen');
$timestamp=$_GET['timestamp'];
//将时间戳格式化为SQL格式
$curr_time=date('Y-m-d H:i:s',$timestamp);
$sql=“从发布日期所在的“发布”中选择*=:当前时间”;
$stmt=$pdo->;准备($sql);
$stmt->;bindValue(“:curr\u time”,“$curr\u time”);
$stmt->;执行();
//以关联数组的形式获取结果
$posts=$stmt->;fetchAll(PDO::FETCH_ASSOC);
//如果没有结果的话
如果($stmt->;rowCount()<;=0){
//创建主循环
而($stmt->;rowCount()<;=0){
//如果仍然没有结果或新职位
如果($stmt->;rowCount()<;=0){
//如果我们等了60秒仍然没有结果
如果($time_wasted>;=60){
die(json_)编码(数组(
“消息类型”=>;“错误”,
“消息内容”=>;“无结果”,
“时间戳”=>;时间()
)));
}
//对服务器有一点帮助
睡眠(1);
$sql=“从发布日期所在的“发布”中选择*=:当前时间”;
$stmt=$pdo->;准备($sql);
$stmt->;bindParam(“:curr\u time”,$curr\u time);
$stmt->;执行();
$posts=$stmt->;fetchAll(PDO::FETCH_ASSOC);
//将浪费的时间增加一个变量
$time_wasted+=1;
}
}
}
//如果有结果,我们就输出它。
如果($stmt->;rowCount()>;0){
die(json_)编码(数组(
“消息内容”=>;“结果”,
“时间戳”=>;time(),
“posts”=>;$posts,
)));
退出();
}
}
这是我的ajax/post.php:
<;?php
如果(isset($_POST['POST_content'])){
$post_content=strip_标签(修剪($_post['post_content']);
if(空($post_内容)){
/*如果用户没有输入任何内容*/
echo json_编码(数组(
“消息类型”=>;“错误”,
“邮件内容”=>;“您的帖子似乎是空的”
));
}否则{
$pdo=new-pdo('mysql:host=localhost;dbname=test','akar','raparen');
$sql=“插入到`posts`(`post\u id`、`post\u content`、`post\u date`)值中(NULL,:post\u content,NOW());”;
$stmt=$pdo->;准备($sql);
$stmt->;bindValue(“:post\u content”,$post\u content);
$stmt->;执行();
echo json_编码(数组(
“消息类型”=>;“消息”,
“邮件内容”=>;“您的帖子已成功发布。”
));
}
}
如果你不明白,就问我。我知道这是肮脏的代码,我重复了很多次。我这样做是为了测试,所以这并不重要
谢谢
坦白地说,我不明白你为什么要同时进行这种优化,除非你计划处理数千条消息。您还可以在每次刷新页面时获取全部内容
每秒钟用每个客户机的请求敲打服务器都会产生大量流量,因此优化应该从定义更合理的轮询周期或更智能、自适应的刷新机制IMHO开始
现在,如果你真的想去做,你必须做一个适当的同步。如果您弄乱了时间戳,您可以跳过其他客户机触发自动刷新时添加的消息,或者两次获取所述消息
所有超时处理都是不必要的。如果出现问题,通过Ajax的服务器请求将产生一个错误事件,这将意味着连接或您的服务器出现故障,或者您的PHP端代码出现一些问题,需要修复
关于应用程序结构的概念:
- 更新请求将向PHP传递一个时间戳,请求检索比所述时间戳更新的所有帖子。初始值将是1/1/1970或其他任何值,因此初始获取将检索所有现有帖子。响应中将包含一个新的时间戳,这样增量请求将跳过已经获取的数据
- Javascript会定期生成这样的请求(我宁愿将周期设置为30秒左右,以避免服务器负载过大——假设您的普通用户能够处理等待下一批伪tweet那么长时间的挫折感)
- 提交一篇新文章只需将其添加到数据库中,但由于所有工作都是在服务器端完成的,因此您不需要担心竞争条件
你所有的“浪费的时间”和“当前时间”代码都应该放到垃圾桶里。
唯一需要的时间参考是来自此特定客户端的上次读取请求的日期。
服务器端(在“stream”PHP文件中)只需要一个DB请求来获取比客户端提供的时间戳更新的帖子,它将返回一个帖子列表(可能为空)和相同时间戳的更新值
坦率地说,除了这些可能令人困惑的时间戳之外,您还可以使用最后一次回迁的唯一标识符(对初始请求使用0或任何常规值)