[深刻15] WebSocket

導航

[深刻01] 執行上下文
[深刻02] 原型鏈
[深刻03] 繼承
[深刻04] 事件循環
[深刻05] 柯里化 偏函數 函數記憶
[深刻06] 隱式轉換 和 運算符
[深刻07] 瀏覽器緩存機制(http緩存機制)
[深刻08] 前端安全
[深刻09] 深淺拷貝
[深刻10] Debounce Throttle
[深刻11] 前端路由
[深刻12] 前端模塊化
[深刻13] 觀察者模式 發佈訂閱模式 雙向數據綁定
[深刻14] canvas
[深刻15] webSocket
[深刻16] webpack
[深刻17] http 和 https
[深刻18] CSS-interview
[react] Hookshtml

[部署01] Nginx
[部署02] Docker 部署vue項目
[部署03] gitlab-CI前端

[源碼-webpack01-前置知識] AST抽象語法樹
[源碼-webpack02-前置知識] Tapable
[源碼-webpack03] 手寫webpack - compiler簡單編譯流程vue

前置知識

一些單詞

specify:指定
stable:穩定的
amount:合計
optional:可選的 
optional object:可選對象
ordinary:普通的
omitted:省略的
broadcast:廣播
outdated:過期的
複製代碼

NRM - nrm

  • nrm 的做用是 ( 切換npm源 ) (npm的註冊表管理器,能夠切換npm的鏡像地址)
  • npm, cnpm, taobao, nj(nodejitsu)等
  • command:命令
  • 全局安裝後,報錯處理
    • nrm : 沒法加載文件 D:\Program Files\nodejs\nrm.ps1,由於在此係統上禁止運行腳本。
    • 解決辦法:
      • (1) 用管理員身份打開cmd,輸入如下命令
      • (2) set-ExecutionPolicy RemoteSigned命令將計算機上的執行策略更改成 RemoteSigned,輸入Y肯定
    • ExecutionPolicy:執行策略
    • 執行策略能夠幫助你執行不信任的腳本
(1) install
npm install -g nrm


(2) useage
nrm [options] [command] 

options
-h,--help //----------------------------------- help
-V,--version //-------------------------------- version number

commonds
nrm ls //------------------------------------------- 列出全部源
nrm use <registry> //------------------------------- 使用具體哪一個源
nrm add <registry> <url> [home] //------------------ 添加源,(1) registry是源的名字,能夠隨便取 (2) url源地址
nrm del <registry> //------------------------------- 刪除源
nrm test [registry] // ----------------------------- 測速,返回響應的時間
複製代碼

NVM - nvm

  • nvm 用於切換 node 和 npm 版本
  • windows系統上能夠用 nvm-windows
  • 教程:
  • 注意事項 !!!!!!!
    • 若是以前安裝過node即系統中存在node,須要將node卸載乾淨,步驟以下

useage

nvm use <version> [arch] //------------------ 使用哪一個版本的node,(arch表示32位或64位,非必須)
mvm list [available] // --------------------- 展現可用的node版本列表,(available表示有效,非必須)
nvm install <version> [arch] // ------------- 安裝指定的node版本,version表示具體的版本號
nvm uninstall <version>
複製代碼
----
查看全局安裝的包:----------------- npm ls -g --depth=0
查看全局安裝的包:----------------- npm list -g --depth=0 // ls 和 list 均可以
卸載本地全局安裝包:--------------- npm uninstall -g xxxx
查看須要更新的全局包:------------- npm outdated -g --depth=0 // outdated是過期的意思

npm info xxxx // ------------------------------ 遠程包的信息
npm info xxxx version // ---------------------- 遠程最新的版本號
npm info xxxx versions // --------------------- 遠程全部版本號
複製代碼

window.postMessage 跨域通訊

  • window.postMessage 能夠實現跨域信息交互,兩個web瀏覽器標籤頁之間的通訊IFrame 通訊等
  • otherWindow.postMessage(message, targetOrigin, [transfer]);
  • 注意:在targetWindow.open()後,要等到目標頁面加載完成才能進行 postMessage 跨域通訊,可是在跨域的狀況下,沒法對目標窗口進行onload監聽,因此能夠用 setTimeout延時,對於IFrame同理
(一)
otherWindow.postMessage(message, targetOrigin, [transfer]) 跨域通訊

(1) otherWindow
- otherWindow指的是其餘窗口的一個引用
1. iframe 的 contentWindow 屬性
2. window.open() 返回的一個窗口對象
3. 命名過或數值索引的 window.frames
4. 兩個窗口之間
  - a -> b,otherWindow是b窗口
  - b -> a,otherWindow是a窗口,即 ( top ) 或者 ( parent )

