国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

WebSocket+Vue實(shí)現(xiàn)簡易多人聊天室 以及 對異步調(diào)用的理解

這篇具有很好參考價(jià)值的文章主要介紹了WebSocket+Vue實(shí)現(xiàn)簡易多人聊天室 以及 對異步調(diào)用的理解。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

代碼倉庫:github

聊天室 WebSocket+Vue

??HTTP是不支持長連接的,WebSocket是一種通信協(xié)議,提供了在單一、長連接上進(jìn)行全雙工通信的方式。它被設(shè)計(jì)用于在Web瀏覽器和Web服務(wù)器之間實(shí)現(xiàn),但也可以用于任何需要實(shí)時(shí)通信的應(yīng)用程序。使用ws作為協(xié)議標(biāo)識(shí)符,如果需要加密則使用wss作為協(xié)議標(biāo)識(shí)符,類似于http和https的區(qū)別。
相比HTTP,WebSocket請求頭多了
??????Upgrade: websocket
??????Connection: Upgrade
這一段是表明現(xiàn)在是用的WebSocket協(xié)議,而不是簡單的HTTP。
優(yōu)勢:

  • 全雙工通信: 與傳統(tǒng)的請求-響應(yīng)通信模型(如HTTP)不同,WebSocket允許雙向通信??蛻舳撕头?wù)器都可以獨(dú)立地發(fā)送消息。
  • 持久連接:WebSocket在客戶端和服務(wù)器之間建立了一個(gè)持久連接,只要雙方需要,連接就會(huì)保持打開狀態(tài)。這消除了為每次通信重復(fù)打開和關(guān)閉連接的需要。
  • 低延遲:WebSocket旨在最小化延遲并減少傳統(tǒng)HTTP輪詢所帶來的開銷。這使其非常適用于需要實(shí)時(shí)更新的應(yīng)用程序,例如聊天應(yīng)用程序、在線游戲、金融交易平臺(tái)和協(xié)同編輯工具。
    為建立WebSocket連接,客戶端向服務(wù)器發(fā)送WebSocket握手請求,在握手成功后,連接將升級到WebSocket協(xié)議。一旦建立,客戶端和服務(wù)器都可以隨時(shí)相互發(fā)送消息。

這也就是最大的一個(gè)特點(diǎn):服務(wù)器可以主動(dòng)向客戶端推送信息,客戶端也可以主動(dòng)向服務(wù)器發(fā)送信息,是真正的雙向平等對話。
WebSocket適用于需要實(shí)時(shí)更新或連續(xù)的數(shù)據(jù)流,而HTTP更適用于獲取舊數(shù)據(jù)或者只獲得一次數(shù)據(jù)即可,不需要實(shí)時(shí)獲取數(shù)據(jù)。
綜上,WebSocket適用于需要實(shí)時(shí)的場景,例如實(shí)時(shí)聊天室、多玩家游戲、實(shí)時(shí)地圖位置、在線協(xié)同編輯等場景,接下來主要運(yùn)用于實(shí)時(shí)聊天室實(shí)現(xiàn)多人聊天室,可以做到將消息放松到群聊并實(shí)時(shí)推送給全體用戶。

前端

具體框架如下圖所示:
WebSocket+Vue實(shí)現(xiàn)簡易多人聊天室 以及 對異步調(diào)用的理解,websocket,vue.js,異步調(diào)用

布局

頁面布局主要分上下兩部分,上面是導(dǎo)航欄,下面是登陸頁面或者聊天頁面。
WebSocket+Vue實(shí)現(xiàn)簡易多人聊天室 以及 對異步調(diào)用的理解,websocket,vue.js,異步調(diào)用
在App.vue中進(jìn)行初次布局,按照上圖進(jìn)行設(shè)計(jì)如下

  <ContentBase>
    <NavBar />
  </ContentBase>
 
  <div class="box">
    <router-view/>
  </div>

由于下面會(huì)根據(jù)登陸狀態(tài)分LoginView.vue和HomeView.vue兩種頁面,所以需要設(shè)置為路由狀態(tài),根據(jù)路由選擇顯示指定頁面。
對每一個(gè)方塊可以設(shè)計(jì)個(gè)卡片包括起來,主要使用bootstrap
封裝到ContentBase.vue 使用 接收傳過來的children,之后只要把需要"框"起來只需要放到即可。

<template>
  <div class="home">
    <div class="container">
      <div class="card">
        <div class="card-body">
          <slot></slot>
          <!-- 存放父組件傳過來的children -->
        </div>
      </div>
    </div>
  </div>
</template>
導(dǎo)航欄

