https://www.shangmayuan.com/a/b95e6dd581ad4339a56d17bd.html
HTTP2
- HTTP Header的压缩,采用的是HPack算法。
- HTTP/2的Server Push,非常重要的一个特性。
请求的pipeline。
- 修复在HTTP 1.x的队头阻塞问题。
- 在单个TCP连接里多工复用请求。
- HTTP/1.x 有连接无法复用、队头阻塞、协议开销大和安全因素等多个缺陷。
- HTTP/2 通过多路复用、二进制流、Header 压缩等等技术,极大地提高了性能,http2会慢慢取代HTTP/1.x 而被广泛采用。
**
http/2最大的特点是使用多路复用,对同一个域的服务器只建立一次TCP连接,加载多个资源,使用二进制帧传输,同时会对http头部进行压缩。使用http2会比http/1.1更加地高效,因此笔者对博客网站尝试进行了升级。
HTTP/1.1的缺陷
1.高延迟—带来页面加载速度的降低
虽然近几年来网络带宽增长非常快,然而我们却并没有看到网络延迟有对应程度的降低。网络延迟问题主要由于队头阻塞(Head-Of-Line Blocking),导致带宽无法被充分利用。
队头阻塞是指当顺序发送的请求序列中的一个请求因为某种原因被阻塞时,在后面排队的所有请求也一并被阻塞,会导致客户端迟迟收不到数据。针对队头阻塞,人们尝试过以下办法来解决:
- 雪碧图
- 内联
- webpack 拼接 JS
2. 无状态特性—带来的巨大HTTP头部
Header里携带的内容过大,在一定程度上增加了传输的成本。更要命的是,成千上万的请求响应报文里有很多字段值都是重复的,非常浪费。
3.明文传输—带来的不安全性
4.不支持服务器推送消息
HTTP/2 新特性
HTTP/2传输数据量的大幅减少,主要有两个原因:以二进制方式传输和Header 压缩。我们先来介绍二进制传输,HTTP/2 采用二进制格式传输数据,而非HTTP/1.x 里纯文本形式的报文 ,二进制协议解析起来更高效。 HTTP/2 将请求和响应数据分割为更小的帧,并且它们采用二进制编码。
它把TCP协议的部分特性挪到了应用层,把原来的”Header+Body”的消息”打散”为数个小片的二进制”帧”(Frame),用”HEADERS”帧存放头数据、”DATA”帧存放实体数据。HTP/2数据分帧后”Header+Body”的报文结构就完全消失了,协议看到的只是一个个的”碎片”。
HTTP/2 中,同域名下所有通信都在单个连接上完成,该连接可以承载任意数量的双向数据流。每个数据流都以消息的形式发送,而消息又由一个或多个帧组成。多个帧之间可以乱序发送,根据帧首部的流标识可以重新组装。
HTTP/2并没有使用传统的压缩算法,而是开发了专门的”HPACK”算法,在客户端和服务器两端建立“字典”,用索引号表示重复的字符串,还采用哈夫曼编码来压缩整数和字符串,可以达到50%~90%的高压缩率。
具体来说:
- 在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键-值对,对于相同的数据,不再通过每次请求和响应发送;
- 首部表在HTTP/2的连接存续期内始终存在,由客户端和服务器共同渐进地更新;
- 每个新的首部键-值对要么被追加到当前表的末尾,要么替换表中之前的值。
例如下图中的两个请求, 请求一发送了所有的头部字段,第二个请求则只需要发送差异数据,这样可以减少冗余数据,降低开销。

3.多路复用
在 HTTP/2 中引入了多路复用的技术。多路复用很好的解决了浏览器限制同一个域名下的请求数量的问题,同时也接更容易实现全速传输,毕竟新开一个 TCP 连接都需要慢慢提升传输速度。
4.Server Push
HTTP2还在一定程度上改变了传统的“请求-应答”工作模式,服务器不再是完全被动地响应请求,也可以新建“流”主动向客户端发送消息。比如,在浏览器刚请求HTML的时候就提前把可能会用到的JS、CSS文件发给客户端,减少等待的延迟,这被称为”服务器推送”( Server Push,也叫 Cache push)。
下图是PUSH模式,当请求一个HTML时,如果HTML里有CSS文件,server会一并推给client,而不像在HTTP 1.1下,还需要再发一个CSS的请求。