(2) message
- message指發送給其餘窗口的數據
- message會被序列化,因此無需本身序列化

(3) targetOrigin     !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- targetOrigin:設置目標窗口的源(協議域名端口組成的字符串),指定哪些窗口能 ( 接收 ) 到消息事件
- 在 ( 發消息 ) 的時候,若是( 目標窗口 ) 的 ( 協議,域名,端口) 任意一項不知足 targetOrigin 提供的值,消息就不會發送
- 三者要所有匹配纔會發送
- targetOrigin的值能夠是 (  *  ) 號,表示全部窗口都能接收到消息

(4) transfer
- transfer 是一串和message同時傳遞的 Transferable 對象
- 這些對象的全部權將被轉移給消息的接收方,而發送一方將再也不保有全部權



發消息:--------------- otherWindow.postMessage(message, targetOrigin, [transfer])
收消息:--------------- window.addEventListener('message', (data) => {console.log(data.data, data.origin)}, false)
注意:----------------- 經過 ( targetOrigin - 驗證接收方 ) 和 ( data.origin - 驗證發送方 ) 來精確通訊


- data.origin 和 data.source 和 data.data
- 在接收端的監聽函數中,注意 origin 和 source
- origin: ------------- 發送方的協議,域名,端口組成的字符串
- source:------------- 發送方窗口對象的引用
- data:--------------- 接收到的數據
window.addEventListener("message", receiveMessage, false); // 接收消息的tab標籤頁面監聽message事件
function receiveMessage(event) {
  // For Chrome, the origin property is in the event.originalEvent
  // object. 
  // 這裏不許確,chrome沒有這個屬性
  // var origin = event.origin || event.originalEvent.origin; 
  var origin = event.origin
  if (origin !== "http://example.org:8080")
    return;
    // ...
}


(二)
注意事項:
- 使用postMessage將數據發送到其餘窗口時,始終要指定精確的目標origin,而不是使用 *
- 使用 origin 和 source 驗證 ( 發件人 ) 的身份


(三)
實例:

--------------
a頁面
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="a-open">點擊,打開b頁面</div>
  <div id="a-send">點擊,發送消息,a->b</div>
  <script>
    const aOpen = document.getElementById('a-open')
    const aSend = document.getElementById('a-send')
    var a = null
    aOpen.addEventListener('click', () => a = window.open('http://127.0.0.1:5500/b.html'), false)
    aSend.addEventListener('click', () => a.postMessage('this message is a to b', 'http://127.0.0.1:5500'), false)
    // 注意:
    // 1. a.postMessage只有在目標頁面(b頁面)的頁面加載完成時才能發送
    // 2. a.postMessage的第二個參數,表示targetOrigin目標源,即目標窗口的協議域名端口組成的字符串
    // 3. targetOrigin設置事後,只有目標窗口徹底符合targetOrigin字符串的值才能接收到消息
  </script>
</body>
</html>


---------------
b頁面
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div>b頁面</div>
  <script>
    window.addEventListener('message', (data) => { // ----- 監聽message事件
      console.log(data)
    }, false)
  </script>
</body>
</html>
複製代碼

websocket概述

  • websocket是應用層協議的一種,創建在http協議之上,是一種雙向通訊的協議
  • HTTP在1.1版本中也能創建長鏈接 Connection:Keep-alive
    • 可是 ( HTTP ) 創建的長鏈接本質上仍是 request response 這樣的形式,即 ( 一個request對應一個response )
    • 而 ( websocket ) 是 ( 全雙工通訊 )
  • TCP是傳輸層協議
  • HTTP 和 websocket 是應用層的協議
  • IP是網絡層協議

WebSocket 客戶端api

new WebSocket(url)

  • const ws = new WebSocket('ws://localhost:8080')
  • WebSocket 做爲構造函數,用於新建 websocket 實例
  • ws:表示websocket協議
  • wss:表示websocket加密協議

webSocket.readyState

  • readyState 屬性返回實例對象的當前狀態,一共4種
CONNECTING:0 --------------- 表示正在鏈接
OPEN: 1 --------------------- 表示鏈接成功,能夠通訊了
CLOSING:2 ------------------ 表示鏈接正在關閉
CLOSED:3 ------------------- 表示鏈接已經關閉,或者鏈接打開失敗
複製代碼

webSocket.onopen

  • 指定鏈接成功後的回調函數
  • 指定一個回調函數:ws.onopen = function(){}
  • 指定多個回調函數:ws.addEventListener('open', function(){})

webSocket.onclose

  • 指定鏈接關閉後的回調函數