首先是導(dǎo)航欄,根據(jù)登陸狀態(tài)會(huì)有兩種情況,當(dāng)未登陸的時(shí)候,分為(聊天室,Home,登陸)。無論點(diǎn)擊哪一個(gè)都自己路由到登陸頁面,當(dāng)?shù)顷懙臅r(shí)候分為(聊天室,username,退出)
當(dāng)點(diǎn)擊username或聊天室會(huì)顯示登陸頁面,如果點(diǎn)擊退出會(huì)觸發(fā)logout函數(shù)使用戶退出并顯示登陸狀態(tài)。
其中l(wèi)ogout函數(shù)簡單介紹

const logout = () => {
  store.commit('logout');
}
<nav class="navbar navbar-expand-lg bg-body-tertiary">
  <div class="container-fluid">
    <router-link v-if="$store.state.is_login" class="navbar-brand" :to="{name:'home'}">聊天室</router-link>
    <router-link v-else class="navbar-brand" :to="{name:'login'}">聊天室</router-link>
    <div class="collapse navbar-collapse" id="navbarNavDropdown">
      <ul class="navbar-nav" v-if="!$store.state.is_login">
        <li class="nav-item">
          <router-link class="nav-link active" aria-current="page" :to="{name:'login'}">Home</router-link>
        </li>
        <li class="nav-item">
          <router-link class="nav-link" :to="{name:'login'}" role="button" data-bs-toggle="dropdown" aria-expanded="false">
            登陸
          </router-link>
        </li>
      </ul>
        <!-- 上面是未登錄狀態(tài)   下面是已登錄狀態(tài) -->
      <ul class="navbar-nav" v-else>
        <li class="nav-item">
          <router-link class="nav-link active" aria-current="page" :to="{name:'home'}">{{ $store.state.username }}</router-link>
        </li>
        <li class="nav-item">
          <router-link @click="logout" class="nav-link" :to="{name:'login'}" role="button" data-bs-toggle="dropdown" aria-expanded="false">
            退出
          </router-link>
        </li>
      </ul>
    </div>
  </div>
</nav>
</div>

接下來就是下面主頁面,分為登錄頁面和聊天頁面,所以需要路由

在component不適用引入而是直接使用匿名函數(shù)是異步加載方式即頁面沒有被顯示這個(gè)代碼就不會(huì)被執(zhí)行

import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'

const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/login',
    name: 'login',
    component: () => import(/* webpackChunkName: "about" */ '../views/LoginView.vue')
  }
]

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

export default router
登陸頁面

“/login” 是登陸頁面
在這里簡單設(shè)計(jì)一下登錄窗口即可

  <ContentBase style="margin-top: 200px;;">
    <form>
      <div class="mb-3">
        <input type="text" placeholder="請輸入用戶名" v-model="username" />
      </div>
      <div class="mb-3 form-check">
        <input type="checkbox" class="form-check-input" id="exampleCheck1">
        <label class="form-check-label" for="exampleCheck1">Check me out</label>
      </div>
      <button type="submit" class="btn btn-primary" @click="handleEnter">Submit</button>
    </form>
  </ContentBase>

當(dāng)submit之后會(huì)觸發(fā)handleEnter函數(shù),在script中進(jìn)行聲明

const handleEnter = () => {
    const _username = username.value; //ref對象的值用value取得
    //控制用戶名格式
    if (_username.length < 2) {
        alert('用戶名應(yīng)不小于2位');
        username.value = '';
        return;
    }
    sessionStorage.setItem('username', _username); //存入localStorage
    username.value = '';
    store.commit('login',_username);
    router.push('/');
};

用戶名必須要不小于兩位,確認(rèn)成功之后存入到sessionStorage中并且調(diào)用store.commit上傳到vuex中,這樣就可以全局改變登陸狀態(tài),并且立馬路由到聊天頁面上。vuex的配置會(huì)在后續(xù)給出。
如果需要根據(jù)之前是否有所登錄,如果有登錄可以在掛載之后檢查sessionStorage檢查是否存在,如果存在立馬跳轉(zhuǎn),比如下列代碼

onMounted(()=>{
  //查看sessionStorage中是否存在username
  username.value = sessionStorage.getItem('username');
  if(username.value){//存在的話直接跳轉(zhuǎn)
    router.push('/');
    return ;
  }
});

sessionStorage是位置
WebSocket+Vue實(shí)現(xiàn)簡易多人聊天室 以及 對異步調(diào)用的理解,websocket,vue.js,異步調(diào)用

聊天頁面

“/” 是聊天頁面
聊天頁面分成三塊,左側(cè)是用戶列表UserList,右側(cè)分上下兩層分別為聊天記錄框和發(fā)送窗口
WebSocket+Vue實(shí)現(xiàn)簡易多人聊天室 以及 對異步調(diào)用的理解,websocket,vue.js,異步調(diào)用
在用戶列表中會(huì)顯示當(dāng)前在線用戶人數(shù)以及用戶名稱,對用戶列表會(huì)排除掉自身,因?yàn)樽陨頃?huì)放到首位顯示出。
為了簡單起見就不再分三個(gè)components,直接在HomeView.vue中設(shè)計(jì)下布局即可,使用bootstrap中的grid布局。
左側(cè)右側(cè)col-3 col-9即3:9分開,上下大概550px:150px。

<template>
  <ContentBase>
      <div class="row" style="width: 700px;">
        <div class="col-3" style="width:150px; background-color: lightblue;">
          <div>UserList : {{ userList.length+1 }} </div>
          <hr>
          <div>{{ username }}</div>
          <div v-for="(item,index) in userList" :key="index"> {{ item }} </div>
        </div>
        <div class="col-9" style="height:500px; width: 550px;  padding: 0px 0px;">
          <div id="ltk"> 
            <ul>
              <li v-for="item of msgList" :key="item.id" style="list-style: none; height: 80px;">
                <div>      
                  <span style="display: block; text-align: center; font-size: small;">{{ item.dataTime }}</span> 
                  <span v-if="item.user === username" 
                    style="display: block; text-align: right; padding-right: 50px; padding-top: 0; font-size: small;">
                    {{ item.user }}
                  </span>
                  <span v-else style="text-align: left;">
                    {{ item.user }}
                  </span>
                </div>
                <div v-if="item.user === username" 
                  style="display: block; text-align: right; padding-right: 50px;">
                  {{ item.msg }}
                </div>
                <div v-else style="text-align: left;">
                  {{ item.msg }}
                </div>

              </li>
            </ul>
          </div>
          <div class="input">
            <input type="text" placeholder="輸入消息" v-model="msg"/>
            <button @click="handleSend">發(fā)送</button>
          </div>
        </div>
      </div>
  </ContentBase>

</template>

WebSocket+Vue實(shí)現(xiàn)簡易多人聊天室 以及 對異步調(diào)用的理解,websocket,vue.js,異步調(diào)用

這部分script部分比較重要
需要實(shí)現(xiàn)的功能主要有:
獲取當(dāng)前username
保證實(shí)時(shí)滾動(dòng)即當(dāng)消息過多的時(shí)候需要發(fā)消息會(huì)滾動(dòng)到底層,使用scrollTop=scrollHeight即可(讓頂層和當(dāng)前高度一致)。
發(fā)送消息:需要向服務(wù)端發(fā)送,便于服務(wù)端群發(fā)到各個(gè)在線用戶,為了便于顯示當(dāng)前時(shí)間格式設(shè)置為"時(shí):分:秒",但要注意判斷不能全是空格,利用trim()去掉空格來判斷
為了便于獲取數(shù)據(jù),設(shè)置函數(shù)handleMessage來接收服務(wù)端廣播的消息,以便實(shí)時(shí)獲取到數(shù)據(jù)
為了便于新用戶獲得之前的聊天記錄,可以讓服務(wù)器記錄歷史記錄,新用戶初次登陸進(jìn)行獲取

<script>
import { reactive,toRefs,onMounted,ref } from 'vue';
import { useRouter } from 'vue-router';
import useWebSocket from '../hooks/websocket.js'
import store from '@/store';
import ContentBase from '@/components/ContentBase.vue';
import LoginView from './LoginView.vue';

export default {
  name: 'HomeView',
  components:{
    ContentBase,
  },
  setup(){
    const router = useRouter();
    
    const state = reactive({
      msg:'',
      msgList:[],
    });

    let userList = ref([]);
    let username = sessionStorage.getItem('username');
    onMounted(() => {
      if(!username || store.state.is_login===false){
        router.push('/login');
        return ;
      }
      //實(shí)現(xiàn)實(shí)時(shí)滾動(dòng)
      setInterval(()=>{
        var e = document.getElementById('ltk');
        e.scrollTop = e.scrollHeight;
        //scrollTop:指的是滾動(dòng)條卷去的距離(滾動(dòng)條向下滾動(dòng)之后距離頂部的距離)
        //scrollHeight:指的是內(nèi)容的高度
      },20)
    })
    const ws = useWebSocket(handleMessage,username);
    const handleSend = () => {
      const _msg = state.msg;
      if(!_msg.trim().length){
        return ;//空
      }
      let time = new Date();
      ws.send(JSON.stringify({
        id: time.getTime(),
        user: username,
        dataTime:`${time.getHours()}:${time.getMinutes()}:${time.getSeconds()}`,
        msg:state.msg,
      }));
      state.msg = '';
    }

    function handleMessage(e){
      const _msgData=JSON.parse(e.data);
      if(_msgData.tag === 'userUpdate'){
          for(let i = 0;i < _msgData.userList.length;i++){
            var f = false;
            for(let j = 0;j < userList.value.length;j++){
              if(userList.value[j] === _msgData.userList[i]){
                f = true;
                break;
              }
            }
            if(!f)
              userList.value.push(_msgData.userList[i]);
          }
      }else if(_msgData.tag === 'msgUpdate'){
        if(state.msgList.length === 0)
          console.log(_msgData.chatList.length);
          for(let i = 0;i < _msgData.chatList.length;i++){
            state.msgList.push(_msgData.chatList[i]);
          }
      }
      else
        state.msgList.push(_msgData);
      userList.value = userList.value.filter(item=>item!==username);
      
    }


    return {
      ...toRefs(state),  //平鋪開state
      handleSend,
      userList,
      username,
    }
  }
}
</script>