怎样把网站升级到http/2
要求nginx的最低版本是1.10.0,openssl的最低版本是1.0.2
然后添加nginx配置,原本https的listen为:
listen 443 ssl;
现在在后面加上http2:
listen 443 ssl http2;
然后把nginx关了再开一下(因为新安装了一个nginx,要先关一下再开),这个时候再用浏览器访问,原本的http1.1 就变为 HTTP/2
1. 实现 CSS 布局
一个div垂直居中
其距离屏幕左右两边各10px
其高度始终是宽度的50%
div中有文本'A'
其font—size:20px
文本水平垂直居中
.div-container{
width: 100%;
display: flex;
align-item: center; // 垂直居中
padding: 0 10px; // 其距离屏幕左右两边各10px
}
.div{
padding-top: 25%;
padding-bottom: 25%;
font—size: 20px;
text-align: center; // 文本水平垂直居中
}
2. 函数中的arguments是数组吗?类数组转数组的方法了解一下?
arguments 是一个对应于传递给函数的参数的类数组对象。
arguments对象不是一个 Array 。它类似于Array,但除了 length 属性和索引元素之外没有任何Array属性。例如,它没有 pop 方法。但是它可以被转换为一个真正的Array:
类数组有什么:length,索引
数组有什么:pop
var args = Array.prototype.slice.call(arguments);
var args = [].slice.call(arguments);
Array.prototype.forEach.call(arguments)
// ES2015
const args = Array.from(arguments);
const args = [...arguments];
3. 类型比较
if([]==false){console.log(1)}; // true
if({}==false){console.log(2)}; // false
if([]){console.log(3)} // true
if([1]==[1]){console.log(4)} // false 数组的存储的是引用,都不相等

typeof null === 'object在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于null代表的是空指针(大多数平台下值为 0x00),因此,null 的类型标签是 0,typeof null也因此返回"object"。js中对象到字符串的转换经过了如下步骤:
- 如果对象具有toString()方法,则调用这个方法。如果它返回一个基本类型值,js将这个值转换为字符串,并返回这个字符串。
- 如果对象没有toString()方法,或者这个方法返回的不是一个基本类型值,那么js将调用valueOf()方法。如果存在这个方法,则调用,如果返回值是基本类型值,转换为字符串并返回
- 否则,js无法从toString()或valueOf()获得一个基本类型值,此时将会抛出类型错误异常
undefined、null、false、+0、-0、NaN、""只有这些toBoolean()是false,其余都为true
== 主要分为 x 和 y 类型相同和类型不同的情况,类型相同时没有类型转换,类型不同时
- x, y 为 null、undefined 两者中一个 // 返回true
- x、y为 Number 和 String 类型时,则转换为 Number 类型比较。
- 有 Boolean 类型时,Boolean 转化为 Number 类型比较。
- 一个 Object 类型,一个 String 或 Number 类型,将 Object 类型进行原始转换(
ToPrimitive)后,按上面流程进行原始值比较。
链接:https://juejin.im/post/6844904095774425101
4. eventloop
async function a1 () {
console.log('a1 start')
await a2()
console.log('a1 end')
}
async function a2 () {
console.log('a2')
}
console.log('script start')
setTimeout(() => {
console.log('setTimeout')
}, 0)
Promise.resolve().then(() => {
console.log('promise1')
})
a1()
let promise2 = new Promise((resolve) => {
resolve('promise2.then')
console.log('promise2')
})
promise2.then((res) => {
console.log(res)
Promise.resolve().then(() => {
console.log('promise3')
})
})
console.log('script end')
//
script start
a1 start
a2
promise2
script end
promise1
a1 end
promise2.then
promise3
setTimeout
https://zhuanlan.zhihu.com/p/55511602
Event Loop 是一个很重要的概念,指的是计算机系统的一种运行机制。
以JavaScript语言为例,它是一种单线程语言,所有任务都在一个线程上完成。因为多线程需要共享资源、且有可能修改彼此的运行结果,对于一种网页脚本语言来说,这就太复杂了。后来就约定俗成,JavaScript为一种单线程语言。(Worker API可以实现多线程,但是JavaScript本身始终是单线程的。)
- JS调用栈(栈,后进先出)
- 当函数执行的时候,会被添加到栈的顶部,当执行栈执行完成后,就会从栈顶移出,直到栈内被清空。
- 任务队列
Task Queue,即队列,是一种先进先出的一种数据结构。 - 宏任务
- setTimeout
- setInterval
- resquestAnimationFrame
微任务
- promise
- nextTick
- Object.observe
执行栈在执行完同步任务后,查看执行栈是否为空,如果执行栈为空,就会去执行
Task(宏任务),每次宏任务执行完毕后,检查微任务(microTask)队列是否为空,如果不为空的话,会按照先入先出的规则全部执行完微任务(microTask)后,设置微任务(microTask)队列为null,然后再执行宏任务,如此循环。

5. 改正代码,输出0123401234
function a () {
for (var i = 0; i < 5; i++) {
this.i = i
setTimeout(function () {
console.log(i)
}, 0)
console.log(this.i)
}
}
a()
闭包
一个函数嵌套在另一个函数的内部,那么这个函数就可以获取到外部作用域中的变量。然后将这个函数进行返回,在外部函数执行过之后,其内部的变量因为有此函数的引用,所以不会被垃圾回收。在执行该函数的时候,就可以访问到外部函数的内部变量,实现访问“私有变量”的效果。
定时器、事件监听、ajax 请求、跨窗口通信、web workers 或者任何其他的异步或者同步任务中,只要使用了回调函数,实际上就是在使用闭包。
题目是 var 是一个全局的 i,定时器里面所有的 i 都共享一个 i 的引用,循环的终止条件时 i = 6,所以循环终止时 i 的最终值是 6,定时器的回调是在循环结束之后调用(eventloop),所以在执行回调的时候 i 是 6 => 创建新的函数作用域。
- 立即执行函数:通过声明并立即执行一个函数来创建新的作用域
function a() { for (var i = 0; i < 5; i++) { (function(j){ setTimeout(function () { console.log(j) }, 0) })(i) this.i = i console.log(this.i) } } a()
let 创建新的块级作用域:将一个块转换成一个可以被关闭的作用域
闭包(setTimeout 的 function 要获取到 外层函数的变量)
function c () {
for (var i = 0; i < 5; i++) {
this.i = i
const _i = i
setTimeout(function () {
console.log(_i)
}, 0)
console.log(this.i)
}
}
c()
6. 手写 bind
Function.prototype.bind2 = function (context) {
if (typeof this !== "function") {
throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
}
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
var fNOP = function () {};
var fbound = function () {
self.apply(this instanceof self ? this : context, args.concat(Array.prototype.slice.call(arguments)));
}
fNOP.prototype = this.prototype;
fbound.prototype = new fNOP();
return fbound;
}
7. 函数的防抖

