共计 10303 个字符,预计需要花费 26 分钟才能阅读完成。
导航
[[深刻 01] 执行上下文](https://juejin.im/post/684490…
[[深刻 02] 原型链](https://juejin.im/post/684490…
[[深刻 03] 继承](https://juejin.im/post/684490…
[[深刻 04] 事件循环](https://juejin.im/post/684490…
[[深刻 05] 柯里化 偏函数 函数记忆](https://juejin.im/post/684490…
[[深刻 06] 隐式转换 和 运算符](https://juejin.im/post/684490…
[[深刻 07] 浏览器缓存机制(http 缓存机制)](https://juejin.im/post/684490…
[[深刻 08] 前端平安](https://juejin.im/post/684490…
[[深刻 09] 深浅拷贝](https://juejin.im/post/684490…
[[深刻 10] Debounce Throttle](https://juejin.im/post/684490…
[[深刻 11] 前端路由](https://juejin.im/post/684490…
[[深刻 12] 前端模块化](https://juejin.im/post/684490…
[[深刻 13] 观察者模式 公布订阅模式 双向数据绑定](https://juejin.im/post/684490…
[[深刻 14] canvas](https://juejin.im/post/684490…
[[深刻 15] webSocket](https://juejin.im/post/684490…
[[深刻 16] webpack](https://juejin.im/post/684490…
[[深刻 17] http 和 https](https://juejin.im/post/684490…
[[深刻 18] CSS-interview](https://juejin.im/post/684490…
[[深刻 19] 手写 Promise](https://juejin.im/post/684490…
[[深刻 20] 手写函数](https://juejin.im/post/684490…
[[react] Hooks](https://juejin.im/post/684490…
[[部署 01] Nginx](https://juejin.im/post/684490…
[[部署 02] Docker 部署 vue 我的项目](https://juejin.im/post/684490…
[[部署 03] gitlab-CI](https://juejin.im/post/684490…
[[源码 -webpack01- 前置常识] AST 形象语法树](https://juejin.im/post/684490…
[[源码 -webpack02- 前置常识] Tapable](https://juejin.im/post/684490…
[[源码 -webpack03] 手写 webpack – compiler 简略编译流程](https://juejin.im/post/684490…
[[源码] Redux React-Redux01](https://juejin.im/post/684490…
[[源码] axios ](https://juejin.im/post/684490…
[[源码] vuex ](https://juejin.im/post/684490…
[[源码 -vue01] data 响应式 和 初始化渲染 ](https://juejin.im/post/684490…
[[源码 -vue02] computed 响应式 – 初始化,拜访,更新过程 ](https://juejin.im/post/684490…
前置常识
一些单词
specify:指定
stable:稳固的
amount:共计
optional:可选的
optional object:可选对象
ordinary:一般的
omitted:省略的
broadcast:播送
outdated:过期的
NRM – nrm
- nrm 的作用是 (<font color=red> 切换 npm 源 </font>)
(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
- <font color=red>nvm 用于切换 node 和 npm 版本 </font>
- windows 零碎上能够用 <font color=red>nvm-windows</font>
- [教程:]()
-
注意事项 !!!!!!!
- 如果之前装置过 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 能够实现跨域信息交互,<font color=red> 两个 web 浏览器标签页之间的通信 </font>,<font color=red>IFrame</font> 通信等
- 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 概述
- <font color=red>websocket 是应用层协定的一种,建设在 http 协定之上,是一种双向通信的协定 </font>
-
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
- 指定连贯敞开后的回调函数
<font color=red>webSocket.onmessage</font>
- <font color=red> 指定收到服务器数据后的回调函数 </font>
- 留神:服务器返回的数据有两种可能 (<font color=red> 文本 </font>) 或 (<font color=red> 二进制数据 – blob 对象或 Arraybuffer 对象 </font>)
-
判断数据数据类型:<font color=red> binaryType </font>
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"); } }
<font color=red>webSocket.send()</font>
- <font color=red>wx.send() 用于向服务器发送数据 </font>
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')) // ------------- 监听端口
材料
https://juejin.im/post/684490…
阮一峰 http://www.ruanyifeng.com/blo…
nvm 和 nrm https://juejin.im/post/684490…
nrm 官网:https://github.com/Pana/nrm
nrn 装置后输出命令报错:https://blog.csdn.net/ougexin…
nodejs-websocket:https://github.com/sitegui/no…
otherWindow.postMessage:https://juejin.im/entry/68449…