vuex中存儲(chǔ)當(dāng)前用戶的登陸狀態(tài)和當(dāng)前用戶名

state: {
  is_login : false,
  username : "",
  // count : 0,
},
getters: {
},
mutations: {
  login(state,username){
    state.username = username,
    state.is_login = true;
  },
  logout(state){
    state.is_login = false;
    state.username = "";
  }
},

WebSocket

最關(guān)鍵的是WebSocket的實(shí)現(xiàn),WebSocket構(gòu)造函數(shù)開啟ws://localhost:8000端口,主要分為open、message、close、error。
當(dāng)處理open的時(shí)候,可以默認(rèn)發(fā)送I’m ${username} 作為問候語。
當(dāng)處理message的時(shí)候,調(diào)用handleMessage讓前端獲取到服務(wù)端廣播的消息。
當(dāng)處理close的時(shí)候,打印一下表明已經(jīng)退出即可。
當(dāng)處理error的時(shí)候,簡單打印下event。

function useWebSocket(handleMessage,username){
    const ws = new WebSocket('ws://localhost:8000');
    ws.addEventListener('open',(e)=>{
        console.log('client open');
        let time = new Date();
        ws.send(JSON.stringify({
          id: time.getTime(),
          user: username,
          dataTime:`${time.getHours()}:${time.getMinutes()}:${time.getSeconds()}`,
          msg:`Hello I'm ${username}`,
        }));
    },false);

    ws.addEventListener('message',handleMessage);
    ws.addEventListener('close',(event)=>{
        console.log(`${username} closed`);
    });
    ws.addEventListener('error',(event)=>{
        console.log('error: ',event);
    })

    return ws;
}

export default useWebSocket;

后端

??ws后端,利用Server配置端口號(hào),監(jiān)聽事件。分為open、error、connect、close。只有當(dāng)connect成功的時(shí)候才會(huì)出現(xiàn)事件message。
主要對connect、message和close進(jìn)行相應(yīng)的處理。
??首先定義了userNum、chatList和userList記錄當(dāng)前在線人數(shù)、歷史群聊記錄和當(dāng)前用戶列表。
connect:當(dāng)觸發(fā)該事件時(shí),表明有了新客戶端進(jìn)行了連接,這時(shí)候可以增加當(dāng)前在線人數(shù)、username到userList并且廣播。
message:當(dāng)觸發(fā)該事件的時(shí)候,需要廣播該消息到每個(gè)客戶端并且廣播chatList,因?yàn)樾掠脩艏尤霑?huì)發(fā)送一個(gè)消息所以必定會(huì)立馬獲得chatList,當(dāng)然放到connect不放在message中也可以。
close:當(dāng)觸發(fā)該事件的時(shí)候,需要減少人數(shù)并且廣播。
這么多種廣播,客戶端應(yīng)該如何區(qū)分呢?可以在對象中增加tag屬性來表明廣播的是哪種類型的信息。(userUpdate、chatUpdate)
客戶端在handleMessage區(qū)分廣播的消息如下:

function handleMessage(e){
  const _msgData=JSON.parse(e.data);
  if(_msgData.tag === 'userUpdate'){
      for(let i = 0;i < _msgData.userList.length;i++){
        var f = false;
        for(let j = 0;j < userList.value.length;j++){
          if(userList.value[j] === _msgData.userList[i]){
            f = true;
            break;
          }
        }
        if(!f)
          userList.value.push(_msgData.userList[i]);
      }
  }else if(_msgData.tag === 'msgUpdate'){
    if(state.msgList.length === 0)
      console.log(_msgData.chatList.length);
      for(let i = 0;i < _msgData.chatList.length;i++){
        state.msgList.push(_msgData.chatList[i]);
      }
  }
  else
    state.msgList.push(_msgData);
  userList.value = userList.value.filter(item=>item!==username);
  
}
var userNum = 0
var chatList = []
var userList = []