8. 从一个无序,不相等的数组中,选取N个数,使其和为M实现算法
9. 一个字典[‘I’, ‘have’, ‘a’, ‘book’, ‘good’],实现一个函数,判断一个字符串中是否都是出自字典中的,输出true/false
10. 一个长阶梯有n级,可以一次走1级,一次走2级,一共有多少种走法?
动态规划
dp[n] = dp[ n - 1 ] + dp[ n - 2]
11. 说说http缓存
https://segmentfault.com/a/1190000008956069
Web 缓存大致可以分为:数据库缓存、服务器端缓存(代理服务器缓存、CDN 缓存)、浏览器缓存。
浏览器缓存也包含很多内容: HTTP 缓存、indexDB、cookie、localstorage 等等。这里我们只讨论 HTTP 缓存相关内容。
数据请求分为:网络请求、后端处理、浏览器请求;
浏览器缓存可以帮助我们在第一和第三步骤中优化性能。比如说直接使用缓存而不发起请求,或者发起了请求但后端存储的数据和前端一致,那么就没有必要再将数据回传回来,这样就减少了响应数据。
缓存位置(按照优先级依次查找):
- Service Worker
- Memory Cache
- Disk Cache
- Push Cache
- 网络请求
Service Worker 的缓存与浏览器其他内建的缓存机制不同,它可以让我们自由控制缓存哪些文件、如何匹配缓存、如何读取缓存,并且缓存是持续性的。
他基于h5的web worker,所以绝对不会阻碍当前js线程的执行,sw最重要的工作原理就是
- 后台线程:独立于当前网页线程;
- 网络代理:在网页发起请求时代理,来缓存文件;
Memory Cache 也就是内存中的缓存,读取内存中的数据肯定比磁盘快。但是内存缓存虽然读取高效,可是缓存持续性很短,会随着进程的释放而释放。 一旦我们关闭 Tab 页面,内存中的缓存也就被释放了。
- 对于大文件来说,大概率是不存储在内存中的,反之优先
- 当前系统内存使用率高的话,文件优先存储进硬盘
Disk Cache 也就是存储在硬盘中的缓存,读取速度慢点,但是什么都能存储到磁盘中,比之 Memory Cache 胜在容量和存储时效性上。
强缓存和协商缓存
强缓存**就是强制缓存,强制使用缓存。
强缓存是利用http头中的Expires(代表这这个资源的失效时间)和Cache-Control两个字段来控制的,用来表示资源的缓存时间。强缓存中,普通刷新会忽略它,但不会清除它,需要强制刷新。浏览器强制刷新,请求会带上Cache-Control:no-cache和Pragma:no-cache
协商缓存
协商缓存就是由服务器来确定缓存资源是否可用,所以客户端与服务器端要通过某种标识来进行通信,从而让服务器判断请求资源是否可以缓存访问。
普通刷新会启用弱缓存,忽略强缓存。只有在地址栏或收藏夹输入网址、通过链接引用资源等情况下,浏览器才会启用强缓存,这也是为什么有时候我们更新一张图片、一个js文件,页面内容依然是旧的,但是直接浏览器访问那个图片或文件,看到的内容却是新的。
Last-Modify/If-Modify-Since
浏览器第一次请求一个资源的时候,服务器返回的header中会加上Last-Modify,Last-modify是一个时间标识该资源的最后修改时间,例如Last-Modify: Thu,31 Dec 2037 23:59:59 GMT。
当浏览器再次请求该资源时,request的请求头中会包含If-Modify-Since,该值为缓存之前返回的Last-Modify。服务器收到If-Modify-Since后,根据资源的最后修改时间判断是否命中缓存。
如果命中缓存,则返回304,并且不会返回资源内容,并且不会返回Last-Modify。
浏览器第一次请求资源时,本地无缓存,向web服务器发送请求,服务器起端响应请求,浏览器端缓存。
在第一次请求时,服务器会将页面最后修改时间通过Last-Modified标识由服务器发送给客户端,客户端记录修改时间;服务器还会生成一个Etag,并发送给客户端。