webSocket.onmessage

  • 指定收到服務器數據後的回調函數
  • 注意:服務器返回的數據有兩種可能 ( 文本 ) 或 ( 二進制數據 - blob對象或Arraybuffer對象 )
  • 判斷數據數據類型: binaryType
    • ws.binaryType = 'blob'
    • ws.binaryType = 'arraybuffer'
    • binary:二進制的
ws.onmessage = function(event) {
  var data = event.data;
  // 處理數據
};

ws.addEventListener("message", function(event) {
  var data = event.data;
  // 處理數據
});


----------


ws.onmessage = function(event){
  if(typeof event.data === String) {
    console.log("Received data string");
  }

  if(event.data instanceof ArrayBuffer){
    var buffer = event.data;
    console.log("Received arraybuffer");
  }
}
複製代碼

webSocket.send()

  • wx.send() 用於向服務器發送數據

webSocket.bufferedAmount

  • wx.bufferedAmount 表示還有多少字節的二進制數據沒有發送出去,能夠用來判斷是否發送結束
  • wx.bufferedAmount === 0 表示發送結束
  • amount:合計的意思

webSocket.onerror

  • wx.onerror 指定報錯時的回調函數

使用 websocket 和 nodejs-websocket 簡單聊天室

客戶端:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <input type="text" id="name-input">
  <button id="name-button">建立名字</button>
  <input type="text" id="input">
  <button id="button">發送消息</button>
  <script>
    const inputDom = document.getElementById('input')
    const button = document.getElementById('button')
    const nameInput = document.getElementById('name-input')
    const nameButton = document.getElementById('name-button')
    const ws = new WebSocket('ws://localhost:5555') 
    // ----------------------------------------------------- 生成websocket實例對象
    // ----------------------------------------------------- 參數是url
    // ----------------------------------------------------- 注意:協議是 (ws:// ) 或者 (wss:// 加密協議)
    ws.onopen = function() { // ---------------------------- onopen:鏈接成功後的回調
      // ws.send('客服端 => 發送給服務端的消息字符串') // -- send():向服務端發送消息
      nameButton.addEventListener('click', () => {
        nameButton.setAttribute('disabled', 'disabled')
        ws.send(JSON.stringify({
          type: 'name',
          value: nameInput.value
        }))
      }, false)
      button.addEventListener('click', () => {
        ws.send(JSON.stringify({
          type: 'chat',
          value: inputDom.value,
        }))
      }, false)
    }
    ws.onmessage = function(e) { // --------------------------- onmessage:收到服務端返回數據時觸發的回調
      const p = document.createElement('p')
      p.innerHTML = e.data
      document.body.appendChild(p)
    }
/*
    ws.addEventListener('open', connectedCallback, false)
    function connectedCallback() {
      ws.send('客服端 => 發送給服務端的消息字符串')
    }
    ws.onopen = function() {
      ws.send('客服端 => 發送給服務端的消息字符串')
    }
    ws.onmessage = function(e) {
      console.log(e.data)
    }
*/
  </script>
</body>
</html>

複製代碼
服務端:
const ws = require('nodejs-websocket')

const server = ws.createServer(function(conn) {
  console.log("New connection")
  conn.on("text", function (str) { // ------------------------ 客戶端發來的數據是text類型時觸發
       console.log("Received "+str)
    // conn.sendText(str)
    const data = JSON.parse(str)

    switch(data.type) {
      case 'name':
          conn.nickname = data.value;
          broadcast(data.value + '加入了房間');
          break;
      case 'chat':
          console.log(data.value, 'data.value');
          broadcast(data.value);
          break;
      default:
        break;
    }
  })
  function broadcast(str) { // --------------------------------------- broadcast:廣播
    server.connections.forEach((conn) => {
      conn.sendText(str)
    })
  }
    conn.on("close", function (code, reason) { // --------------------- 關閉鏈接時觸發
    console.log("Connection closed")
    broadcast(conn.nickname + '離開了房間')
  })
  // conn.send('服務端 => 發給客服端的消息')
  conn.on('error', (err) => { // -------------------------------------- 處理錯誤
    console.log(err)
  })
})
server.listen(5555, () => console.log('server runing')) // ------------- 監聽端口
複製代碼

資料

juejin.im/post/5a1bdf…
阮一峯 www.ruanyifeng.com/blog/2017/0…
nvm 和 nrm juejin.im/post/5c9040…
nrm官網:github.com/Pana/nrm
nrn安裝後輸入命令報錯:blog.csdn.net/ougexingfub…
nodejs-websocket:github.com/sitegui/nod…
otherWindow.postMessage:juejin.im/entry/57d7c…node

相關文章
相關標籤/搜索