const WebSocket = require('ws');

const server = new WebSocket.Server({port:8000});


server.on('open',()=>{
    console.log('server open');
})

server.on('error',()=>{
    console.log('server error');
})

server.on('connection',(ws)=>{
    console.log('has connected');
    userNum++;
    server.clients.forEach((item)=>{
        if(item.readyState === WebSocket.OPEN)
            item.send(JSON.stringify({tag:"userUpdate",userNum:userNum,userList:userList}));
    })
    ws.on('message',(msg)=>{
        msg = msg.toString();
        console.log(`received message ${msg}`);
        var res = JSON.parse(msg);
        server.clients.forEach((item)=>{
            if(item.readyState === WebSocket.OPEN)
                item.send(JSON.stringify({tag:"msgUpdate",chatList:chatList}));
        })
        chatList.push(res);
        var f = false;
        for(let i = 0;i < userList.length;i++)
            if(userList[i] === res.user)
                f = true;
        if(!f){
            userNum=server.clients.size;
            userList.push(res.user);
            server.clients.forEach((item)=>{
                if(item.readyState === WebSocket.OPEN)
                    item.send(JSON.stringify({tag:"userUpdate",userNum:userNum,userList:userList}));
            })
        }
        server.clients.forEach((client)=>{
            if(client.readyState === WebSocket.OPEN)
                client.send(msg);
        })
    })
})

server.on('close',()=>{
    userNum--;
    server.clients.forEach((item)=>{
        if(item.readyState === WebSocket.OPEN)
            item.send(JSON.stringify({tag:"userUpdate",userNum:userNum,userList:userList}));
    })
    console.log('disconnected');
})

設(shè)置下執(zhí)行語句在package.json

"scripts": {
  "dev": "nodemon index.js"
},

執(zhí)行npm run dev 等效于 nodemon index.js 開啟服務(wù)器。

運(yùn)行結(jié)果

未登陸狀態(tài)
導(dǎo)航欄
WebSocket+Vue實(shí)現(xiàn)簡易多人聊天室 以及 對異步調(diào)用的理解,websocket,vue.js,異步調(diào)用
登陸頁面
WebSocket+Vue實(shí)現(xiàn)簡易多人聊天室 以及 對異步調(diào)用的理解,websocket,vue.js,異步調(diào)用
已登陸狀態(tài)
導(dǎo)航欄
WebSocket+Vue實(shí)現(xiàn)簡易多人聊天室 以及 對異步調(diào)用的理解,websocket,vue.js,異步調(diào)用
聊天界面(實(shí)時(shí)群聊)
WebSocket+Vue實(shí)現(xiàn)簡易多人聊天室 以及 對異步調(diào)用的理解,websocket,vue.js,異步調(diào)用
WebSocket+Vue實(shí)現(xiàn)簡易多人聊天室 以及 對異步調(diào)用的理解,websocket,vue.js,異步調(diào)用
WebSocket+Vue實(shí)現(xiàn)簡易多人聊天室 以及 對異步調(diào)用的理解,websocket,vue.js,異步調(diào)用
WebSocket+Vue實(shí)現(xiàn)簡易多人聊天室 以及 對異步調(diào)用的理解,websocket,vue.js,異步調(diào)用

異步調(diào)用

在JS中,同步任務(wù)在主線程中,會(huì)優(yōu)先執(zhí)行,碰到異步任務(wù)就會(huì)放入到異步隊(duì)列中,而異步隊(duì)列又分為兩個(gè)隊(duì)列,分別是宏隊(duì)列和微隊(duì)列。
JS執(zhí)行時(shí)首先執(zhí)行所有的初始化同步任務(wù)的代碼,之后就會(huì)區(qū)分出宏隊(duì)列和微隊(duì)列執(zhí)行。每執(zhí)行一個(gè)宏任務(wù)之前都會(huì)執(zhí)行一個(gè)微任務(wù)。
宏隊(duì)列主要存儲(chǔ)宏任務(wù),包括定時(shí)器setTimeout、ajax回調(diào)等
微隊(duì)列主要存儲(chǔ)微任務(wù),包括Promise回調(diào)等
WebSocket+Vue實(shí)現(xiàn)簡易多人聊天室 以及 對異步調(diào)用的理解,websocket,vue.js,異步調(diào)用

AJAX