浏览器再次发送请求时
- 浏览器请求某一资源时,会先获取该资源缓存的header信息,然后根据header中的
Cache-Control和Expires来判断是否过期。若没过期则直接从缓存中获取资源信息,包括缓存的header的信息,所以此次请求不会与服务器进行通信。这里判断是否过期,则是强缓存相关。后面会讲Cache-Control和Expires相关。 - 如果显示已过期,浏览器会向服务器端发送请求,这个请求会携带第一次请求返回的有关缓存的header字段信息,比如客户端会通过
If-None-Match头将先前服务器端发送过来的Etag发送给服务器,服务会对比这个客户端发过来的Etag是否与服务器的相同,若相同,就将If-None-Match的值设为false,返回状态304,客户端继续使用本地缓存,不解析服务器端发回来的数据,若不相同就将If-None-Match的值设为true,返回状态为200,客户端重新机械服务器端返回的数据;客户端还会通过If-Modified-Since头将先前服务器端发过来的最后修改时间戳发送给服务器,服务器端通过这个时间戳判断客户端的页面是否是最新的,如果不是最新的,则返回最新的内容,如果是最新的,则返回304,客户端继续使用本地缓存。
12. 用过typescript吗?它的作用是什么?
ts 是 js 的超集,对 JS 代码进行类型检查
增加了代码的可读性和可维护性**
- 类型系统实际上是最好的文档,大部分的函数看看类型的定义就可以知道如何使用了
- 可以在编译阶段就发现大部分错误,这总比在运行时候出错好
- 增强了编辑器和 IDE 的功能,包括代码补全、接口提示、跳转到定义、重构等
类型推论:如果没有明确的指定类型,那么 TypeScript 会依照类型推论(Type Inference)的规则推断出一个类型。如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查:
let myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
// index.ts(2,1): error TS2322: Type 'number' is not assignable to type 'string'.
联合类型(Union Types)表示取值可以为多种类型中的一种。
接口(Interfaces)定义对象的类型,赋值的时候,变量的形状必须和接口的形状保持一致。
interface Person {
name: string;
age: number;
}
let tom: Person = {
name: 'Tom',
age: 25
};
泛型(Generics):**在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
function createArray<T>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
createArray<string>(3, 'x'); // ['x', 'x', 'x']
类型断言(Type Assertion): **可以用来手动指定一个值的类型。(在联合类型中经常使用)
interface Cat {
name: string;
run(): void;
}
interface Fish {
name: string;
swim(): void;
}
function isFish(animal: Cat | Fish) {
if (typeof (animal as Fish).swim === 'function') {
return true;
}
return false;
}
枚举(Enum)类型用于取值被限定在一定范围内的场景,比如一周只能有七天,颜色限定为红绿蓝等
**
13. ts的用法用到了装饰器,你了解过吗?知道如何实现的嘛?
装饰器接收一个参数,也就是我们被装饰的目标方法,处理完扩展的内容后再返回一个方法,供以后调用,同时也失去了对原方法对象的访问。
当我们对某个方法应用了装饰之后,其实就是改变了被装饰方法的入口引用,使其重新指向了装饰器返回的方法的入口点,从而来实现对原函数的扩展、修改等操作
不过装饰器模式仍处于第 2 阶段提案中,使用它之前需要使用 babel 模块 transform-decorators-legacy 编译成 ES5 或 ES6。
装饰器是一种函数,使用 @ + 函数名的方式对类进行处理,可以作用于类方法 也 可以作用与类本身。
装饰器在编译时运行代码,本质就是在编译时运行的函数,在对象运行期间动态的增加某个功能,和继承相比,更加的灵活。
使用的 Object.definePrototy
- react-redux 中的 connect
- withRouter
- loading
- watch
14. PWA使用过吗?serviceWorker的使用原理是啥?
progressive web app(渐进式网络应用) 结合了 web 和 native 的优势
web 的缺点
- 每次访问都需要输入网址
- 不能离线访问
- 不能推送消息
native 的缺点
- 需要安装应用
- 安卓和 ios 需要开发两份,成本高,并且 ios 需要审核。更新成本高
PWA 优点
- 桌面入口,打开方便
- 离线可用,不过度依赖网络
- 安装和开发便捷
- 能够进行消息推送
核心技术:serviceWorker、indexDB
什么是serviceWorker?
serviceWorker 是一个注册在指定域和路径下的事件驱动型 web worker。充当了浏览器和web app 之间的代理服务。可以进行资源在文件级别的缓存,还可以拦截页面请求
- 只能在 https 下使用
- 运行在浏览器后台,不受页面刷新的影响
- 更强大的离线缓存能力
- 拦截请求的能力
- 完全异步,不能使用同步 API
- 持续运行,第一次访问页面后,serviceWorker 就会安装激活并持续运行,直至手动销毁
if('serviceWorker' in navigator){ window.addEventListener('load', function(){ navigator.serviceWorker.register('/sw.js', {scope: '/' }).then(function(registration){ console.log('ServiceWorker registration successful with scope: ' + registration.scope); }, function(err){ console.log('ServiceWorker registration failed: ' + err); }); }); }

