js 中常见的数据类型:
- string
- number
- boolean
- underfined
- Null
- NaN
- object
- symbol
js中基本数据类型有
- number
- string
- boolean
- null
- undefined
js中的引用数据类型有
- object
- array
- function
检测数据类型的方法
- typeof
可以判断出'string','number','boolean','underfined','symbol'
当判断typeof(null)时值为'object',判断数组和对象的值均为'object'
- instanceof
原理是构造函数的 prototype 属性是否出现在对象的原型链中的任何位置
字符串比较问题
"2">"11" //结果:true
- 在同是字符串的时候,首先左边第一位的是 '2' 转换成 0000 0010(二进制) 与右边第一位 '1' 转换成 0000 0001 (二进制) 做比较大小
- 在字符串和number进行比较时,把字符串隐式转化成number类型在进行比较。
cookie,sessionStorage和localStorage
- cookie用来保存登录信息,大小限制为4KB左右
- localStorage是Html5新增的,用于本地数据存储,保存的数据没有过期时间,一般浏览器大小限制在5MB
- sessionStorage接口方法和localStorage类似,但保存的数据的只会在当前会话中保存下来,页面关闭后会被清空。
跨域
什么是跨域? **
跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。
什么是同源策略?
同源策略/ SOP(Same origin policy)是一种约定,由Netscape公司发布。它是浏览器最核心,也最基本的安全功能,如果有了同源策略,所谓相似是指协议+域名+端口**三者相同,如果有一个不同,即为非同源。
跨域解决方案:
1. cors 跨域资源共享
设置响应头
response.setHeader("Access-Control-Allow-Origin", "*")
缺点:是会引起CSRF攻击,如何解决这个问题呢? 解决方法:1.主要使用token 2. 尽量使用Post 2. jsonp jsonp缺点:只能实现get一种请求。
CORS与JSONP 区别
- JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求。
- 使用CORS,可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理。
- JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS。[低版本IE7以下不支持,要支持IE7还是要用jsonp方式]
cookie 跨域问题
- nginx反向代理
- jsonp
- nodejs superagent 其实本质也是jsonp的方式
localStorage跨域问题
可以使用postMessage和iframe
思路如下:
假设有a页面和b页面,两个页面。
通过a页面去修改b页面的本地数据:
> ① 在a页面创建一个iframe,嵌入b页面。
> ② a页面通过postMessage传递指定格式的消息给b页面。
> ③ b页面解析a页面传递过来的消息内容,调用localStorage API 操作本地数据。
> ④ b页面包装localStorage的操作结果,并通过postMessage传递给a页面。
> ⑤ a页面解析b页面传递回来的消息内容,得到 localStorage 的操作结果。
var 、let 和const区别
- 在作用域方面
var 声明的变量不存在块及作用
let 声明的变量存在块及作用域、
- 在变量提升方面
var 声明的变量存在变量提升
let const声明的变量不存在变量提升 唯一不同的是 const 声明的变量一旦赋值就不能再改变了
- 在重复声明方面
var 可以多次声明,let不存在多次声明
const和let基本相同 唯一不同的是const声明的变量一旦赋值就不能在改变。
面向对象
特点:封装,继承,多态
-
封装
把一些数据和对数据的操作集中在一起,向外暴露需要的接口(属性和方法) -
继承
一个类型的实例能够访问另外一个类型的属性和方法。 类和类之间的关系 子类继承父类,你只不过是子类中的实例。 构造函数继承 原型链继承 组合继承 寄生组合式继承 class 继承 -
多态
所谓多态,就是同一个方法的多种调用方式
promise
promise是一个类,是异步编程的解决方案和回调函数的使用有关,多个回调函数使用行成回调地狱。promise有三个状态分别是等待,成功,失败,每个promise都有一个.then的方法,resolve代表成功,reject代表失败,不管先调用resolve方法,还是先调用reject方法,按照先调用先生效的原则。
ES5新增的有哪些?
像 数组:
forEach();map();every()filter();isArray()
string:
trim()
Data:
Date.now()
Json:
JSON.stringify()//将js对象转化成字符串
JSON.parse()//将字符串转换为js值
this指向
ES6新增的有哪些?
- let const可以再说说var,const,let的区别
- 模板字符串
- 解构赋值对数组和对象的优化
- 箭头函数,可以多说说,this指向问题
- 扩展运算符 ...
- set方法,常用于数组去重
- promise解决异步问题
- set和map方法
- for...of...
ES7新增
- 求幂运算符
Math.pow(3, 2) === 3 ** 2
- Array.prototype.includes()
indexOf(3) > -1 //true 区别:1. 简便性;includes返回值是布尔值,indexOf返回值是索引 2.精确性 对于NaN,在严格模式下,includes返回值是布尔值,indexOf返回值是-1
ES8新增
- 使用async await异步解决
- Object.entries()
Object.entries({ one: 1, two: 2 }) //[['one', 1], ['two', 2]] Object.extries([1, 3]) //[['0', 1], ['1', 3]]
- 字符串填充padStart()、padEnd() **promise **
Promise.all():当所有的异步都执行完毕以后才会执行.then中的操作。
Promise.race():只要有一个promise执行完毕后就会执行.then操作。
基础promise封装
===========
functionajax(url) {
return newPromise(function (resolve, reject) {
if (window.XMLHttpRequest) {
var xhr=newXMLHttpRequest();
} else {
var xhr=newActiveXObject("Microsoft.XMLHTTP");
}
xhr.open("GET", url, true);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState==4) {
if (xhr.status==200) {
var data = xhr.responseText;
resolve(data);
}
}
}
})
}
set和map区别
set:
set是ES6提供的一种新的数据结构,类似于数组,但是成员的值是唯一的没有重复的,接受的参数是一个数组方法有: add():添加
delete():删除
size:长度
has():查找
clear:清除所有
map:
map类似于对象,也是键值对的集合, 但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键方法有:
set():设置
get():获取
delete():删除
has():查找
clear():清除所有
for of 和for in区别:
for in 循环特别适合遍历对象 for…in是遍历数组、对象的key for…of是遍历数组的value
闭包的概念及优缺点
========= 闭包的概念:
就是在一个函数外部能够访问该函数内部局部变量的函数。
优点:
避免全局变量的污染。
希望一个变量长期储存在内存中。
缺点:
内内存泄漏
增加内存的使用量
this 指向问题
宗旨就是:谁调用它,它就指向谁
- 箭头函数中的this指向它的环境。
- 构造函数调用,this 指向实例对象
- 对象方法调用, 此时 this 指向 该方法所属的对象
- 通过事件绑定, 此时 this 指向 绑定事件的对象
箭头函数和普通函数的区别?
- 外型上的区别:箭头函数是有箭头的,普通函数没有。
- 函数名上的区别:箭头函数都是匿名函数,普通函数可以是匿名函数也可以不是匿名函数。
- new运算符上的区别:箭头函数不能使用new运算符,普通函数可以是new运算符。
- this指向的区别:箭头函数的this指向它的环境,普通函数的this指向,谁调用它,它就指向谁。
如何改变this指向以及它们的区别
call apply bind
- call和apply区别是参数个数不同。
- call的参数可以无限个;而apply的参数最多只能有两个。
- bind是创建一个新函数,与被调函数有相同的函数体。
http和https的区别?
- https协议需要申请证书,一般不免费
- http是超文本传输协议,信息是明文传输的,https具有安全性,https采用的是加密传输协议。
- http和https采用的不同的连接方式,http端口号是80,https端口号是443.
节流和防抖
防抖
防抖是指在一段时间内,函数被触发多次,但是只执行一次,当达到了一定的时间间隔就会执行一次
使用场景:搜索,window触发resize
function debounce(fn, delay) {
let timer = null;
return function () {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, arguments);
}, delay);
}
}
节流
节流是会有规律的每隔时间n就执行一次函数。
使用场景:鼠标不断点击触发;监听滚动事件
function throttle(fn, cycle) {
let start = Date.now();
let now;
let timer;
return function () {
now = Date.now();
clearTimeout(timer);
if (now - start >= cycle) {
fn.apply(this, arguments);
start = now;
} else {
timer = setTimeout(() => {
fn.apply(this, arguments);
}, cycle);
}
}
}
bom 和 dom 有什么区别,常见的 bom 对象有哪些?
BOM 是 Browser Object Model 缩写,即浏览器对象模型 Dom 是 Document Object Model 缩写,即文档对象模型
常见的 bom 对象有哪些
- window 对象——BOM 核心
- document 对象
- location 对象
获得当前页面的 URL,并重定向到新的页面
- location.herf
- location.port
- navigator 对象 获得与浏览器有关的信息 userAgent 是最常用的属性,用来完成浏览器判断
- screen 对象 主要用来获取用户的屏幕信息。
- history 对象
-
back() 返回上一页。
-
forward() 返回下一页
go(“参数”) -1 表示上一页,1 表示下一页。
原生 js 事件传播流程是什么?
- 事件捕获
- 处于目标阶段
- 事件冒泡阶段
js单线程
JavaScript 的单线程,与它的用途有关。JavaScript浏览器脚本语言,JavaScript 的主要用途是实现用户互动,及操作 DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。
为了利用多核 CPU 的计算能力,HTML5 提出 Web Worker 标准,允许 JavaScript 脚本创建多个线程,但是子线程完全受主线程控制,且不得操作 DOM。所以,这个新标准并没有改变 JavaScript 单线程的本质。
面向对象(封装继承多态)
- 封装 把相关的信息(无论数据或方法)存储在对象中的能力
- 继承 从另一个类(或多个类)得来类的属性和方法的能力
- 多态 编写能以多种方法运行的函数或方法的能力
回流和重绘
区别:回流必将引起重绘;而重绘不一定会引起回流。
回流: 当 render tree 中的一部分(或全部)元素的属性改变而需要重新构建页面。这就称为回流(reflow)。 重绘:
当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,称为重绘。
比方说:只有颜色改变的时候就只会发生重绘而不会引起回流,
当页面布局和几何属性改变时就需要回流.
get 和 post 区别
- get 传输不安全,因为数据放在请求的 url 中;post 所有操作用户是看不到的
- get 传输数据量小,因为受到 url 长度的限制;post 传输的数据量较大,一般不受限制
- get 执行效率比 post 更好。get 是 form 提交的默认方式。
为什么要使用深拷贝?
在改变新的数组(对象)的时候,不改变原数组(对象)
深拷贝和浅拷贝
- 浅拷贝: 将原对象或原数组的引用(地址)直接赋给新对象,新数组,新对象/数组只是原对象的一个引用。
- 实现浅拷贝的方法有:
-
for...in...
-
object.assign()
-
直接用 = 号
-
扩展运算符 ...
-
深拷贝: 将原对象的各项属性的“值”(数组的所有元素)拷贝给新的对象和数组,是“值”而不是“引用”。
- 实现深拷贝的方法:
- Json.parse()和Json.stringfiy()
- 使用Jquery中的$.extend()
js变量提升的原理
我们习惯将 var a = 2;看做是一个声明,而实际上 javascript 引擎并不这么认为。它将 var a 和 a = 2 看做是两个单独的声明,第一个是编译阶段的任务,而第二个则是执行阶段的任务。
HTTP 状态码及含义
200 OK ,表明请求已经成功. 默认情况下状态码为200的响应可以被缓存。
302 Found,临时重定向。重定向状态码表明请求的资源被暂时的移动到了由 Location 头部指定的 URL 上。浏览器会重定向到这个URL,但是搜索引擎不会对该资源的链接进行更新。
400 Bad Request,表示由于语法无效,服务器无法理解该请求。客户端不应该在未经修改的情况下重复此请求。
403 Forbidden,指的是服务器端有能力处理该请求,但是拒绝授权访问。进入该状态后,不能再继续进行验证。该访问是永久禁止的,并且与应用逻辑密切相关(例如不正确的密码)
404 Not Found,说明服务器端无法找到所请求的资源。404 不能说明请求的资源是临时还是永久丢失。如果服务器知道该资源是永久丢失,那么应该返回 410 (Gone) 而不是 404 。
500 Internal Server Error,表示所请求的服务器遇到意外的情况并阻止其执行请求。
502 Bad Gateway,表示作为网关或代理角色的服务器,从上游服务器(如tomcat、php-fpm)中接收到的响应是无效的。服务器挂掉了的意思。
503 Serveice Unavailable,表示服务器尚未处于可以接受请求的状态。
web 性能优化
- 减少 http 请求
- 使用 css scripts
- 样式放在头部,js 放在底部
- 压缩组件
- 使用 CDN
map 和 forEach 有什么区别?
- forEach()返回值是 undefined,不可以链式调用。
2、 map()返回一个新数组,原数组不会改变。
3、 没有办法终止或者跳出 forEach()循环,除非抛出异常,所以想执行一个数组是否满足什么条件,返回布尔值,可以用一般的 for 循环实现,或者用 Array.every()或者 Array.some();
4、 $.each()方法规定为每个匹配元素规定运行的函数,可以返回 false 可用于及早停止循环。
异步与同步
-
同步概念
同步是阻塞模式。当一个方法被调用时,调用者需要等待该方法执行完毕并返回才能继续执行,我们称这个方法是同步方法。
-
异步概念
异步是非阻塞模式。当一个方法被调用时立即返回,并获取一个线程执行该方法内部的业务,调用者不用等待该方法执行完毕,我们称这个方法为异步方法
举个生活中的例子:
同步就像你冬天早上起来上班,需要先把水烧好后再去洗脸刷牙,这样一来你就会觉得时间不够用,那么此时异步就能节约很多的时间,你可以在烧热水的时间内,完成洗漱等事情,不需要等待热水烧好。
DOM 事件流传播
- 事件捕获阶段(当你使用事件捕获时,父级元素先触发,子级元素后触发,即 div 先触发,p 后触发。)
- 处于目标阶段
- 事件冒泡阶段(当你使用事件冒泡时,子级元素先触发,父级元素后触发,即 p 先触发,div 后触发)
阻止事件流方式:
- q1:阻止冒泡方式有哪些?
- IE:事件对象.cancelBubble=true;
- 火狐:事件对象.stopPropagation();
- q2:阻止浏览器的默认行为有哪些?
- event.preventDefault(); //现代浏览器
- event.returnValue = false; //IE 低版本及部分现代浏览器。
- return false;//兼容性比较好 最好用在代码的最后面。
DOM2 级事件和普通(传统)事件区别:
1.捕获由外向内传播;冒泡由内向外。
2.传统事件不支持捕获;DOM2级事件支持捕获。
3.传统事件多个相同的事件名,会覆盖 ;DOM2级事件会依次执行。
4.DOM2级事件有兼容性的。
事件委托?
概念:利用冒泡原理,把某个子元素事件委托给父元素执行。 优点:
- 提高性能
- 动态监听
谈谈js事件循环机制
程序开始执行之后,主程序则开始执行同步任务,碰到异步任务就把它放到任务队列中,等到同步任务全部执行完毕之后,js引擎便去查看任务队列有没有可以执行的异步任务,将异步任务转为同步任务,开始执行,执行完同步任务之后继续查看任务队列,这个过程是一直循环的,因此这个过程就是所谓的事件循环,其中任务队列也被称为事件队列。通过一个任务队列,单线程的js实现了异步任务的执行,给人感觉js好像是多线程的。
async 和 await
原理:async 和 await 用了同步的方式去做异步,async 定义的函数的返回值都是 promise,await 后面的函数会先执行一遍,然后就会跳出整个 async 函数来执行后面js的代码
Ajax
ajax是“Asynchronous JavaScript and XML”的缩写,是一种创建交互式网页应用的网页开发技术, ajax具有以下优点:
- 使用异步方式与服务器通信,具有更加迅速的响应能力。
- 优化了浏览器和服务器之间的传输,减少不必要的数据往返,减少了带宽占用。
- Ajax最大特点可以实现动态不刷新(局部刷新)
同时ajax也是有缺点的:
1、ajax不支持浏览器back按钮。
2、安全问题 AJAX暴露了与服务器交互的细节。
3、对搜索引擎的支持比较弱。
4、破坏了程序的异常机制。
5、不容易调试。
如何获取用户的浏览器是什么?
navigator.userAgent
原型和原型链
每一个构造函数都有一个原型对象protype,每一个原型对象都有一个指向构造函数的内部指针construct,每一个实例都有一个指向原型对象的内部指针-proto-,原型对象上的属性和方法都能被实例所访问到。
排序算法
- 选择排序
function selectionSort(arr) {
var len = arr.length;
var minIndex, temp;
for (var i = 0; i < len - 1; i++) {
minIndex = i;
for (var j = i + 1; j < len; j++) {
if (arr[j] < arr[minIndex]) { // 寻找最小的数
minIndex = j; // 将最小数的索引保存
}
}
temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
return arr;
}
- 冒泡排序
var examplearr=[8,94,15,88,55,76,21,39];
function sortarr(arr){
for(i=0;i<arr.length-1;i++){
for(j=0;j<arr.length-1-i;j++){
if(arr[j]>arr[j+1]){
var temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
return arr;
}
sortarr(examplearr);
console.log(examplearr);
- 快速排序
function quickSort(arr){
if(arr.length<1){
return arr;
}
var pivotIndex=Math.floor(arr.length/2);//找到那个基准数
var pivot=arr.splice(pivotIndex,1)[0]; //取出基准数,并去除,splice返回值为数组。
var left=[];
var right=[];
for(var i=0;i<arr.length;i++){
if(arr[i]<pivot){
left.push(arr[i]);
}else{
right.push(arr[i]);
}
}
return quickSort(left).concat([pivot],quickSort(right)); //加入基准数
}
arr=[2,1,5,8,3,7,4,6,9];
console.log(quickSort(arr)); //[1, 2, 3, 4, 5, 6, 7, 8, 9]
浏览器的渲染原理(浏览器是怎样工作的)
用户输入url,浏览器向服务器发送请求,服务器返回html文件,浏览器载入html代码,当浏览器解析到head中有使用link标签引入的css样式的时候,浏览器再次向服务器发出请求,请求css文件,然后服务器返回css文件,当浏览器解析到html中body部分,此时的css文件已经到手了,浏览器开始渲染页面,当浏览器解析到img标签的时候,再次向服务器发送请求,此时浏览器是不会先加载图片的,而是先加载后面的代码,当服务器返回图片时,浏览器重新渲染这部分代码,当浏览器发现script标签的时候,很快去运行它,当浏览器解析到,此时浏览器叹了口气,终于完成任务了,我太难了。
数组的方法
slice()方法
格式:数组.slice(start,end)
功能:可以基于当前数组获取指定区域的元素包含start,不包含end,即[start,end)。
返回值:生成新的数组,原数组不发生变化。
splice()方法
格式:数组.splice(start,length,数据1,数据2...)
功能:增加,删除,修改
参数:start指开始截取的位置
lenght截取的元素长度
从第三个参数开始:在start位置,插入的元素
返回值:截取元素组成的数组
join()方法
格式:数组.join(字符串)
功能:将数组中的元素,用传入的拼接符,拼接成一个字符串。
返回值:拼接好的字符串。
reverse()方法
格式:数组.reverse()
功能:逆序
sort()方法
格式:数组.sort() 默认从小到大排序,按照字符串进行排序的。
参数:一个函数,该函数表示怎么进行排序的。
ECMAscript 5新增的数组方法:
indexOf()
格式:数组.indexOf(item,start)
参数:item是数组任意元素
start是指数组下标
功能:在数组中查找第一次出现item元素下标,从start开始查找。
返回值:-1表示没有查找到的元素下标
>=0表示查找到的元素下标
数组遍历:
for
for...in
forEach
forEach
数组.forEach(function(item,index,array){
item是数组任意元素
index是指数组下标
array数组本身
})
map
数组.map(function(item,index,array){
//遍历要做的事情
// 返回值:新数组,原数组不发生改变
})
filter
数组.filter(function(item,index,array){ //过滤
//过滤的条件
})
some
数组.some(function(item,index,array){ //查找数组的是否有符合条件的元素,如果有返回true,没有返回false。
//只找到符合条件的元素,后面的循环都停止了。
})
every
数组.every(function(){//查找数组的元素是否都符合条件,是返回true,否则返回false.
//
})
reduce
数组.reduce(function(prev,next,index,array){
prev 第一次是下标为0的元素。
第二次是上一次return的值。
next 从下标1开始,当前遍历到的元素。
array数组本身。
})
字符串的方法
charAt()
字符串.charAt(下标) 下标是从零开始
charCodeAt()
charCodeAt(下标) 返回对应下标对应的ASCII值
fromCharCode(码值)
功能:将ascii值转为对应的字符
substring() 截取
格式:字符串.substring(start,end)
功能:将字符串中[start,end)提取这一部分字符,生成新字符。
返回值:新字符串。
substr() 截取
格式:substr(start,length)
返回值:新生成的字符串。
slice() 提取
格式:字符串.slice(start,end)
功能:将字符串中[start,end)提取这一部分字符,生成新字符。
返回值:新生成的字符串。
replace() 替换
格式:字符串.replace(oldStr,newStr)
功能:用newStr替换oldStr
返回值:新生成的字符串。
split()
格式:字符串.split(分割符,length)
参数:分隔符对原字符串进行分割,length返回数组的长度,一般不用。
功能:用分割符对原字符串,进行字符串分割。将分割完毕后的字符串放在数组中返回。
返回值:数组。
join()
格式:数组.join()
功能:将数值转换成字符串。
export(导出)和import(导入) 之间的区别:
ES6主要有两个功能:export(导出)和import(导入)
export用于对外输出本模块(一个文件可以理解为一个模块)变量的接口
import用于在一个模块中加载另一个含有export接口的模块。
也就是说使用export命令定义了模块的对外接口以后,其他JS文件就可以通过import命令加载这个模块(文件)。
export与export default之间的区别:
1、export与export default均可用于导出常量、函数、文件、模块等
2、你可以在其它文件或模块中通过import+(常量 | 函数 | 文件 | 模块)名的方式,将其导入,以便能够对其进行使用
3、在一个文件或模块中,export、import可以有多个,export default仅有一个
4、通过export方式导出,在导入时要加{ },export default则不需要
这样来说其实很多时候export与export default可以实现同样的目的。
注意第四条,通过export方式导出,在导入时要加{ },export default则不需要。使用export default命令,为模块指定默认输出,这样就不需要知道所要加载模块的变量名。
数组去重问题
1. 双层 for 循环嵌套
for (var i = 0; i < arr.length; i++) {
for (var j = i + 1; j < arr.length; j++) {
if (arr[i] == arr[j]) {
//如果第一个等于第二个,splice方法删除第二个
arr.splice(j, 1);
j--;
}
}
}
- es5 方法,Ie8 以下不支持
var arrs = [];
//遍历当前数组
for (var i = 0; i < array.length; i++) {
//如果临时数组里没有当前数组的当前值,则把当前值push到新数组里面
if (arrs.indexOf(array[i]) == -1) {
arrs.push(array[i]);
}
}
return arrs;
- es6 利用 set 去重
function newArr(arr) {
return Array.from(new Set(arr));
}
- sort 去重
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return;
}
arr = arr.sort()
var arrry= [arr[0]];
for (var i = 1; i < arr.length; i++) {
if (arr[i] !== arr[i-1]) {
arrry.push(arr[i]);
}
}
return arrry;
}
利用sort()排序方法,然后根据排序后的结果进行遍历及相邻元素比对
网页性能优化
1、资源压缩合并,减少http请求
2、非核心代码异步加载 --> 异步加载的方式 --> 异步加载的区别
3、利用浏览器缓存 --> 缓存的分类 --> 缓存的原理
4、使用CDN
5、DNS预解析
浏览器打开网页都经历了什么?
浏览器页面准备:如unload前一个页面、初始化资源等。
重定向:如果服务端返回header中定义了重定向才会有这个过程,如果没有重定向,不会产生这个过程。
app cache:会先检查这个域名是否有缓存,如果有缓存就不需要DNS解析域名。这里的app是值应用程序application,不指手机app。
DNS解析:把域名解析成IP,如果直接用ip地址访问,不产生这个过程。
TCP连接:http协议是经过TCP来传输的,所以产生一个http请求就会有TCP connect,但是依赖于长连接,不会产生这个过程。
发送请求:请求服务端资源。
接受请求:接受服务端返回数据。
解析HTML结构
加载外部脚本和样式表文件:正常来说JS、css都是外部加载的。
解析并执行脚本代码
构建与解析HTML DOM树
加载外部图片
页面加载完成,页面正常显示。
图片懒加载和预加载
- 预加载:提前加载图片,当用户需要的时候直接从本地缓存中渲染。
- 懒加载:懒加载的主要目的是作为服务器前端的优化,减少请求数量或延迟请求数量。
- 两种技术的本质:两者的行为是相反的,一个是提前加载,一个是迟缓甚至不加载。
- 懒加载对服务器前端有一定的缓解压力,预加载 则会增加服务器前端压力。 参考:图片的懒加载和预加载