作用:可以在不刷新的情況下向服務(wù)端發(fā)送http請求并得到響應(yīng)
最初使用XML格式的字符串,現(xiàn)在使用更加簡潔的JSON格式,設(shè)置xhr.responseType='json’即可實(shí)現(xiàn)。
Ajax操作主要分為四步:
創(chuàng)建對象、設(shè)置請求類型和url、發(fā)送請求、綁定事件
當(dāng)狀態(tài)為4的時(shí)候表明服務(wù)器完成請求響應(yīng),之后可以根據(jù)xhr.status判斷響應(yīng)狀態(tài)

 //1. 創(chuàng)建對象
 const xhr = new XMLHttpRequest();
 //2. 設(shè)置類型和url
 xhr.open('POST','http://127.0.0.1:8000/server');
 //3. 發(fā)送
 xhr.send();
 //4. 綁定事件
 xhr.onreadystatechange = ()=>{
     if(xhr.readyState === 4){
     		// 判斷響應(yīng)狀態(tài)是否成功
         if(xhr.status >= 200 && xhr.status < 300){
             //對xhr.response進(jìn)行相關(guān)操作;
             //xhr.response是響應(yīng)體
         }
     }
 }

原生的AJAX一般很少直接用到,更多的是用jQuery、fetch或axios間接運(yùn)用AJAX。

Promise

