Web Worker + socket.io搭建的简易聊天室

559 阅读2分钟

一 Web Worker是什么

web worker是h5的一个新特性,主要是为了解决js在处理一些耗时任务时阻塞页面的渲染交互导致用户体验不好的问题,因为web worker可以为页面额外开启一个自包含的执行环境(js是单线程的),web worker开启一个额外线程靠的是浏览器支持。开启的这个线程用于为js处理那些耗时任务,然后js主线程继续处理页面渲染交互,用户体验就不会变差了。

二 socket.io服务端代码

演示demo使用node+koa搭建服务端代码,如果自己已经搭建过,可以忽略此步骤。

// 引入依赖
const koa = require("koa");
// 初始化koa
const app = new koa();
// 开启 http
var server = require("http").createServer(app.callback());
// 初始化 socket
const io = require("socket.io")(server, { cors: true });
// 监听
io.on("connection", (socket) => {
    console.log("🙋进入一个socket链接", io.eio.clientsCount);

    socket.on('disconnect', () => {
        console.log('🙅退出一个socket链接', io.eio.clientsCount);
    });

    // 监听收到的消息
    socket.on('chat_room_1', function (data) {
        console.log("收到消息", data);
        io.emit('chat_room_1', data);
    });
});
server.listen(3000);

三 业务层代码(以vue3为例)

1 搭建项目框架,做用户登录验证。

<template>
    <div class="login-container">
        请输入当前用户名:<input type="text" v-model="current_user">
        <button @click="login">确定</button>
    </div>
</template>

<script>
import { ref } from "vue";
import { useLocalStorage } from "@vueuse/core";
import { useRouter } from "vue-router";

export default {
    setup() {
        const router = useRouter();
        let current_user = ref("");
        
        const login = () => {
            let state = useLocalStorage("current_user", null);
            state.value = current_user.value;
            router.push("/");
        };

        return {
            current_user,
            login,
        };
    },
};
</script>
<style lang="css" scoped>
</style>
import { createRouter, createWebHistory } from "vue-router";
import { useLocalStorage } from '@vueuse/core';

import Login from "../views/login.vue";
import Index from "../views/index.vue";

const routes = [
    {
        path: "/",
        component: Index
    },
    {
        path: "/login",
        component: Login
    }
]

const router = createRouter({
    routes,
    history: createWebHistory()
})

router.beforeEach((to, from, next) => {
    const state = useLocalStorage('current_user', null)
    if (to.path == '/login' || state.value) {
        next()
    } else {
        next("/login")
    }
})

export default router;

2 聊天室业务层

(1) 引入并加载Web Worker线程

import Worker from "worker-loader!@/workers/web";

setup() {
  const input_value = ref("");
  const worker = new Worker();
  
  onMounted(() => {
    current_user.value = useLocalStorage("current_user").value;
    worker.onmessage = (e) => {
      console.log("收到worker进程消息", e.data);
    };
  });
  
  onBeforeUnmount(() => {
    // 线程关闭
    worker.terminate();
  });
  
  const sendMsg = () => {
    worker.postMessage({
      type: "emit",
      data: {
        username: current_user.value,
        message: input_value.value,
      },
    });
    input_value.value = "";
  };
  
  return {
    sendMsg,
    input_value,
    current_user,
  };
}

(2) 在src文件夹下面新建workers文件夹

(3) 在workers文件夹新建web.js文件

import io from "socket.io-client";

let chatList = []
let socket;


/**
 * 开启socket
 */
function start_socket() {
    socket = io("http://localhost:3000"); // 连接后端的 socket.io 方法里面传服务端的ip
    socket.on("connect", () => {
        console.log(socket.id, "监听客户端连接成功-connect");
    });
    socket.on("chat_room_1", (data) => {
        console.log("data", data);
        // 自定义一个事件来获取,服务端推送回来的消息列表
        chatList = [...chatList, ...[data]];
        console.log("收到消息", chatList);
        return postMessage(chatList)
    });
}
start_socket()


/**
 * 发送socket
 */
function emit_socket(data) {
    socket.emit("chat_room_1", data);
}

addEventListener('message', e => {
    const { data } = e
    console.log(data)
    if (data.type === 'emit') {
        emit_socket(data.data)
    }
})
export default {}

3 配置worker-loader

在vue.config.js下配置

chainWebpack: config => {
        config.module
            .rule('worker-loader')
            .test(/.worker.js$/)
            .use({
                loader: 'worker-loader',
                options: {
                    inline: true
                }
            })
            .loader('worker-loader')
            .end()
    }

四 效果演示

服务端:

客户端1:

客户端2: