IP: 互联网的数据是经过数据包传递的,若是要将主机A的数据传递到主机B,就须要知道主机B的IP地址,才能正确寻址;额外的,数据包上还会添加上A的IP地址,这样B才知道怎么回复A;可是,B拿到数据包以后,并不知道要交给哪一个程序进行处理,就须要UDP(用户数据包协议)和TCP协议的帮助;
TCP(传输控制协议):上层把数据包传递给传输层 --> 传输层给数据包加上UDP头交给网络层 --> 网络层把IP头附加在数据包上,交给底层 --> 数据包被传输给了B的网络层,这时候主机B把IP头拆开,把数据包交给传输层 --> 传输层把UDP头拆开,根据端口号交给相应的应用程序进行处理;
TCP的三次握手:主要是为了确认通讯能力,也就是双方都有发信和收信的能力,若是不确认的话任何数据传送都是不稳定的~因此须要三次握手:
客户端A向服务端B发送报文(B已确认了A的发信能力和B的收信能力) --> 服务端收到报文后,向客户端发送报文(A已确认了双方的收发能力) --> A返回ACK并创建链接(B确认了A的收信能力和B的发信能力)。TCP链接创建后,浏览器就能够利用HTTP/HTTPS协议向服务器发送请求了。
TCP的四次挥手:因为TCP协议有半关闭的状态(就是只能够接收信息不能够发生信息),关闭能够由客户端或者服务端提出:
二者在established状态,客户端A向服务端B提出关闭请求 --> B收到以后,给A发送收到信息的响应,同时通知应用程序关闭相关资源 --> B准备好了以后,给A发送关闭通知消息 --> A回复B,断开链接。javascript
主要就是在浏览器本地把对应的 IP 和域名关联起来,这样在进行DNS解析的时候就很快。html
存在内存里的缓存。不会请求服务器。从优先级上来讲,它是浏览器最早尝试去命中的一种缓存。从效率上来讲,它是响应速度最快的一种缓存。主要用来缓存图片、字体、通常脚本等;和渲染进程“生死相依”,tab关掉就没有了;前端
cache-control: max-age=31536000
比较合适。cache-control比expires优先度更高;这种状况下网络请求对应的状态码是 304。
协商缓存的实现,从Last-Modified
到Etag
。Last-Modified 是一个时间戳,第一次请求的时候,服务器会返回Last-Modified
,随后咱们每次请求时,会带上一个叫 If-Modified-Since
的时间戳字段, 服务器会进行比较;可是存在last-modified
不许确的现象(好比咱们编辑了文件可是内容没有发生改变,服务器只认修改的时间,所以会去修改last-modified
的值,这样的话就么有正确使用协商缓存~),所以有了Etag
,Etag
是由服务器为每一个资源生成的惟一的标识字符串。vue
Service Worker 是一种独立于主线程以外的 Javascript 线程。它脱离于浏览器窗体,所以没法直接访问 DOM。这样独立的个性使得 Service Worker 的“我的行为”没法干扰页面的性能,这个“幕后工做者”能够帮咱们实现离线缓存、消息推送和网络代理等功能。咱们借助 Service worker 实现的离线缓存就称为 Service Worker Cache。java
Service Worker
GoogleChrome关于service worker的sample.jsgit
service worker是基于web worker发展而来的(web worker主要是由于js是单线程的,用ww能够开辟一个新的线程,是脱离在主线程以外的,咱们能够将复杂耗费时间的事情交给web worker来作)。sw是在ww的基础上增长了离线缓存的能力。github
sw是由事件驱动的,具备生命周期,能够拦截处理页面的全部网络请求(fetch),能够访问cache和indexDB,支持推送,而且可让开发者本身控制管理缓存的内容以及版本,为离线弱网环境下的 web 的运行提供了可能,让 web 在体验上更加贴近 native。换句话说他能够把你应用里的全部静态动态资源根据不一样策略缓存起来,在你下次打开时再也不须要去服务器请求,这样一来就减小了网络耗时,使得web应用能够秒开,而且在离线环境下也变得可用。作到这一切你只须要增长一个sw文件,不会对原有的代码产生任何侵入。web
// 页面注册service worker if ('serviceWorker' in navigator) { window.addEventListener('load', function() { navigator.serviceWorker.register('/sw.js'); }); }
service worker的生命周期:
最常绑定的事件:面试
js遵循同源策略,即同协议,同域名,同端口号,不然都算跨域。
下图帮助理解:
能够进行跨域的主要有iframe / JSONP / CORS算法
<iframe src="demo.html" height="300" width="500" name="demo" scrolling="auto" sandbox="allow-same-origin"></iframe>
window.top
来防止咱们页面被嵌套。if(window != window.top){ window.top.location.href = myURL; }
什么是宏任务和微任务?
异步队列有宏任务和微任务之分。
宏任务
微任务
从新布局叫回流,就是改变布局,每次的回流都会触发重绘(repaint), 又要去消耗gpu; 但并非每次repaint都会触发reflow,好比改个背景色啥的,就不须要从新布局;
onLoad: 在页面全部文件加载完成后执行;DomContentLoaded: DOM加载后执行,没必要等待样式脚本和图片下载;
WebSocket 协议实现了浏览器与服务器全双工通讯,能更好的节省服务器资源和带宽并达到实时通信的目的。它与HTTP同样经过已创建的TCP链接来传输数据,可是它和HTTP最大不一样是:
WebSocket 链接必须由浏览器发起,请求协议是一个标准的HTTP请求(也就是说,WebSocket的创建是依赖HTTP的)。请求报文格式以下:GET ws://localhost:3000/ws/chat HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Origin: http://localhost:3000
Sec-WebSocket-Key: client-random-string // 用于标识这个链接
Sec-WebSocket-Version: 13 //指定了websocket的协议版本
建立web socket, 指定open、message等事件的回调便可(和web worker和service worker还挺像);
WebSocket 构造函数const ws = new WebSocket('ws://localhost:8080/ws')
webSocket.readyState
CONNECTING: 值为0
,表示正在链接。
OPEN: 值为1
,表示链接成功,能够通讯了。
CLOSING: 值为2
,表示链接正在关闭。
CLOSED: 值为3
,表示链接已经关闭,或者打开链接失败。
webSocket.onopen : 指定链接成功以后的回调函数:
ws.onopen = function() { console.log('hello websocket') }
webSocket.onclose: 指定链接关闭以后的回调函数
webSocket.onmessage: 指定收到服务器数据后的回调函数
webSocket.onmessage = function (event) { // 数据多是文本或者二进制数据 if (typeof event.data === 'string') { //... } else if (event.data.instanceof ArrayBuffer) { //... } console.log(event.data) }
webSocket.send: : 实例对象的send()方法用于向服务器发送数据webSocket.send(message)
来自 微信小程序和PWA对比分析
二者和native app最大的区别都是“无需安装、用完即走”。
咱们全部的App都是界面和数据的交互,因此须要类来进行界面的绘制,因而出现了View,须要类来管理数据因而出现了Model。咱们设计的View应该能显示任意的内容好比页面中显示的文字应该是任意的而不仅是某个特定Model的内容,因此咱们不该该在View的实现中去写和Model相关的任何代码,若是这样作了,那么View的可扩展性就至关低了。而Model只是负责处理数据的,它根本不知道数据到时候会拿去干啥,可能拿去做为算法噼里啪啦去了,可能拿去显示给用户了,它既然没法接收用户的交互,它就不该该去管和视图相关的任何信息,因此Model中不该该写任何View相关代码。然而咱们的数据和界面应该同步,也就是必定要有个地方要把Model的数据赋值给View,而Model内部和View的内部都不可能去写这样的代码,因此只能新创造一个类出来了,取名为Controller。
这张图把MVC分为三个独立的区域,而且中间用了一些线来隔开。颇有意思的设计,由于这些线彷佛出如今了驾校科目一的内容中,你瞧C和V以及C和M之间的白线,一部分是虚线一部分是实线对吧,这就代表了引用关系:C能够直接引用V和M,而V和M不能直接引用C,至少你不能显式的在V和M的代码中去写和C相关的任何代码,而V和M之间则是双黄线,没错,它们俩谁也不能引用谁,你既不能在M里面写V,也不能在V里面写M。哦,上面的描述有点小小的问题,你不是“不能”这样写,而是“不该该”这样写,没人能阻止你在写代码的时候在一个M里面去写V,可是一旦你这样作了,那么你就违背了MVC的规范,你就不是在使用MVC了,因此这算是MVC的一个必要条件:使用MVC –> M里面没有V的代码。因此M里面没有V的代码就是使用MVC的必要条件。
MVVM的诞生:
就像咱们以前分析MVC是如何合理分配工做的同样,咱们须要数据因此有了M,咱们须要界面因此有了V,而咱们须要找一个地方把M赋值给V来显示,因此有了C,然而咱们忽略了一个很重要的操做:数据解析。在MVC出生的年代,手机APP的数据每每都比较简单,没有如今那么复杂,因此那时的数据解析极可能一步就解决了,因此既然有这样一个问题要处理,而面向对象的思想就是用类和对象来解决问题,显然V和M早就被定义死了,它们都不该该处理“解析数据”的问题,理所应当的,“解析数据”这个问题就交给C来完成了。而如今的手机App功能愈来愈复杂,数据结构也愈来愈复杂,因此数据解析也就没那么简单了。若是咱们继续按照MVC的设计思路,将数据解析的部分放到了Controller里面,那么Controller就将变得至关臃肿。还有至关重要的一点:Controller被设计出来并非处理数据解析的。一、管理本身的生命周期;二、处理Controller之间的跳转;三、实现Controller容器。这里面根本没有“数据解析”这一项,因此显然,数据解析也不该该由Controller来完成。那么咱们的MVC中,M、V、C都不该该处理数据解析,那么由谁来呢?这个问题实际上在面向对象的时候至关好回答:既然目前没有类可以处理这个问题,那么就建立一个新的类出来解决不就行了?因此咱们聪明的开发者们就专门为数据解析建立出了一个新的类: ViewModel。这就是MVVM的诞生。