跨域问题
1. 跨域问题说明
- 浏览器 为了网络安全, 有一个同源策略, 要求必须 域名、端口、协议 三个都相同.
- 都相同了才认为是同源, 是安全可靠的,才允许ajax请求数据
为了能够成功的拿到数据, 跨域有三种常见的解决方案:
1.1 jsonp
- 原理 : 利用 script 标签 src 属性, 跨域请求服务器资源
- 前端 : jquery => $.ajax({ dataType:‘jsonp’ }) 发送一个jsonp请求
- 好处 : 兼容性好, 早期使用率比较高
- 缺点 : 只能发送 get 请求
1.2 cors 跨域资源共享 (Cross-origin resource sharing)
- 原理 : xhr2.0 允许跨域资源共享, 后台需要设置响应头
- 后端 :
res.setHeader('Access-Control-Allow-Origin':'*' )
- 好处 : 简单方便, 前端不需要做任何处理, 且支持任何请求类型,
- 缺点 : 兼容性 IE 10/11+, 和后台沟通好
1.3 代理服务器
- 原理 : 服务器给服务器发请求, 服务器之间没有跨域问题, 没有同源策略
- 演示1 : webpack 代理 (开发阶段, 临时解决跨域问题)
- 演示2 : nginx 代理 (上线阶段)
2. webpack 配置反向代理
开发阶段 => 我们开发人员配置
- 图解
- 演示接口 : http://toutiao-app.itheima.net/v1_0/user/channels
- 访问 :
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rl7PdDO7-1608472784003)(images/Snipaste_2020-12-09_19-57-14.png)]
- 在
vue.config.js
中配置
module.exports = {
devServer: {
open: true,
...改前...
proxy: {
'/aaa': {
target: 'http://baidu.com/',
pathRewrite: { '^/aaa': '' },
secure: true, // 默认值 true
changeOrigin: true // 默认值 true
}
}
...改后...
proxy: {
'/mgapi': {
target: 'http://toutiao-app.itheima.net',
pathRewrite: { '^/mgapi': '' },
secure: true, // 默认值 true
changeOrigin: true // 默认值 true
}
}
...
},
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rXSfKkud-1608472784007)(images/Snipaste_2020-12-09_19-58-34.png)]
参数说明:
-
target 代理到的目标地址
-
pathRewrite 路径重写
-
secure: true
-
https 协议使用
-
true : 将不接受在 HTTPS 上运行且证书无效的后端服务器。 (默认值: true)
-
fale : 如果需要接收证书无效的后端服务器数据,可以这样修改配置为 false
-
-
changeOrigin: true (默认值: true)
默认情况下,代理时会保留主机头的来源,可以将
changeOrigin
设置为true
, 如果设置成true, 发送请求头中host会设置成target。
- webpack反向代理的注意事项
注意: 开发阶段, 可以配置webpack的反向代理, 解决跨域问题, 但是如果项目上线, 那么webpack的反向代理就失效了!!!
3. nginx 配置反向代理
线上阶段 => 后台人员配置 => 我们了解即可
准备工作
3.1 下载 nginx windows版本 演示
下载地址:http://nginx.org/en/download.html => 已下载到 资源文件
演示 可拷贝至桌面 保证路径不能有汉字
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EoC3u6tl-1608472784008)(images/Snipaste_2020-12-09_20-00-34.png)]
3.2 双击 : nginx.exe
=> 闪一下代码开启成功
3.3 浏览器访问 localhost
=> 默认80端口 => 页面展示成功
3.4 关闭 nginx, 执行命令, 杀死起的 nginx 服务器进程即可
taskkill /f /t /im nginx.exe
跨域配置
3.1 把 dist/ 包
拷贝到 nginx 里面的 html/
内
3.2 双击 nginx.exe
=> 开启 nginx => 闪一下
3.3 访问 localhost
=> 页面成功 => 数据访问失败
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-btH6b0Ni-1608472784010)(images/Snipaste_2020-12-09_20-09-12.png)]
3.4 配置跨域
- 把
/mgapi
干掉重写 - 拼接路径
http://toutiao-app.itheima.net
location /mgapi {
rewrite ^.+mgapi/?(.*)$ /$1 break;
include uwsgi_params;
proxy_pass http://toutiao-app.itheima.net;
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ILQ4FrRs-1608472784011)(images/Snipaste_2020-12-09_20-10-09.png)]
3.5 访问 : localhost:80
或者 locahost
=> 页面(ok) + 接口(ok)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UBIvJeb3-1608472784013)(images/Snipaste_2020-12-09_20-15-51.png)]
3.6 关闭 nginx, 执行命令, 杀死起的 nginx 服务器进程即可
taskkill /f /t /im nginx.exe
开启 nginx => 双击 nginx.exe => 闪一下
修改conf配置文件
方式1 : nginx.exe -s reload => 重启
方式2 : 先杀掉 进程 taskkill /f /t /im nginx.exe => 双击开启
vue中双向数据绑定的原理
双向数据绑定 无非就是实现 视图层(V) 和 数据层(M) 的同步 , 也就是考察 MVVM 原理 ( 数据劫持 )
M => V : 数据层的数据变化, 视图层自动更新
V => M : 视图层的数据变化, 数据层自动更新
1. 基本原理
vue2.0 数据劫持: Object.defineProperty (es5)
vue3.0 数据劫持: Proxy (es6)
解答: Vue的双向绑定原理其实就是 MVVM 的基本原理, Vuejs官网已经说明, 实际就是通过 Object.defineProperty方法 完成了对于Vue实例中数据的 劫持
, 通过对于 data中数据 进行set/get的劫持监听, 然后通过**观察者模式
**, 通知 对应的绑定节点 进行节点数据更新, 完成数据驱动视图的更新
简单概述 : 通过Object.defineProperty 完成对于数据的劫持, 利用观察者模式, 完成对于节点的数据更新
##2. 具体代码
2.1 Object.defineProperty
// vue2.0 版本中, 使用的是 es5的数据劫持来实现数据的双边绑定 , vue2.0 不兼容 IE678,
var data = {
name : 'zs',
age : 18,
gender : '男'
}
// 数据劫持的缺点1 : 每次只能劫持一个属性, 对于一个对象来说, 需要遍历来劫持
for(let k in data) {
let temp = data[k]
// 参数1 : 对象
// 参数2 : 属性
// 参数3 : 属性描述符
Object.defineProperty(data, k, {
set(val){
console.log('劫持了 set');
temp = val
},
get(){
console.log('劫持了 get');
return temp
}
})
}
// 数据劫持的缺点2 : 动态的添加属性, 劫持不了, 浏览器测试, 不打印劫持代码
data.money = '100'
2.2 Proxy
// 代理了data对象, 得到一个新对象 操作新对象即可
const newObj = new Proxy(data,{
set(target,k,v){
console.log('劫持了 set');
target[k] = v
},
get(target,k){
console.log('劫持了 get');
return target[k]
}
})
// 添加定属性 => 浏览器演示 => newObj.name 和 newObj.name='ls' => 打印 劫持
data.money = 100
3. 底层原理
vue 官网 => 深入响应式原理
组件内部
data : {
name : 'zs',
age : 20
}
<h1>{{ name }}</h1>
<p>{{ name }}</p>
- Data => Observer(defineReactive(defineProperty)) => Data(setter/getter)
- getter => Watcher(name) => Dep([Watcher])
- setter => Dep([]) => notify => Watcher => re-render => update
组件外部
- 父组件 => msg => 子组件实例 => props
- 子组件实例 --- 对应一个 Watcher
- msg变化 => notify => Watcher => re-render => update
图解
4. 虚拟DOM
- DOM是前端性能的瓶颈,操作DOM, 有损性能
- 虚拟DOM就是一个普通的js对象, 可以完整的描述DOM结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w5dwaLNL-1608472784013)(images/虚拟DOM.png)]
Promise 相关
1. Promise的静态方法
1.1 Promise.resolve()
// 简写:
new Promise((resolve, reject) => {
resolve()
})
// 演示 :
let res = Promise.resolve('123')
res.then(res => {
console.log('then:', res)
}).catch(err => {
})
1.2 Promise.reject()
// 简写:
new Promise((resolve, reject) => {
reject()
})
// 演示 :
let res = Promise.reject('123')
res.then(res => {
}).catch(err => {
console.log('catch:', err)
})
1.3 Promise.all([promise1, promise2, promise3]) 是在所有promise都完成后执行, 可以用于处理一些并发的任务
let p1 = axios.get(' http://localhost:3000/list1')
let p2 = axios.get(' http://localhost:3000/list2')
let p3 = axios.get(' http://localhost:3000/list3')
Promise.all([p1,p2,p3]).then(res =>{
console.log('all:',res);
})
1.4 Promise.race([promise1, promise2, promise3]) 是在所有promise中只要一个执行完成, 可以用于处理一些并发的任务
let p1 = axios.get(' http://localhost:3000/list1')
let p2 = axios.get(' http://localhost:3000/list2')
let p3 = axios.get(' http://localhost:3000/list3')
Promise.race([p1,p2,p3]).then(res =>{
console.log('race:',res);
})
2. 事件循环 EventLoop
- 演示1 : 延时器 + for 10000
- 演示2 : 定时器 + for 10000
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CEpXtQDo-1608472784014)(images/事件循环.png)]
3. 宏任务和微任务面试题
题目1 :
console.log('start');
setTimeout(() => {
console.log('timeout');
}, 0);
new Promise((resolve)=>{
console.log('promise1');
resolve()
}).then(res => {
console.log('then1');
})
console.log('end');
解析1 :
宏任务 : js中script部分、setTimeout
微任务 : Promise.then( 非 new Promise()部分 )
setTimeout 是下一次循环的宏任务
题目2 :
async function async1() {
console.log('async1 start');
await async2();
console.log('asnyc1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(() => {
console.log('setTimeOut');
}, 0);
async1();
new Promise(function (reslove) {
console.log('promise1');
reslove();
}).then(function () {
console.log('promise2');
})
console.log('script end');
解析2 :
- await之后如果不是promise,await会阻塞后面的代码,会先执行async外面的同步代码,等外面的同步代码执行完成在执行async中的代码。
- 如果它等到的是一个 promise 对象,await 也会暂停async后面的代码,先执行async外面的同步代码,等着 Promise 对象 fulfilled,然后把 resolve 的参数作为 await 表达式的运算结果。
Grid 网格布局(二维布局)
1. 结构
<style>
.item1 {
background-color: pink;
}
.item2 {
background-color: red;
}
.item3 {
background-color: green;
}
.item4 {
background-color: skyblue;
}
.container {
width: 400px;
background-color: #ccc;
}
</style>
<div class="container">
<div class="item1">1</div>
<div class="item2">2</div>
<div class="item3">3</div>
<div class="item4">4</div>
</div>
2. 基本特性
2.1 样式
.container {
width: 400px;
background-color: #ccc;
display: grid;
/* x 轴的个数+宽度 */
grid-template-columns:repeat(2,1fr) ;
/* y 轴的个数 + 高度 */
grid-template-rows: 50px 100px;
/* justify-items: center;
align-items: center; */
/* place-items: center start; */
/* gap : 10px; */
}
.container div {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
2.2 知识点
// flex布局 : 一维布局
// grid布局 : 二维布局
//1. 给 容器 添加 gird 布局
//2. x 轴的个数+宽度
// grid-template-columns: 200px 200px;
//3 y 轴的个数 + 高度
// grid-template-rows: 50px 100px;
//4. 值的类型
//4.1 绝对值 : 100px 200px
//4.2 百分比 : 50% 30%
//4.3 比例 : 1fr 2fr
//4.4 重复 : repeat(2,1fr)
//5. 水平、垂直问题
// place-items : center center; // start center end
//6. 间隙
// gap : 10px;
// gap : 10px 50px
3. 题目1
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RlDDakQf-1608472784015)(images/grid1.png)]
.container {
background-color: #ccc;
display: grid;
grid-template-columns: 1fr 1fr 2fr 2fr;
grid-template-rows: 60px;
}
.container div {
display: flex;
justify-content: center;
align-items: center;
color: #333;
}
4. 题目2
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SMesczNo-1608472784015)(images/grid2.png)]
.container {
background-color: #ccc;
display: grid;
grid-template-columns: 1fr 1fr ;
grid-template-rows: 150px 150px;
gap : 20px;
padding: 20px;
}
.container div {
display: flex;
justify-content: center;
align-items: center;
color: #333;
}
一次完整的http访问过程
1. 题目: 访问过程
当我们在 web浏览器的地址栏中输入 :
www.baidu.com
, 具体发生了什么 ?
1. 首页对 www.baidu.com 这个网址进行DNS域名解析,得到对应的IP地址
2. 根据这个IP,找到对应的服务器,发起TCP的三次握手
3. 建立TCP连接后发起HTTP请求
4. 服务器响应HTTP请求,浏览器得到html代码
5. 浏览器解析html代码,并请求html代码中的资源(如js、css、图片等)(先得到html代码,才能去找这些资源)
6. 浏览器对页面进行渲染呈现给用户
7. 服务器关闭关闭TCP连接
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-npB6L5ez-1608472784016)(images/http请求过程.png)]
2.DNS 解析
a)找缓存 : 首先会搜索浏览器自身的DNS缓存(缓存时间比较短,大概只有1分钟,且只能容纳1000条缓存)
b)找hosts : 如果浏览器自身的缓存里面没有找到,那么尝试从 hosts 文件里面去找
C:\Windows\System32\drivers\etc
d)找DNS服务器 : 在前面都没获取到的情况下,就递归地去域名服务器去查找,具体过程如下
3.TCP 和 三次握手
- TCP是一个端到端的可靠的面相连接的协议,HTTP基于传输层TCP协议不用担心数据传输的各种问题(当发生错误时,会重传)
- 图解
4. 请求类型和状态码
**状态码:**状态码用于表示服务器对请求的处理结果
1xx:指示信息——表示请求已经接受,继续处理
2xx:成功——表示请求已经被成功接收、理解、接受。
3xx:重定向——要完成请求必须进行更进一步的操作
4xx:客户端错误——请求有语法错误或请求无法实现
5xx:服务器端错误——服务器未能实现合法的请求。
列举几种常见的:
200(OK 没有问题)
302(Found 要你去找别人)
304(Not Modified 要你去拿缓存)
307( Temporary Redirect 要你去拿缓存)
403(Forbidden 有这个资源,但是没有访问权限)
404(Not Found 服务器没有这个资源)
500(Internal Server Error 服务器这边有问题)
5. 渲染页面
- reflow(重排) + repain(重绘)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oSt8PVhc-1608472784017)(images/渲染过程.png)]
http缓存控制
##1. 术语分析
Web 缓存大致可以分为:数据库缓存、服务器端缓存(代理服务器缓存、CDN 缓存)、浏览器缓存。
浏览器缓存也包含很多内容: HTTP 缓存、indexDB、cookie、localstorage 等等。这里我们只讨论 HTTP 缓存相关内容。
在具体了解 HTTP 缓存之前先来明确几个术语:
- 缓存命中率:从缓存中得到数据的请求数与所有请求数的比率。理想状态是越高越好。
- 过期内容:超过设置的有效时间,被标记为“陈旧”的内容。通常过期内容不能用于回复客户端的请求,必须重新向源服务器请求新的内容或者验证缓存的内容是否仍然准备。
- 验证:验证缓存中的过期内容是否仍然有效,验证通过的话刷新过期时间。
- 失效:失效就是把内容从缓存中移除。当内容发生改变时就必须移除失效的内容。
2. 浏览器缓存分类+流程
浏览器缓存分为强缓存和协商缓存,浏览器加载一个页面的简单流程如下:
- 浏览器先根据这个资源的http头信息来判断是否命中强缓存。如果命中则直接加在缓存中的资源,并不会将请求发送到服务器。(强缓存)
- 如果未命中强缓存,则浏览器会将资源加载请求发送到服务器。服务器来判断浏览器本地缓存是否失效。若可以使用,则服务器并不会返回资源信息,浏览器继续从缓存加载资源。(协商缓存)
- 如果未命中协商缓存,则服务器会将完整的资源返回给浏览器,浏览器加载新资源,并更新缓存。(新的请求)
3. 看图
4. 强缓存
命中强缓存时,浏览器并不会将请求发送给服务器。在Chrome的开发者工具中看到http的返回码是200,但是在Size列会显示为(cache)。www.jd.com
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AWSUxkg6-1608472784018)(images/缓存01.png)]
4.1 Expries
- 缓存过期时间, 用来指定资源到期的时间, 在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。
- 比如
Expires: Fir,25 Nov 2050 02:00:13 GMT
这个时间代表着这个资源的失效时间,也就是说在2050年11月25日02:00:13
都是有效的,即命中缓存。 - 查看 www.jd.com
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pgeoq7Iu-1608472784018)(images/缓存-expries.png)]
这种方式有一个明显的缺点,由于失效时间是一个
绝对时间
,所以当客户端本地时间
被修改以后,服务器与客户端时间偏差变大以后,就会导致缓存混乱。于是发展出了Cache-Control
location / {
# 判断 .jpg
if ($request_filename ~* ^.*?\.(gif|jpg|jpeg|png|bmp|swf)$){
# add_header Cache-Control no-cache;
# add_header Cache-Control max-age=6000;
expires 30d; # 30天
expires 30s; # 30秒
}
index index.html index.htm;
}
- 命令 : 重启 cmd => nginx.exe -s reload => ctrl+F5 重启 (OK 没有走缓存) => 下次刷新(from memory cache)
- 查看图片演示
4.2 Cache-Control
- Cache-Control是一个
相对时间
,例如Cache-Control:3600
,代表着资源的有效期是3600秒
。 - 由于是相对时间,并且都是与客户端时间比较,所以服务器与客户端时间偏差也不会导致问题。
- Cache-Control与Expires可以在服务端配置同时启用或者启用任意一个,同时启用的时候
Cache-Control优先级高
。
location / {
if ($request_filename ~* ^.*?\.(gif|jpg|jpeg|png|bmp|swf)$){
# add_header Cache-Control no-cache;
add_header Cache-Control max-age=30;
expires 30s;
}
}
- 查看图片演示
5. 协商缓存
若未命中强缓存,则浏览器会将请求发送至服务器。服务器根据http头信息中的 Last-Modified/If-Modify-Since
或Etag/If-None-Match
来判断是否命中协商缓存。如果命中,则http返回码为304,浏览器从缓存中加载资源。
协商缓存, 协商什么?
浏览器问服务器我缓存的文件你有么有更新啊?
- 没有更新, 浏览器可以用缓存 304
- 文件更新, 浏览器不用缓存, 服务器发新的给浏览器
5.1 Last-Modified/If-Modify-Since
浏览器第一次请求一个资源的时候,服务器返回的header中会加上Last-Modified,Last-modified是一个时间标识该资源的最后修改时间,例如Last-Modified: Thu,31 Dec 2037 23:59:59 GMT
。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Agp8X3uD-1608472784019)(images/协商缓存01.png)]
当浏览器再次请求该资源时,发送的请求头中会包含If-Modified-Since
,该值为缓存之前返回的Last-Modified
。服务器收到 If-Modified-Since
后,根据资源的最后修改时间判断是否命中缓存。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yJDvhYjF-1608472784020)(images/协商缓存02.png)]
如果命中缓存,则返回http304,并且不会返回资源内容,
由于对比的服务端时间,所以客户端与服务端时间差距不会导致问题。但是有时候通过最后修改时间来判断资源是否修改还是不太准确, 于是出现了 ETag/If-None-Match
。
- 没有给 index.html 添加强缓存 => 协商缓存
- locahost => index.html => 演示
- 不用强制刷新 => 刷新即可
- 刷新一下 => 304 => 协商缓存
- 修改index.html内容 => 重启 => 刷新一下 => 200 => 获取新内容 => Last-Modified/If-Modify-Since 值不一致
###5.2 ETag/If-None-Match
与Last-Modified/If-Modified-Since
不同的是,Etag/If-None-Match
返回的是一个校验码
(ETag: entity tag)。ETag可以保证每一个资源是唯一的,资源变化都会导致ETag变化。ETag值的变更则说明资源状态已经被修改。服务器根据浏览器上发送的 If-None-Match
值来判断是否命中缓存。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tqs7od0n-1608472784021)(images/协商缓存03.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-503JYq2D-1608472784021)(images/协商缓存04.png)]
ETag扩展说明
我们对ETag寄予厚望,希望它对于每一个url生成唯一的值,资源变化时ETag也发生变化。神秘的Etag是如何生成的呢?以Apache为例,ETag生成靠以下几种因子
- 文件的i-node编号,此i-node非彼iNode。是Linux/Unix用来识别文件的编号。是的,识别文件用的不是文件名。使用命令’ls –I’可以看到。
- 文件最后修改时间
- 文件大小
生成Etag的时候,可以使用其中一种或几种因子,使用抗碰撞散列函数来生成。所以,理论上ETag也是会重复的,只是概率小到可以忽略。
浏览器内多个标签页之间的通讯
浏览器存储
1.调用 localStorage
- 在一个标签页里面使用
localStorage.setItem(key,value)
添加(修改、删除)内容; - 在另一个标签页里面监听
storage
事件。 即可得到 localstorge 存储的值,实现不同标签页之间的通信。
1.1 传数据
<!-- 结构 -->
<input id="name" autocomplete="off" />
<input type="button" id="btn" value="提交" />
<!-- js -->
<script type="text/javascript">
var btnEle = document.getElementById('btn')
var nameEle = document.getElementById('name')
btnEle.onclick = function () {
var name = nameEle.value
// localStorage.setItem("键", 值);
localStorage.setItem('name', name)
}
</script>
1.2 接数据
<!-- js -->
<script type="text/javascript">
window.onload = function () {
window.addEventListener('storage', function (event) {
console.log(event.key + '=' + event.newValue)
})
}
</script>
2.调用 cookie + setInterval()
-
将要传递的信息存储在cookie中,每隔一定时间读取cookie信息,即可随时获取要传递的信息。
-
在A页面将需要传递的消息存储在cookie当中
-
在B页面设置setInterval,以一定的时间间隔去读取cookie的值。
2.1 传数据
<input id="name" autocomplete="off" />
<input type="button" id="btn" value="提交" />
<script type="text/javascript">
window.onload = function () {
var btnEle = document.getElementById('btn')
var nameEle = document.getElementById('name')
btnEle.onclick = function () {
var name = nameEle.value
document.cookie = 'name=' + name
}
}
</script>
2.2 接数据
<script type="text/javascript">
window.onload = function () {
function getCookie(key) {
// console.log(document.cookie.replace(/;\s+/gim, "\",\"").replace(/=/gim, "\":\""));
if (document.cookie) {
return JSON.parse(
'{"' + document.cookie.replace(/;\s+/gim, '","').replace(/=/gim, '":"') + '"}'
)[key]
} else {
return ''
}
}
setInterval(function () {
console.log('name=' + getCookie('name'))
}, 2000)
}
</script>
2.3 cookie 要在服务器里才有效果
live-server 开启即可
监听服务器事件
##3. html5 浏览器的新特性SharedWorker
- js 是单线程, html5出来一个很多新技术, worker 新技术, 实现了js多线程
- worker 是单页面实现多线程的 share worker 可以实现多页面多线程
普通的webworker直接使用new Worker()即可创建,这种webworker是当前页面专有的。然后还有种共享worker(SharedWorker),这种是可以多个标签页、iframe共同使用的。SharedWorker可以被多个window共同使用,但必须保证这些标签页都是同源的(相同的协议,主机和端口号)
3.1 首先新建一个js文件worker.js
,具体代码如下:
// sharedWorker所要用到的js文件,不必打包到项目中,直接放到服务器即可
let data = '';
let onconnect = function (e) {
let port = e.ports[0];
port.onmessage = function (e) {
if (e.data === 'get') {
port.postMessage(data)
} else {
data = e.data
}
}
}
3.2 webworker端
的代码就如上,只需注册一个onmessage监听信息的事件,客户端
(即使用sharedWorker的标签页)发送message时就会触发。
-
注意webworker无法在本地使用,出于浏览器本身的安全机制,
示例也是放在服务器上的,worker.js和index.html在同一目录。
-
客户端
发送数据
和接收数据
要分成两步来处理
。示例中会有两个按钮,分别对应的向sharedWorker发送数据的请求以及获取数据的请求,但他们本质上都是相同的事件–发送消息。 -
webworker端会进行判断,传递的数据为’get’时,就把变量data的值回传给客户端,其他情况,则把客户端传递过来的数据存储到data变量中。下面是客户端的
// 创建 worker
var worker = new SharedWorker('worker.js')
// 点击 发数据 按钮 => 发数据
setBtn.addEventListener('click', function (e) {
worker.port.postMessage(txt.value);
}, false);
// 点击 取数据 按钮 => 取数据
getBtn.addEventListener('click', function (e) {
worker.port.postMessage('get');
}, false);