- 注册后,Service Worker开始进行安装,安装成功之后,会在worker中触发
install事件;如果安装失败,则进入废弃状态。 - 安装成功之后,Service Worker开始进行激活。激活成功之后,会在worker中触发
activate事件,这个时候,Service Worker就能够控制页面了,我们可以通过Service Worker去进行文件的缓存、请求的监听等操作。如果Service Worker激活失败,则会进入废弃状态。 - 如果Service Worker逻辑文件更新(相关资源文件变动或者内部逻辑更新等),Service Worker会重新安装,如果这个时候,页面依然存在激活状态下的worker(旧的Service Worker),那么新的worker会进入waiting状态进行等待,直到我们主动去操作worker强制其更新,或者等待用户关闭所有页面,这个时候新的worker才会进入到激活状态。
15. 线程与进程,空间分配、资源分配等等
进程就像是火车,线程相当于一节一节的车厢。
空间分配
- 分配你所需要的内存
- 使用分配到的内存
- 不需要时候将其释放
基本数据类型
- 基本数据类型存放在栈中,大小固定,按值
引用类型
- 栈中存放地址指向堆内存中的对象,大小不固定
栈中的内存,操作系统会自动进行内存分配和内存释放。
堆中的内存,由 JS 引擎手动释放(垃圾回收)
V8 的垃圾回收机制
js 中绝大多数的对象存货周期都很短,大部分在经过一次的垃圾回收之后,内存就会被释放掉,少部分对象的存货周期会很长,一直是活跃的对象,不需要被回收。所以为了提高效率,就分为了新生代 和 老生代,采用不同的算法。
- 新生代:存放生存时间短的对象;内存小;时间换空间,复制活动对象
- 老生代:存放生存周期长的对象;内存大;标记之后清除非活动对象
垃圾回收器怎么知道哪些对象是活动对象还是非活动对象?
从初始的根对象的指针开始,递归搜索所有引用到的对象,被引用到的对象标记为活动对象。
新生代中的对象什么时候变成老生代中的对象呢?
一个对象第一次分配内存时会被分配到新生代的 nursery 中,如果进行一次垃圾回收还存在在新生代中,那么移动到 intermediate 中,再经过一次垃圾回收,如果这个对象还在新生代中,就会被移动到老生代中。
**
内存泄漏
- BOM / DOM对象泄漏
- scipt中存在对BOM / DOM对象的引用
- javaScript对象泄漏
- 闭包函数导致的泄漏
-
主要关注的代码点
DOM中的addEventLisner 函数及派生的事件监听, 比如Jquery 中的on 函数, vue 组件实例的 $on 函数,第三方库中的初始化函数
- BOM对象的事件监听,比如webSocket的监听事件
- 避免不必要的函数引用
- 如果是要render函数,避免在html标签中 DOM / BOM事件
在vue中如何处理内存泄漏的
- 如果在mounted/created 钩子中绑定了DOM/BOM 对象中的事件,需要在beforeDestroy 中做对应解绑处理
- 如果在mounted/created 钩子中使用了第三方库初始化,需要在beforeDestroy 中做对应销毁处理
- 如果组件中使用了定时器,需要在beforeDestroy 中做对应销毁处理
- 模板中不要使用表达式来绑定到特定的处理函数,这个逻辑应该放在处理函数中
- 如果在mounted/created 钩子中使用了$on,需要在beforeDestroy 中做对应解绑($off)处理
- 某些组件在模板中使用 事件绑定可能会出现泄漏,使用$on 替换模板中的绑定
最好能有一种方法,在新建引用的时候就声明,哪些引用必须手动清除,哪些引用可以忽略不计,当其他引用消失以后,垃圾回收机制就可以释放内存。这样就能大大减轻程序员的负担,你只要清除主要引用就可以了。
ES6 考虑到了这一点,推出了两种新的数据结构:WeakSet 和 WeakMap。它们对于值的引用都是不计入垃圾回收机制的,所以名字里面才会有一个”Weak”,表示这是弱引用。
16. 三次握手、四次挥手及标志位、time-wait
17. web worker,web storage,怎样验证本地数据的有效性
webWorker: 说到webWorker,我们就得谈一谈程序、进程和线程的概念了,程序是保存在磁盘中的代码,进程是将代码调到内存中执行,并且分配内存空间,而线程就是运行在进程中的代码片段。
之所以讲这三个概念,是因为通常我们浏览网页时,脚本是跟着UI主线程一起运行的,页面的状态是等到脚本运行完才执行的,这就使得有些特殊情况时用户体验是很差的,而webWorker就很好的解决了这个问题,它是独立运行在后台的脚本语言,与主线程区分开,内存会另批一块地给它玩,不会影响页面的加载,当我们在进行用户体验时,它只会在后台默默的运行,是不是挺好的。
和主线程通信使用 postMessage
<input type="text" id="inp"/>
<button id="btn">计算累加和</button>
<div id="div"></div>
<script>
var btn = document.getElementById("btn");
var w2 = new Worker("2.js");
btn.onclick=function(){
var num = parseInt(document.getElementById("inp").value);
//console.log(num);
w2.postMessage(num); //通过postMessage方法将input框里的数值传给webWorker线程
w2.onmessage=function(e){ //通过onmessage 方法接收webWorker线程计算好的值
console.log(e.data)
document.getElementById("div").innerHTML= e.data; //显示在网页上
}
}
</script>
// web worker 部分
onmessage = function(e){ //接收主线程传来的数字计算累加和
var num = e.data;
for(var i=0,sum=0;i<=num;i++){
sum+=i;
}
postMessage(sum); //将处理好的数据发回至主线程
}
接下来我们说说webStorage ,它是一种客户端存储数据技术,可在在浏览器存储用户浏览网页专用数据,例如:访问历史,购物车,样式等。客户端存储数据有四种方式,它们分别是:
(1) cookie 技术: 浏览器兼容性好;数据不能超4KB;操作复杂
(2) Flash存储:依赖于Flash播放器
(3) WebStorage(localStorage\sessionStorage ):不能超过8MB,操作简单
(4) IndexedDB:可存储大量数据,还不是标准技术
18. 缓存相关的http头部属性,强制缓存,协商缓存,优先级,以及meta标签
19. websocket

