[Laravel][socket.io] 学习sokcet.io视频中遇到的两个问题

在这节视频的最后(13:08),教主打开了两个网页,来测试结果。
我的理解是,刷新一个网页后,两个网页应该同时会显示Jelly,不过实际结果是被刷新的网页(视频中的左侧)中Jelly最后是消失了。这是为什么 ?

另外一个问题是,在这节课中,应该是有两层数据共享,或者说broadcast / subscribe的,
第一层是:Redis, 用于Laravel和Socket.js (node) 共享数据;
另一层是:Socket.io的服务端和客户端之间的数据传递。
我的理解对吗?

谢谢!

JellyBool

so…换个角度,这样说怎么样:

同时会显示Jelly

这里面的同时应该是理解为对所有的客户端来说,数据是应该同时更新的。对于刷新的这个页面,其实是一个 Publisher,其他的客户端是 Subscriber,所以,数据同时更新是应该说的是 Subscriber。那么,如果你想两边都显示 Jelly,其实就回到了第二节视频的内容,就是在刷新的这个页面,添加一个 dom

网页(视频中的左侧)中Jelly最后是消失了

这个确切来说,它不是显示的 Jelly ,而是显示着 name,就是 name 这个字符串,因为在代码中,我们是写的 name,然后刷新的时候,Vuejs 解析并没有那么快,所以我们会在一瞬间看到 name 和两个大括号,但是一旦 dom 树渲染完毕,交给 Vuejs 解析的时候,Vuejs 识别到,当前的 name 是一个 空的字符串,自然就不会显示了。

Redis, 用于Laravel和Socket.js (node) 共享数据

恩,我个人理解也是这样的

Socket.io的服务端和客户端之间的数据传递

恩,服务端的 socket.io 通过 emit() 传数据到客户端,客户端负责接收。

我个人大概这样理解。还有问题请继续讨论

sunnirvana

第二节视频中的代码:

index.html

...
<script>
    var socket = io();
    $('#messageForm').submit(function(){
        // send chat.message to the server
        socket.emit('chat.message', $('#message').val());    <== 客户端广播socket.io事件
        $('#message').val('');
        return false;
    });
 
    socket.on('chat.message', function(message){   <== 客户端监听socket.io事件
        console.log(message);
//        $('#messages').html('<li> ' + message + '</li>');
        $('#messages').append($('<li>').text(message));
    });
</script>
...

index.js

...
io.on('connection', function(socket){
    console.log('a user connect');
    // listening chat.message
    socket.on('chat.message', function(message){  <== 服务器端监听socket.io事件
        console.log('a new message: ' + message);
        // broadcast chat.message to all users connected to the server.
        io.emit('chat.message', message);  <== 服务器端广播socket.io事件
    });
});
...

这个过程应该是: [打开网页] -> [客户端广播socket.io事件] -> [服务器端监听socket.io事件] -> [服务器端广播socket.io事件] -> [客户端监听socket.io事件]
对于一个打开的网页来说,它既是广播者又是订阅者。
所以当打开多个网页的时候,刷新不同的网页,会在每个网页上都显示信息。

sunnirvana

第四节视频中的代码

route.php

...
Redis::publish('test-channel', json_encode($data));  <== 服务器端在test-channel上广播Redis信息
...

socket.js

...
redis.subscribe('test-channel');  <== 服务器端订阅Redis test-channel

redis.on('message', function(channel, message){  <== 服务器端监听Redis事件
    console.log(channel, message);
    io.emit(channel + ':' + JSON.parse(message).event, JSON.parse(message).data);  <== 服务器端广播socket.io事件
});
...

welcome.blade.php

...
<script>
            ready:function(){
                socket.on('test-channel:userMessage', function(data){  <== 客户端监听socket.io事件
                    this.users.push(data.first_name + ' ' + data.last_name);
                }.bind(this))
            }
</script>
...

这个过程应该是:[打开网页] -> [服务器端在test-channel上广播Redis信息] -> [服务器端订阅Redis test-channel] -> [服务器端监听Redis事件] -> [服务器端广播socket.io事件] -> [客户端监听socket.io事件]
对于一个打开的网页来说,它是监听者,当它加载时(刷新)他就是事件触发者。
所以当有多个网页打开时,刷新其中一个网页,它本身不会显示,而信息只能显示在其他的网页。

sunnirvana

谢谢教主的回答,重新整理下思路,不知道上面两个帖子我理解的对不对。并且如果我想知道,在后面这种情况下,我想要所有网页都显示socket.io信息,应该如何修改代码呢?
谢谢!

JellyBool 回复 sunnirvana

没事啊,有问题就发贴问撒

sunnirvana 回复 JellyBool

教主,还没回复我的新问题…

JellyBool 回复 sunnirvana

理论上不用改代码吧,你直接通过命令行来触发看看。比如说 curl

curl http://api.dev
TenYear

同样在这节,我遇到个问题,

redis.on('message',function (channel, message) {
    message = JSON.parse(message);
    console.log(message.data.name);
    io.emit("test-channel:a", message.data);
});

服务端这边 emit可以正常发送数据,但客户端这边却始终接收不到,

<script>
        var socket = io('127.0.0.1:3000');
        new Vue({
            el:'#discuzz',
            data:{
                users:[]
            },
            ready:function () {
               socket.on('test-channel:a', function (data) {
                    console.log(data);
                    this.users.push(data.name);
                }.bind(this))
            }
        })
 </script>

vue的版本是一样的1.04,,请教一下怎么解决这个问题