Promise是ES6規(guī)范新技術(shù)、是實(shí)現(xiàn)異步編程的新解決方案。簡單來說Promise就是一個(gè)容器,里面保存著某個(gè)未來才會(huì)結(jié)束的結(jié)果,等結(jié)果出來之后才執(zhí)行相應(yīng)的回調(diào)函數(shù)從而實(shí)現(xiàn)異步操作。
Promise支持鏈?zhǔn)秸{(diào)用,可以解決回調(diào)地域問題,但是一旦建立就會(huì)立即執(zhí)行,無法發(fā)中途取消。
Promise主要有三種狀態(tài),分別是pending、fulfilled、rejected。初始為pending操作,執(zhí)行異步操作會(huì)執(zhí)行resolve()或reject()從而變成fulfilled狀態(tài)或rejected狀態(tài),之后就會(huì)執(zhí)行then()參數(shù)的成功或失敗的回調(diào)函數(shù)。
對于Promise的狀態(tài),只會(huì)發(fā)生pending->fulfilled或pending->rejected,即只會(huì)改變一次,但是可以指定多個(gè)回調(diào)

let p = new Promise((resolve,reject) => {
    resolve('ok');  //pending->fulfilled
})

p.then(value=>{
    console.log(value);
})

p.then(value=>{
    alert(value);
})

then()方法本身也是返回Promise對象,可以使用const result = p.then(…)
既然返回Promise對象,那么返回的對象狀態(tài)是如何決定的?
拋出異?!顟B(tài)
非Promise類型——成功狀態(tài)且result和return結(jié)果保持一致
Promise對象——狀態(tài)和結(jié)果都和該P(yáng)romise對象一致

Promise還會(huì)有異常穿透,即進(jìn)行then()鏈?zhǔn)秸{(diào)用時(shí),可以在最后指定失敗回調(diào)。

p.then(value=>{
    console.log(111);
}).then(value=>{
    console.log(222);
}).then(value=>{   
    throw '!';
    console.log(333);
}).catch(reason=>{
    console.warn(reason);
})

如何中斷一個(gè)Promise鏈呢?
??在Promise鏈中,對于fulfilled狀態(tài)或者rejected狀態(tài),都會(huì)傳遞到后面,所以需要一個(gè)pending狀態(tài)的Promise對象才可以完成!

??return new Promise(()=>{})

async/await

是實(shí)現(xiàn)異步調(diào)用的一個(gè)手段,await必須放到async里面,await可以簡單理解為async wait,后面一般修飾promise對象,等待pending狀態(tài)被改變。
異步讀取三個(gè)文件

async function main(){
    try{
        let data1 = await mineReadFile('./files/1.html');
        let data2 = await mineReadFile('./files/2.html');
        let data3 = await mineReadFile('./files/3.html');
        console.log(data1+data2+data3);
    }catch(e){
        console.log(e);
    }
}

如何使用async和await來實(shí)現(xiàn)發(fā)送AJAX呢?
先將AJAX用Promise封裝起來得到sendAJAX函數(shù)
之后定義

async function(){
	let data = await sendAJAX(url);
    console.log(data);
}

將該函數(shù)綁定到某個(gè)觸發(fā)事件中即可

axios

本質(zhì)是基于promise的Ajax流行庫,使用了promise并且底層發(fā)送Ajax。

請求流程

當(dāng)使用axios返送請求時(shí),會(huì)調(diào)用request(config),內(nèi)部執(zhí)行dispatchRequest(config),dispatchRequest()會(huì)調(diào)用適配器xhrAdapter,執(zhí)行回調(diào)后并返回promise對象。
當(dāng)數(shù)據(jù)完成響應(yīng)后,會(huì)原路返回,最后根據(jù)響應(yīng)結(jié)果axios.then()執(zhí)行相應(yīng)的回調(diào)函數(shù)。

request(config)會(huì)將請求攔截器、響應(yīng)攔截器、dispatchRequest()進(jìn)行promise串聯(lián),這樣可以完成攔截的功能。
在內(nèi)部主要存于chain數(shù)組中,只有經(jīng)過請求攔截器才會(huì)執(zhí)行dispatchRequest(),響應(yīng)結(jié)束后會(huì)執(zhí)行響應(yīng)攔截器,都返回成功才是真的成功。

dispatchRequest()會(huì)轉(zhuǎn)換請求數(shù)據(jù)和響應(yīng)數(shù)據(jù),并調(diào)用xhrAdapter()發(fā)送請求。

xhrAdapter()會(huì)創(chuàng)建XHR對象,發(fā)送Ajax請求。

取消流程

??當(dāng)需要取消請求的時(shí)候,我們可以通過執(zhí)行某個(gè)函數(shù)從而改變promise的狀態(tài),當(dāng)promise狀態(tài)從pending->fulfilled立馬執(zhí)行then的成功回調(diào),而這個(gè)成功回調(diào)會(huì)執(zhí)行xhr.abort(),所以可以暴露出來一個(gè)改變該promise對象狀態(tài)的函數(shù)即可完成取消請求。文章來源地址http://www.zghlxwxcb.cn/news/detail-797200.html

//取消請求
if(config.cancelToken){
    //對cancelToken 對象身上的 promise對象指定成功的回調(diào)
    config.cancelToken.promise.then(value=>{
        xhr.abort();
    })
    //一直是pending狀態(tài) 一旦改變成fulfilled狀態(tài)立馬執(zhí)行回調(diào)
}

到了這里,關(guān)于WebSocket+Vue實(shí)現(xiàn)簡易多人聊天室 以及 對異步調(diào)用的理解的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 基于WebSocket的簡易聊天室的基本實(shí)現(xiàn)梳理

    基于WebSocket的簡易聊天室的基本實(shí)現(xiàn)梳理

    目前在很多網(wǎng)站為了實(shí)現(xiàn)推送技術(shù)所用的技術(shù)都是 Ajax 輪詢。輪詢是在特定的的時(shí)間間隔(如每1秒),由瀏覽器對服務(wù)器發(fā)出HTTP請求,然后由服務(wù)器返回最新的數(shù)據(jù)給客戶端的瀏覽器。HTTP 協(xié)議是一種無狀態(tài)的、無連接的、單向的應(yīng)用層協(xié)議。它采用了請求/響應(yīng)模型。通信

    2024年02月11日
    瀏覽(23)
  • Java+Vue實(shí)現(xiàn)聊天室(WebSocket進(jìn)階-聊天記錄)

    Java+Vue實(shí)現(xiàn)聊天室(WebSocket進(jìn)階-聊天記錄)

    WebSocket 是一種在單個(gè)TCP連接上進(jìn)行全雙工通信的協(xié)議。WebSocket通信協(xié)議于2011年被IETF定為標(biāo)準(zhǔn)RFC 6455,并由RFC7936補(bǔ)充規(guī)范。WebSocket API也被W3C定為標(biāo)準(zhǔn)。 WebSocket使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡單,允許服務(wù)端主動(dòng)向客戶端推送數(shù)據(jù)。在WebSocket API中,瀏覽器和服

    2024年02月11日
    瀏覽(111)
  • 【W(wǎng)ebSocket&IndexedDB】node+WebSocket&IndexedDB開發(fā)簡易聊天室

    【W(wǎng)ebSocket&IndexedDB】node+WebSocket&IndexedDB開發(fā)簡易聊天室

    序幕介紹: WebSocket 是 HTML5 開始提供的一種在單個(gè) TCP 連接上進(jìn)行全雙工通訊的協(xié)議。 講人話就是說: WebSocket 使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡單,在 WebSocket API 中,瀏覽器和服務(wù)器只需要完成一次握手,兩者之間就直接可以創(chuàng)建持久性的連接,并進(jìn)行雙向數(shù)

    2024年02月10日
    瀏覽(47)
  • websocket實(shí)現(xiàn)聊天室(vue2 + node)

    websocket實(shí)現(xiàn)聊天室(vue2 + node)

    需求分析如圖: 搭建的項(xiàng)目結(jié)構(gòu)如圖: 前端步驟: vue create socket_demo (創(chuàng)建項(xiàng)目) views下面建立Home , Login組件 路由里面配置路徑 Home組件內(nèi)部開啟websocket連接 前端相關(guān)組件代碼: Login組件 Home組件 router/index.js 后端步驟: 在項(xiàng)目外層創(chuàng)建server文件夾(src目錄同級) npm init -y創(chuàng)建

    2024年01月22日
    瀏覽(101)
  • vue3-多人聊天室角色識(shí)別(全棧)

    vue3-多人聊天室角色識(shí)別(全棧)

    主要技術(shù)棧是vue3,springboot,websocket,element-plus 主要目的是復(fù)習(xí)和梳理 發(fā)送信息,包裝信息,轉(zhuǎn)json,用socket發(fā)送到后端,使輸入欄清空 后端解析json,因?yàn)槭莝ocket接口,所以不能用@requestbody解析json,用以下方式解析json 設(shè)置發(fā)送時(shí)間為當(dāng)前時(shí)間,然后執(zhí)行mapper數(shù)據(jù)庫插入 廣

    2024年02月11日
    瀏覽(32)
  • SpringBoot和Vue2集成WebSocket,實(shí)現(xiàn)聊天室功能

    springboot集成websocket實(shí)現(xiàn)聊天室的功能。如有不足之處,還望大家斧正。

    2024年01月23日
    瀏覽(27)
  • C語言實(shí)現(xiàn)--基于UDP的多人在線聊天室

    C語言實(shí)現(xiàn)--基于UDP的多人在線聊天室

    目錄 實(shí)現(xiàn)功能 實(shí)現(xiàn)思想 實(shí)現(xiàn)代碼(部分及詳解) 服務(wù)端部分代碼 客戶端部分代碼 實(shí)現(xiàn)效果 項(xiàng)目中出現(xiàn)的問題和解決方法 項(xiàng)目整體代碼展示 代碼優(yōu)化思路 服務(wù)端代碼 客戶端代碼 服務(wù)端可以同時(shí)連接多個(gè)客戶端; 新的客戶端連接服務(wù)端時(shí),可以在服務(wù)端顯示自己的名字并

    2024年02月04日
    瀏覽(27)
  • 【Linux網(wǎng)絡(luò)編程】基于UDP實(shí)現(xiàn)多人聊天室

    【Linux網(wǎng)絡(luò)編程】基于UDP實(shí)現(xiàn)多人聊天室

    UDP(User Datagram Protocol)用戶數(shù)據(jù)報(bào)協(xié)議,是不可靠的無連接的協(xié)議。在數(shù)據(jù)發(fā)送前,因?yàn)椴恍枰M(jìn)行連接,所以可以進(jìn)行高效率的數(shù)據(jù)傳輸。 數(shù)據(jù)報(bào)格式套接字 SOCK_DGRAM 采用UDP只管發(fā)送數(shù)據(jù)而不去驗(yàn)證發(fā)送數(shù)據(jù)的正確性,不論傳輸是否被接收,數(shù)據(jù)流是否有丟失,都不再重新發(fā)

    2024年02月08日
    瀏覽(27)
  • 【你的第一個(gè)socket應(yīng)用】Vue3+Node實(shí)現(xiàn)一個(gè)WebSocket即時(shí)通訊聊天室

    【你的第一個(gè)socket應(yīng)用】Vue3+Node實(shí)現(xiàn)一個(gè)WebSocket即時(shí)通訊聊天室

    這篇文章主要是用WebSocket技術(shù)實(shí)現(xiàn)一個(gè) 即時(shí)通訊聊天室 ,首先先要了解為什么使用WebSocket而不是普通的HTTP協(xié)議,如果使用HTTP協(xié)議它是下面這種情況: 我發(fā)送一條消息,發(fā)送一個(gè)發(fā)送消息的請求;* 一直輪詢接收別人發(fā)送的消息,不管有沒有發(fā)送都要定時(shí)去調(diào)用接口。這里明

    2023年04月20日
    瀏覽(31)
  • 基于Python guI的多人聊天室的設(shè)計(jì)與實(shí)現(xiàn)

    基于Python guI的多人聊天室的設(shè)計(jì)與實(shí)現(xiàn)

    現(xiàn)在,即時(shí)聊天系統(tǒng)已成為 Internet 上的主要交流工具,并且涌現(xiàn)出大量的AP和平臺(tái)。這些AP和平臺(tái)都擁有更加完善的交換機(jī)制,使得人們可以更加便捷地進(jìn)行溝通和交換信息。 廣域網(wǎng)的聊天系統(tǒng)多重多樣,知名的軟件主要有 Facebook、騰訊 QQ 等。局域網(wǎng)聊天通信軟件也有很多,

    2024年02月05日
    瀏覽(20)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包