众所周知,Web应用的通信过程通常是客户端通过浏览器发出一个请求,服务器端接收请求后进行处理并返回结果给客户端,客户端浏览器将信息呈现。这种机制对于信息变化不是特别频繁的应用可以良好支撑,但对于实时要求高、海量并发的应用来说显得捉襟见肘,尤其在当前业界移动互联网蓬勃发展的趋势下,高并发与用户实时响应是Web应用经常面临的问题,比如金融证券的实时信息、Web导航应用中的地理位置获取、社交网络的实时消息推送等。
传统的请求-响应模式的Web开发在处理此类业务场景时,通常采用实时通讯方案。比如常见的轮询方案,其原理简单易懂,就是客户端以一定的时间间隔频繁请求的方式向服务器发送请求,来保持客户端和服务器端的数据同步。其问题也很明显:
传统的Web模式在处理高并发及实时性需求的时候,会遇到难以逾越的瓶颈,需要一种高效节能的双向通信机制来保证数据的实时传输。
**
- 什么是 ws
Websocket是一个持久化的网络通信协议,可以在单个 TCP 连接上进行全双工通讯,没有了Request和Response的概念,两者地位完全平等,连接一旦建立,客户端和服务端之间实时可以进行双向数据传输
虽然http1.1默认开启了keep-alive长连接保持了这个TCP通道使得在一个HTTP连接中,可以发送多个Request,接收多个Response,但是一个request只能有一个response。而且这个response也是被动的,不能主动发起。在一次 TCP 连接中完成多个 HTTP 请求,但是对每个请求仍然要单独发 header
websocket虽然是独立于HTTP的一种协议,但是websocket必须依赖 HTTP 协议进行一次握手(在握手阶段是一样的),握手成功后,数据就直接从 TCP通道传输,与 HTTP 无关了,可以用一张图理解两者有交集,但是并不是全部。
WebSocket可以做弹幕、消息订阅、多玩家游戏、协同编辑、股票基金实时报价、视频会议、在线教育、聊天室等应用实时监听服务端变化
可能会有一些未知情况导致SOCKET断开,而客户端和服务端却不知道,需要客户端定时发送一个心跳 Ping 让服务端知道自己在线,而服务端也要回复一个心跳 Pong告诉客户端自己可用,否则视为断开
优点:
- keep-alive 和 polling 效率很低,每次都要携带 http header,ws 只需要验证一次,不需要每次都发送 http header
- keep-alive 和 polling ,服务端都是被动接收消息,不能主动发送消息
20. setTimeout、setInterval与requestAnimationFrame
setTimeout(code, millseconds)用于延时执行参数指定的代码,setInterval(code, millseconds)用于每隔一段时间执行指定的代码requestAnimationFrame(code),一般用于动画,与setTimeout方法类似,区别是setTimeout是用户指定的,而requestAnimationFrame是浏览器刷新频率决定的,一般遵循 W3C 标准,它在浏览器每次刷新页面之前执行。
21. 回文数,数组去重,自定义log,判断数据类型
22. 缓存命中率的问题,怎样确保缓存全部数据,缓存命中率不是100%应该怎么办
23. 说说性能优化的通用架构方案
24. 数据类型转换的原理
25. 跨域问题遇过吗?什么办法可以解决?讲了一下cors,jsonp,websocket,postmessage,反向*等
26. https和http有什么区别?(TLS套接层协议)
27. 如果登陆的请求是https,而其它的请求是http的会出现什么问题?
因为https地址中,如果加载了http资源,浏览器将认为这是不安全的资源,将会默认阻止,这就会给你带来资源不全的问题了,比如:图片显示不了,样式加载不了,JS加载不了。因为样式类,基本上都是写在本地的,所以一般还可以,但是一些公共的js文件,往往就是存在于cdn或者其他服务器上,这时候,如果访问不了,可能就导致了业务就完全操作不了。比如:jquery效法加载失败,可能所有的操作、请求都将无效了。
推荐方法,不指定具体协议,使用资源协议自适配,比如,当前为https页面,那么就是https资源,如果是http页面,那么就是http资源。具体方法超简单:
28. 实现一个div在页面中垂直水平居中,然后高度是宽度的一半(实现不了也可以固定为200px)div里有文字A垂直水平居中,
29. vw,vh,vmin,vmax的区别?垂直水平居中的其它实现方法?
vw、vh、vmin、vmax是一种视窗单位,是由视窗(Viewport)的大小决定的。
视窗是浏览器实际显示内容的区域包含滚动条,不包括工具栏和按钮的网页浏览器。
视窗单位 与 百分比
- 百分比是相对于父元素的大小设定的比例,视窗单位是由视窗大小决定的
- 视窗单位vh可以直接获取可视区域的高度,而百分比是不可以的
- 100vw包含滚动条,100%不包含滚动条
30. margin合并问题,解决方法?BFC和IFC的区别?
BFC 块级格式化上下文
BFC布局规则
- 内部的Box会在垂直方向,一个接一个的放置
- 同一个BFC内,垂直方向的盒子上下margin会重叠
- 每个元素的margin box的左边,与包含块border box的左边连接(对于从右往左的布局,则相反)即使存在浮动也是如此
- 子BFC的区域不会与float box重叠
- BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之也如此。
- 计算BFC的高度时,浮动元素也参与计算(故也可以达到所谓清除浮动的效果,只要将包裹层转变为BFC)
如何将块级元素转换成BFC
- 具有除了float:none的其他浮动属性
- 定位为absolute或者fixed
- dispaly为block、inline-block、table-cell、table-caption、flex、inline-flex
- overflow不为visible(除非该值已经传播到视口,入html body会将overflow的值传播到视口,故此情况下,该属性不能建立BFC)
31. chrome的字体最小为12px,如何设置10px的字体(使用transform:scale()属性进行缩放)
32. 为什么设置 font-weight 是数字的时候作用会失效?
100~400都是normal,500~700都是bold,建议直接用lighter,normal,bold,bolder来设置font-weight。
33. 浏览器缓存相关的问题?讲了一下协商缓存的机制,简单请求和options预检请求
- Last-Modified
在浏览器第一次请求某一个URL时,服务器端的返回状态会是200,内容是你请求的资源,同时有一个Last-Modified的属性标记(HttpReponse Header)此文件在服务期端最后被修改的时间,格式类似这样:
Last-Modified:Tue, 24 Feb 2009 08:01:04 GMT
客户端第二次请求此URL时,根据HTTP协议的规定,浏览器会向服务器传送If-Modified-Since报头(HttpRequest Header),询问该时间之后文件是否有被修改过:
If-Modified-Since:Tue, 24 Feb 2009 08:01:04 GMT
如果服务器端的资源没有变化,则自动返回HTTP304(NotChanged.)状态码,内容为空,这样就节省了传输数据量。当服务器端代码发生改变或者重启服务器时,则重新发出资源,返回和第一次请求时类似。从而保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。
注:如果If-Modified-Since的时间比服务器当前时间(当前的请求时间request_time)还晚,会认为是个非法请求
- Etag工作原理
HTTP协议规格说明定义ETag为“被请求变量的实体标记”(参见14.19)。简单点即服务器响应时给请求URL标记,并在HTTP响应头中将其传送到客户端,类似服务器端返回的格式:
Etag:“5d8c72a5edda8d6a:3239″
客户端的查询更新格式是这样的:
If-None-Match:“5d8c72a5edda8d6a:3239″
如果ETag没改变,则返回状态304。
即:在客户端发出请求后,HttpReponse Header中包含Etag:“5d8c72a5edda8d6a:3239″
标识,等于告诉Client端,你拿到的这个的资源有表示ID:5d8c72a5edda8d6a:3239。当下次需要发Request索要同一个URI的时候,浏览器同时发出一个If-None-Match报头(Http RequestHeader)此时包头中信息包含上次访问得到的Etag:“5d8c72a5edda8d6a:3239″标识。
If-None-Match:“5d8c72a5edda8d6a:3239“
,这样,Client端等于Cache了两份,服务器端就会比对2者的etag。如果If-None-Match为False,不返回200,返回304(Not Modified) Response。
- Expires
给出的日期/时间后,被响应认为是过时。如Expires:Thu, 02 Apr 2009 05:14:08 GMT
需和Last-Modified结合使用。用于控制请求文件的有效时间,当请求数据在有效期内时客户端浏览器从缓存请求数据而不是服务器端.当缓存中数据失效或过期,才决定从服务器更新数据。
- Last-Modified和Expires
Last-Modified标识能够节省一点带宽,但是还是逃不掉发一个HTTP请求出去,而且要和Expires一起用。而Expires标识却使得浏览器干脆连HTTP请求都不用发,比如当用户F5或者点击Refresh按钮的时候就算对于有Expires的URI,一样也会发一个HTTP请求出去,所以,Last-Modified还是要用的,而且要和Expires一起用。
- Etag和Expires
如果服务器端同时设置了Etag和Expires时,Etag原理同样,即与Last-Modified/Etag对应的HttpRequestHeader:If-Modified-Since和If-None-Match。我们可以看到这两个Header的值和WebServer发出的Last-Modified,Etag值完全一样;在完全匹配If-Modified-Since和If-None-Match即检查完修改时间和Etag之后,服务器才能返回304.
- Last-Modified和Etag
分布式系统里多台机器间文件的last-modified必须保持一致,以免负载均衡到不同机器导致比对失败
分布式系统尽量关闭掉Etag(每台机器生成的etag都会不一样)
Last-Modified和ETags请求的http报头一起使用,服务器首先产生Last-Modified/Etag标记,服务器可在稍后使用它来判断页面是否已经被修改,来决定文件是否继续缓存
过程如下:
- 客户端请求一个页面(A)。
- 服务器返回页面A,并在给A加上一个Last-Modified/ETag。
- 客户端展现该页面,并将页面连同Last-Modified/ETag一起缓存。
- 客户再次请求页面A,并将上次请求时服务器返回的Last-Modified/ETag一起传递给服务器。
- 服务器检查该Last-Modified或ETag,并判断出该页面自上次客户端请求之后还未被修改,直接返回响应304和一个空的响应体。
注:
- Last-Modified和Etag头都是由WebServer发出的HttpReponse Header,WebServer应该同时支持这两种头。
- WebServer发送完Last-Modified/Etag头给客户端后,客户端会缓存这些头;
- 客户端再次发起相同页面的请求时,将分别发送与Last-Modified/Etag对应的HttpRequestHeader:If-Modified-Since和If-None-Match。我们可以看到这两个Header的值和WebServer发出的Last-Modified,Etag值完全一样;
- 通过上述值到服务器端检查,判断文件是否继续缓存;
- 关于 Cache-Control: max-age=秒 和 Expires
Expires = 时间,HTTP 1.0 版本,缓存的载止时间,允许客户端在这个时间之前不去检查(发请求)
max-age = 秒,HTTP 1.1版本,资源在本地缓存多少秒。
如果max-age和Expires同时存在,则被Cache-Control的max-age覆盖。
Expires 的一个缺点就是,返回的到期时间是服务器端的时间,这样存在一个问题,如果客户端的时间与服务器的时间相差很大,那么误差就很大,所以在HTTP 1.1版开始,使用Cache-Control: max-age=秒替代。
Expires =max-age + “每次下载时的当前的request时间”
所以一旦重新下载的页面后,expires就重新计算一次,但last-modified不会变化
34. 实现一个累加函数的功能比如sum(1,2,3)(2).valueOf()//8
35. 封装一个实现继承的函数
36. 什么是堆,什么是栈,在哪里应用
37. 什么是进程,什么是线程
程序是保存在磁盘中的代码,进程是将代码调到内存中执行,并且分配内存空间,而线程就是运行在进程中的代码片段。
38. 一个矩形,水平垂直居中,且宽高比为 2:1
39. webpack打包产物是怎样的,到底是为了什么,优化了什么,为什么要合并文件?
40. vue的diff是为什么,浏览器重绘重排前会diff吗,为什么?
41. 实现一个单行容器内:左边一行文字,右边一个btn,文字边长过程中,不会把btn挤下去,而是文字超出省略
42. 实现一个累加函数,当最后一次调用传入空时,计算所有参数和,类似下面:
const x = sum(1);
x = sum(1,2)(3,4,5)(6)()
var a = {x:1}
var b = a;
a = a.x = {x:1}
console.log(a); // {x:1}
console.log(b); // {x:{x:1}}
43. 如何判断一个对象是不是空对象?
45. 在线编程,getUrlParams(url,key); 就是很简单的获取url的某个参数的问题,但要考虑边界情况,多个返回值等等
46. POST一般可以发送什么类型的文件
47. 链表反序输出,不再申请内存空间
48. Number()的存储空间是多大,如果后台发送了一个超过最大字节的数字怎么办
49. 回流与重绘,如何避免回流
50. 在交互过程中如果数据传送完了,还不想断开连接怎么办,怎么维持
51. websocket与ajax的区别
52. fetch API 与传统 request 的区别
53. 懒加载的节流和防抖,代码实现,并说明原理去区别还有使用场景
54. 写一个继承吧,组合继承,然后说出寄生组合继承相对于组合继承的优点
55. JS 的基本数据类型、获取数据类型的方法、typeof 可以返回多少种值
56. 手写深拷贝
57. css 的单位有哪些
58. 网页渲染的流程
- 用户输入网址(假设是个html页面,并且是第一次访问),浏览器向服务器发出请求,服务器返回html文件。
- 浏览器开始载入html代码,发现标签内有一个标签引用外部CSS文件。
- 浏览器又发出CSS文件的请求,服务器返回这个CSS文件。
- 浏览器继续载入html中部分的代码,并且CSS文件已经拿到手了,可以开始渲染页面了。
- 浏览器在代码中发现一个
标签引用了一张图片,向服务器发出请求。此时浏览器不会等到图片下载完,而是继续渲染后面的代码。
- 服务器返回图片文件,由于图片占用了一定面积,影响了后面段落的排布,因此浏览器需要回过头来重新渲染这部分代码。
- 浏览器发现了一个包含一行Javascript代码的
