共计 12240 个字符,预计需要花费 31 分钟才能阅读完成。
懒加载的特点
- 缩小无用资源的加载:应用懒加载显著缩小了服务器的压力和流量,同时也减小了浏览器的累赘。
- 晋升用户体验: 如果同时加载较多图片,可能须要期待的工夫较长,这样影响了用户体验,而应用懒加载就能大大的进步用户体验。
- 避免加载过多图片而影响其余资源文件的加载:会影响网站利用的失常应用。
—- 问题知识点分割线 —-
节流与防抖
- 函数防抖 是指在事件被触发 n 秒后再执行回调,如果在这 n 秒内事件又被触发,则从新计时。这能够应用在一些点击申请的事件上,防止因为用户的屡次点击向后端发送屡次申请。
- 函数节流 是指规定一个单位工夫,在这个单位工夫内,只能有一次触发事件的回调函数执行,如果在同一个单位工夫内某事件被触发屡次,只有一次能失效。节流能够应用在 scroll 函数的事件监听上,通过事件节流来升高事件调用的频率。
// 函数防抖的实现
function debounce(fn, wait) {
var timer = null;
return function() {
var context = this,
args = arguments;
// 如果此时存在定时器的话,则勾销之前的定时器从新记时
if (timer) {clearTimeout(timer);
timer = null;
}
// 设置定时器,使事件间隔指定事件后执行
timer = setTimeout(() => {fn.apply(context, args);
}, wait);
};
}
// 函数节流的实现;
function throttle(fn, delay) {var preTime = Date.now();
return function() {
var context = this,
args = arguments,
nowTime = Date.now();
// 如果两次工夫距离超过了指定工夫,则执行函数。if (nowTime - preTime >= delay) {preTime = Date.now();
return fn.apply(context, args);
}
};
}
—- 问题知识点分割线 —-
闭包
首先阐明什么是闭包,闭包简略来说就是函数嵌套函数,外部函数援用来内部函数的变量,从而导致垃圾回收
机制没有把以后变量回收掉,这样的操作带来了内存透露的影响,当内存透露到肯定水平会影响你的我的项目运行
变得卡顿等等问题。因而在我的项目中咱们要尽量避免内存透露。
—- 问题知识点分割线 —-
typeof null 的后果是什么,为什么?
typeof null 的后果是 Object。
在 JavaScript 第一个版本中,所有值都存储在 32 位的单元中,每个单元蕴含一个小的 类型标签(1-3 bits) 以及以后要存储值的实在数据。类型标签存储在每个单元的低位中,共有五种数据类型:
000: object - 以后存储的数据指向一个对象。1: int - 以后存储的数据是一个 31 位的有符号整数。010: double - 以后存储的数据指向一个双精度的浮点数。100: string - 以后存储的数据指向一个字符串。110: boolean - 以后存储的数据是布尔值。
如果最低位是 1,则类型标签标记位的长度只有一位;如果最低位是 0,则类型标签标记位的长度占三位,为存储其余四种数据类型提供了额定两个 bit 的长度。
有两种非凡数据类型:
- undefined 的值是 (-2)30(一个超出整数范畴的数字);
- null 的值是机器码 NULL 指针(null 指针的值全是 0)
那也就是说 null 的类型标签也是 000,和 Object 的类型标签一样,所以会被断定为 Object。
—- 问题知识点分割线 —-
GET 办法 URL 长度限度的起因
实际上 HTTP 协定标准并没有对 get 办法申请的 url 长度进行限度,这个限度是特定的浏览器及服务器对它的限度。
IE 对 URL 长度的限度是 2083 字节(2K+35)。因为 IE 浏览器对 URL 长度的允许值是最小的,所以开发过程中,只有 URL 不超过 2083 字节,那么在所有浏览器中工作都不会有问题。
GET 的长度值 = URL(2083)-(你的 Domain+Path)-2(2 是 get 申请中?= 两个字符的长度)
上面看一下支流浏览器对 get 办法中 url 的长度限度范畴:
- Microsoft Internet Explorer (Browser):IE 浏览器对 URL 的最大限度为 2083 个字符,如果超过这个数字,提交按钮没有任何反馈。
- Firefox (Browser):对于 Firefox 浏览器 URL 的长度限度为 65,536 个字符。
- Safari (Browser):URL 最大长度限度为 80,000 个字符。
- Opera (Browser):URL 最大长度限度为 190,000 个字符。
- Google (chrome):URL 最大长度限度为 8182 个字符。
支流的服务器对 get 办法中 url 的长度限度范畴:
- Apache (Server):能承受最大 url 长度为 8192 个字符。
- Microsoft Internet Information Server(IIS):能承受最大 url 的长度为 16384 个字符。
依据下面的数据,能够晓得,get 办法中的 URL 长度最长不超过 2083 个字符,这样所有的浏览器和服务器都可能失常工作。
—- 问题知识点分割线 —-
+
操作符什么时候用于字符串的拼接?
依据 ES5 标准,如果某个操作数是字符串或者可能通过以下步骤转换为字符串的话,+ 将进行拼接操作。如果其中一个操作数是对象(包含数组),则首先对其调用 ToPrimitive 形象操作,该形象操作再调用 [[DefaultValue]],以数字作为上下文。如果不能转换为字符串,则会将其转换为数字类型来进行计算。
简略来说就是,如果 + 的其中一个操作数是字符串(或者通过以上步骤最终失去字符串),则执行字符串拼接,否则执行数字加法。
那么对于除了加法的运算符来说,只有其中一方是数字,那么另一方就会被转为数字。
—- 问题知识点分割线 —-
模块化
js 中当初比拟成熟的有四种模块加载计划:
- 第一种是 CommonJS 计划,它通过 require 来引入模块,通过 module.exports 定义模块的输入接口。这种模块加载计划是服务器端的解决方案,它是以同步的形式来引入模块的,因为在服务端文件都存储在本地磁盘,所以读取十分快,所以以同步的形式加载没有问题。但如果是在浏览器端,因为模块的加载是应用网络申请,因而应用异步加载的形式更加适合。
- 第二种是 AMD 计划,这种计划采纳异步加载的形式来加载模块,模块的加载不影响前面语句的执行,所有依赖这个模块的语句都定义在一个回调函数里,等到加载实现后再执行回调函数。require.js 实现了 AMD 标准
- 第三种是 CMD 计划,这种计划和 AMD 计划都是为了解决异步模块加载的问题,sea.js 实现了 CMD 标准。它和 require.js 的区别在于模块定义时对依赖的解决不同和对依赖模块的执行机会的解决不同。
- 第四种计划是 ES6 提出的计划,应用 import 和 export 的模式来导入导出模块
在有
Babel
的状况下,咱们能够间接应用ES6
的模块化
// file a.js
export function a() {}
export function b() {}
// file b.js
export default function() {}
import {a, b} from './a.js'
import XXX from './b.js'
CommonJS
CommonJs
是Node
独有的标准,浏览器中应用就须要用到Browserify
解析了。
// a.js
module.exports = {a: 1}
// or
exports.a = 1
// b.js
var module = require('./a.js')
module.a // -> log 1
在上述代码中,
module.exports
和exports
很容易混同,让咱们来看看大抵外部实现
var module = require('./a.js')
module.a
// 这里其实就是包装了一层立刻执行函数,这样就不会净化全局变量了,// 重要的是 module 这里,module 是 Node 独有的一个变量
module.exports = {a: 1}
// 根本实现
var module = {exports: {} // exports 就是个空对象
}
// 这个是为什么 exports 和 module.exports 用法类似的起因
var exports = module.exports
var load = function (module) {
// 导出的货色
var a = 1
module.exports = a
return module.exports
};
再来说说
module.exports
和exports
,用法其实是类似的,然而不能对exports
间接赋值,不会有任何成果。对于
CommonJS
和ES6
中的模块化的两者区别是:
- 前者反对动静导入,也就是
require(${path}/xx.js)
,后者目前不反对,然而已有提案, 前者是同步导入,因为用于服务端,文件都在本地,同步导入即便卡住主线程影响也不大。 - 而后者是异步导入,因为用于浏览器,须要下载文件,如果也采纳同步导入会对渲染有很大影响
- 前者在导出时都是值拷贝,就算导出的值变了,导入的值也不会扭转,所以如果想更新值,必须从新导入一次。
- 然而后者采纳实时绑定的形式,导入导出的值都指向同一个内存地址,所以导入值会追随导出值变动
- 后者会编译成
require/exports
来执行的
AMD
AMD
是由RequireJS
提出的
AMD 和 CMD 标准的区别?
- 第一个方面是在模块定义时对依赖的解决不同。AMD 推崇依赖前置,在定义模块的时候就要申明其依赖的模块。而 CMD 推崇就近依赖,只有在用到某个模块的时候再去 require。
- 第二个方面是对依赖模块的执行机会解决不同。首先 AMD 和 CMD 对于模块的加载形式都是异步加载,不过它们的区别在于模块的执行机会,AMD 在依赖模块加载实现后就间接执行依赖模块,依赖模块的执行程序和咱们书写的程序不肯定统一。而 CMD 在依赖模块加载实现后并不执行,只是下载而已,等到所有的依赖模块都加载好后,进入回调函数逻辑,遇到 require 语句的时候才执行对应的模块,这样模块的执行程序就和咱们书写的程序保持一致了。
// CMD
define(function(require, exports, module) {var a = require("./a");
a.doSomething();
// 此处略去 100 行
var b = require("./b"); // 依赖能够就近书写
b.doSomething();
// ...
});
// AMD 默认举荐
define(["./a", "./b"], function(a, b) {
// 依赖必须一开始就写好
a.doSomething();
// 此处略去 100 行
b.doSomething();
// ...
})
- AMD:
requirejs
在推广过程中对模块定义的规范化产出,提前执行,推崇依赖前置 - CMD:
seajs
在推广过程中对模块定义的规范化产出,提早执行,推崇依赖就近 - CommonJs:模块输入的是一个值的
copy
,运行时加载,加载的是一个对象(module.exports
属性),该对象只有在脚本运行完才会生成 - ES6 Module:模块输入的是一个值的援用,编译时输入接口,
ES6
模块不是对象,它对外接口只是一种动态定义,在代码动态解析阶段就会生成。
谈谈对模块化开发的了解
- 我对模块的了解是,一个模块是实现一个特定性能的一组办法。在最开始的时候,js 只实现一些简略的性能,所以并没有模块的概念,但随着程序越来越简单,代码的模块化开发变得越来越重要。
- 因为函数具备独立作用域的特点,最原始的写法是应用函数来作为模块,几个函数作为一个模块,然而这种形式容易造成全局变量的净化,并且模块间没有分割。
- 前面提出了对象写法,通过将函数作为一个对象的办法来实现,这样解决了间接应用函数作为模块的一些毛病,然而这种方法会裸露所有的所有的模块成员,内部代码能够批改外部属性的值。
- 当初最罕用的是立刻执行函数的写法,通过利用闭包来实现模块公有作用域的建设,同时不会对全局作用域造成净化。
—- 问题知识点分割线 —-
什么是作用域链?
首先要理解作用域链,当拜访一个变量时,编译器在执行这段代码时,会首先从以后的作用域中查找是否有这个标识符,如果没有找到,就会去父作用域查找,如果父作用域还没找到持续向上查找,直到全局作用域为止,,而作用域链,就是有以后作用域与下层作用域的一系列变量对象组成,它保障了以后执行的作用域对合乎拜访权限的变量和函数的有序拜访。
—- 问题知识点分割线 —-
let、const、var 的区别
(1)块级作用域: 块作用域由 {}
包含,let 和 const 具备块级作用域,var 不存在块级作用域。块级作用域解决了 ES5 中的两个问题:
- 内层变量可能笼罩外层变量
- 用来计数的循环变量泄露为全局变量
(2)变量晋升: var 存在变量晋升,let 和 const 不存在变量晋升,即在变量只能在申明之后应用,否在会报错。
(3)给全局增加属性: 浏览器的全局对象是 window,Node 的全局对象是 global。var 申明的变量为全局变量,并且会将该变量增加为全局对象的属性,然而 let 和 const 不会。
(4)反复申明: var 申明变量时,能够反复申明变量,后申明的同名变量会笼罩之前申明的遍历。const 和 let 不容许反复申明变量。
(5)暂时性死区: 在应用 let、const 命令申明变量之前,该变量都是不可用的。这在语法上,称为 暂时性死区。应用 var 申明的变量不存在暂时性死区。
(6)初始值设置: 在变量申明时,var 和 let 能够不必设置初始值。而 const 申明变量必须设置初始值。
(7)指针指向: let 和 const 都是 ES6 新增的用于创立变量的语法。let 创立的变量是能够更改指针指向(能够从新赋值)。但 const 申明的变量是不容许扭转指针的指向。
区别 | var | let | const |
---|---|---|---|
是否有块级作用域 | × | ✔️ | ✔️ |
是否存在变量晋升 | ✔️ | × | × |
是否增加全局属性 | ✔️ | × | × |
是否反复申明变量 | ✔️ | × | × |
是否存在暂时性死区 | × | ✔️ | ✔️ |
是否必须设置初始值 | × | × | ✔️ |
是否扭转指针指向 | ✔️ | ✔️ | × |
—- 问题知识点分割线 —-
常见的图片格式及应用场景
(1)BMP,是无损的、既反对索引色也反对间接色的点阵图。这种图片格式简直没有对数据进行压缩,所以 BMP 格局的图片通常是较大的文件。
(2)GIF是无损的、采纳索引色的点阵图。采纳 LZW 压缩算法进行编码。文件小,是 GIF 格局的长处,同时,GIF 格局还具备反对动画以及通明的长处。然而 GIF 格局仅反对 8bit 的索引色,所以 GIF 格局实用于对色调要求不高同时须要文件体积较小的场景。
(3)JPEG是有损的、采纳间接色的点阵图。JPEG 的图片的长处是采纳了间接色,得益于更丰盛的色调,JPEG 非常适合用来存储照片,与 GIF 相比,JPEG 不适宜用来存储企业 Logo、线框类的图。因为有损压缩会导致图片含糊,而间接色的选用,又会导致图片文件较 GIF 更大。
(4)PNG-8是无损的、应用索引色的点阵图。PNG 是一种比拟新的图片格式,PNG- 8 是十分好的 GIF 格局替代者,在可能的状况下,应该尽可能的应用 PNG- 8 而不是 GIF,因为在雷同的图片成果下,PNG- 8 具备更小的文件体积。除此之外,PNG- 8 还反对透明度的调节,而 GIF 并不反对。除非须要动画的反对,否则没有理由应用 GIF 而不是 PNG-8。
(5)PNG-24是无损的、应用间接色的点阵图。PNG-24 的长处在于它压缩了图片的数据,使得同样成果的图片,PNG-24 格局的文件大小要比 BMP 小得多。当然,PNG24 的图片还是要比 JPEG、GIF、PNG- 8 大得多。
(6)SVG是无损的矢量图。SVG 是矢量图意味着 SVG 图片由直线和曲线以及绘制它们的办法组成。当放大 SVG 图片时,看到的还是线和曲线,而不会呈现像素点。SVG 图片在放大时,不会失真,所以它适宜用来绘制 Logo、Icon 等。
(7)WebP是谷歌开发的一种新图片格式,WebP 是同时反对有损和无损压缩的、应用间接色的点阵图。从名字就可以看进去它是为 Web 而生的,什么叫为 Web 而生呢?就是说雷同品质的图片,WebP 具备更小的文件体积。当初网站上充斥了大量的图片,如果可能升高每一个图片的文件大小,那么将大大减少浏览器和服务器之间的数据传输量,进而升高拜访提早,晋升拜访体验。目前只有 Chrome 浏览器和 Opera 浏览器反对 WebP 格局,兼容性不太好。
- 在无损压缩的状况下,雷同品质的 WebP 图片,文件大小要比 PNG 小 26%;
- 在有损压缩的状况下,具备雷同图片精度的 WebP 图片,文件大小要比 JPEG 小 25%~34%;
- WebP 图片格式反对图片透明度,一个无损压缩的 WebP 图片,如果要反对透明度只须要 22% 的分外文件大小。
—- 问题知识点分割线 —-
箭头函数与一般函数的区别
(1)箭头函数比一般函数更加简洁
- 如果没有参数,就间接写一个空括号即可
- 如果只有一个参数,能够省去参数的括号
- 如果有多个参数,用逗号宰割
- 如果函数体的返回值只有一句,能够省略大括号
- 如果函数体不须要返回值,且只有一句话,能够给这个语句后面加一个 void 关键字。最常见的就是调用一个函数:
let fn = () => void doesNotReturn();
(2)箭头函数没有本人的 this
箭头函数不会创立本人的 this,所以它没有本人的 this,它只会在本人作用域的上一层继承 this。所以箭头函数中 this 的指向在它在定义时曾经确定了,之后不会扭转。
(3)箭头函数继承来的 this 指向永远不会扭转
var id = 'GLOBAL';
var obj = {
id: 'OBJ',
a: function(){console.log(this.id);
},
b: () => {console.log(this.id);
}
};
obj.a(); // 'OBJ'
obj.b(); // 'GLOBAL'
new obj.a() // undefined
new obj.b() // Uncaught TypeError: obj.b is not a constructor
对象 obj 的办法 b 是应用箭头函数定义的,这个函数中的 this 就永远指向它定义时所处的全局执行环境中的 this,即使这个函数是作为对象 obj 的办法调用,this 仍旧指向 Window 对象。须要留神,定义对象的大括号 {}
是无奈造成一个独自的执行环境的,它仍旧是处于全局执行环境中。
(4)call()、apply()、bind()等办法不能扭转箭头函数中 this 的指向
var id = 'Global';
let fun1 = () => {console.log(this.id)
};
fun1(); // 'Global'
fun1.call({id: 'Obj'}); // 'Global'
fun1.apply({id: 'Obj'}); // 'Global'
fun1.bind({id: 'Obj'})(); // 'Global'
(5)箭头函数不能作为构造函数应用
构造函数在 new 的步骤在下面曾经说过了,实际上第二步就是将函数中的 this 指向该对象。然而因为箭头函数时没有本人的 this 的,且 this 指向外层的执行环境,且不能扭转指向,所以不能当做构造函数应用。
(6)箭头函数没有本人的 arguments
箭头函数没有本人的 arguments 对象。在箭头函数中拜访 arguments 实际上取得的是它外层函数的 arguments 值。
(7)箭头函数没有 prototype
(8)箭头函数不能用作 Generator 函数,不能应用 yeild 关键字
—- 问题知识点分割线 —-
如何取得对象非原型链上的属性?
应用后 hasOwnProperty()
办法来判断属性是否属于原型链的属性:
function iterate(obj){var res=[];
for(var key in obj){if(obj.hasOwnProperty(key))
res.push(key+':'+obj[key]);
}
return res;
}
—- 问题知识点分割线 —-
代码输入问题
function A(){}
function B(a){this.a = a;}
function C(a){if(a){this.a = a;}
}
A.prototype.a = 1;
B.prototype.a = 1;
C.prototype.a = 1;
console.log(new A().a);
console.log(new B().a);
console.log(new C(2).a);
输入后果:1 undefined 2
解析:
- console.log(new A().a),new A()为构造函数创立的对象,自身没有 a 属性,所以向它的原型去找,发现原型的 a 属性的属性值为 1,故该输入值为 1;
- console.log(new B().a),ew B()为构造函数创立的对象,该构造函数有参数 a,但该对象没有传参,故该输入值为 undefined;
- console.log(new C(2).a),new C()为构造函数创立的对象,该构造函数有参数 a,且传的实参为 2,执行函数外部,发现 if 为真,执行 this.a = 2, 故属性 a 的值为 2。
—- 问题知识点分割线 —-
CSS 优化和进步性能的办法有哪些?
加载性能:
(1)css 压缩:将写好的 css 进行打包压缩,能够减小文件体积。
(2)css 繁多款式:当须要下边距和右边距的时候,很多时候会抉择应用 margin:top 0 bottom 0;但 margin-bottom:bottom;margin-left:left; 执行效率会更高。
(3)缩小应用 @import,倡议应用 link,因为后者在页面加载时一起加载,前者是期待页面加载实现之后再进行加载。
选择器性能:
(1)要害选择器(key selector)。选择器的最初面的局部为要害选择器(即用来匹配指标元素的局部)。CSS 选择符是从右到左进行匹配的。当应用后辈选择器的时候,浏览器会遍历所有子元素来确定是否是指定的元素等等;
(2)如果规定领有 ID 选择器作为其要害选择器,则不要为规定减少标签。过滤掉无关的规定(这样款式零碎就不会浪费时间去匹配它们了)。
(3)防止应用通配规定,如 *{}计算次数惊人,只对须要用到的元素进行抉择。
(4)尽量少的去对标签进行抉择,而是用 class。
(5)尽量少的去应用后辈选择器,升高选择器的权重值。后辈选择器的开销是最高的,尽量将选择器的深度降到最低,最高不要超过三层,更多的应用类来关联每一个标签元素。
(6)理解哪些属性是能够通过继承而来的,而后防止对这些属性反复指定规定。
渲染性能:
(1)谨慎应用高性能属性:浮动、定位。
(2)尽量减少页面重排、重绘。
(3)去除空规定:{}。空规定的产生起因一般来说是为了预留款式。去除这些空规定无疑能缩小 css 文档体积。
(4)属性值为 0 时,不加单位。
(5)属性值为浮动小数 0.**,能够省略小数点之前的 0。
(6)标准化各种浏览器前缀:带浏览器前缀的在前。规范属性在后。
(7)不应用 @import 前缀,它会影响 css 的加载速度。
(8)选择器优化嵌套,尽量避免层级过深。
(9)css 雪碧图,同一页面相近局部的小图标,方便使用,缩小页面的申请次数,然而同时图片自身会变大,应用时,优劣思考分明,再应用。
(10)正确应用 display 的属性,因为 display 的作用,某些款式组合会有效,徒增款式体积的同时也影响解析性能。
(11)不滥用 web 字体。对于中文网站来说 WebFonts 可能很生疏,国外却很风行。web fonts 通常体积宏大,而且一些浏览器在下载 web fonts 时会阻塞页面渲染伤害性能。
可维护性、健壮性:
(1)将具备雷同属性的款式抽离进去,整合并通过 class 在页面中进行应用,进步 css 的可维护性。
(2)款式与内容拆散:将 css 代码定义到内部 css 中。
—- 问题知识点分割线 —-
介绍一下 HTTPS 和 HTTP 区别
HTTPS 要比 HTTPS 多了 secure 安全性这个概念,实际上,HTTPS 并不是一个新的应用层协定,它其实就是 HTTP + TLS/SSL 协定组合而成,而安全性的保障正是 SSL/TLS 所做的工作。
SSL
安全套接层(Secure Sockets Layer)
TLS
(传输层平安,Transport Layer Security)
当初支流的版本是 TLS/1.2, 之前的 TLS1.0、TLS1.1 都被认为是不平安的,在不久的未来会被齐全淘汰。
HTTPS 就是身披了一层 SSL 的 HTTP。
那么区别有哪些呢👇
- HTTP 是明文传输协定,HTTPS 协定是由 SSL+HTTP 协定构建的可进行加密传输、身份认证的网络协议,比 HTTP 协定平安。
- HTTPS 比 HTTP 更加平安,对搜索引擎更敌对,利于 SEO, 谷歌、百度优先索引 HTTPS 网页。
- HTTPS 规范端口 443,HTTP 规范端口 80。
- HTTPS 须要用到 SSL 证书,而 HTTP 不必。
我感觉记住以下两点 HTTPS 次要作用就行👇
- 对数据进行加密,并建设一个信息安全通道,来保障传输过程中的数据安全;
- 对网站服务器进行实在身份认证。
HTTPS 的毛病
- 证书费用以及更新保护。
- HTTPS 升高肯定用户访问速度(实际上优化好就不是毛病了)。
- HTTPS 耗费 CPU 资源,须要减少大量机器。
—- 问题知识点分割线 —-
Vue 路由守卫有哪些,怎么设置,应用场景等
罕用的两个路由守卫:router.beforeEach 和 router.afterEach
每个守卫办法接管三个参数:to: Route: 行将要进入的指标 路由对象
from: Route: 以后导航正要来到的路由
next: Function: 肯定要调用该办法来 resolve 这个钩子。在我的项目中,个别在 beforeEach 这个钩子函数中进行路由跳转的一些信息判断。判断是否登录,是否拿到对应的路由权限等等。
—- 问题知识点分割线 —-
对浏览器的缓存机制的了解
浏览器缓存的全过程:
- 浏览器第一次加载资源,服务器返回 200,浏览器从服务器下载资源文件,并缓存资源文件与 response header,以供下次加载时比照应用;
- 下一次加载资源时,因为强制缓存优先级较高,先比拟以后工夫与上一次返回 200 时的时间差,如果没有超过 cache-control 设置的 max-age,则没有过期,并命中强缓存,间接从本地读取资源。如果浏览器不反对 HTTP1.1,则应用 expires 头判断是否过期;
- 如果资源已过期,则表明强制缓存没有被命中,则开始协商缓存,向服务器发送带有 If-None-Match 和 If-Modified-Since 的申请;
- 服务器收到申请后,优先依据 Etag 的值判断被申请的文件有没有做批改,Etag 值统一则没有批改,命中协商缓存,返回 304;如果不统一则有改变,间接返回新的资源文件带上新的 Etag 值并返回 200;
-
如果服务器收到的申请没有 Etag 值,则将 If-Modified-Since 和被申请文件的最初批改工夫做比对,统一则命中协商缓存,返回 304;不统一则返回新的 last-modified 和文件并返回 200;
很多网站的资源前面都加了版本号,这样做的目标是:每次降级了 JS 或 CSS 文件后,为了避免浏览器进行缓存,强制扭转版本号,客户端浏览器就会从新下载新的 JS 或 CSS 文件,以保障用户可能及时取得网站的最新更新。
—- 问题知识点分割线 —-
Ajax
它是一种异步通信的办法,通过间接由 js 脚本向服务器发动 http 通信,而后依据服务器返回的数据,更新网页的相应局部,而不必刷新整个页面的一种办法。
面试手写(原生):
//1:创立 Ajax 对象
var xhr = window.XMLHttpRequest?new XMLHttpRequest():new ActiveXObject('Microsoft.XMLHTTP');// 兼容 IE6 及以下版本
//2:配置 Ajax 申请地址
xhr.open('get','index.xml',true);
//3:发送申请
xhr.send(null); // 谨严写法
//4: 监听申请,承受响应
xhr.onreadysatechange=function(){if(xhr.readySate==4&&xhr.status==200 || xhr.status==304)
console.log(xhr.responsetXML)
}
jQuery 写法
$.ajax({
type:'post',
url:'',
async:ture,//async 异步 sync 同步
data:data,// 针对 post 申请
dataType:'jsonp',
success:function (msg) { },
error:function (error) {}})
promise 封装实现:
// promise 封装实现:function getJSON(url) {
// 创立一个 promise 对象
let promise = new Promise(function(resolve, reject) {let xhr = new XMLHttpRequest();
// 新建一个 http 申请
xhr.open("GET", url, true);
// 设置状态的监听函数
xhr.onreadystatechange = function() {if (this.readyState !== 4) return;
// 当申请胜利或失败时,扭转 promise 的状态
if (this.status === 200) {resolve(this.response);
} else {reject(new Error(this.statusText));
}
};
// 设置谬误监听函数
xhr.onerror = function() {reject(new Error(this.statusText));
};
// 设置响应的数据类型
xhr.responseType = "json";
// 设置申请头信息
xhr.setRequestHeader("Accept", "application/json");
// 发送 http 申请
xhr.send(null);
});
return promise;
}