面试题整理
HTML
1、列举常见的块级元素和行内元素各5个
- 块级元素:div,h1~h6,p,ul,ol,dl,li…
- 行内元素:a,span,button,selecture,label…
2、什么是语义化标签,为什么要使用语义化标签?
- 语义化标签:语义化标签是HTML5中的新特性。这一类标签的标签名都有特定的含义,与标签自身的功能相对应。例如header表示页面头部结构,footer表示页面底部结构。
- 语义化标签的优点:
- 代码结构清晰,有利于团队开发以及代码的后期维护;
- 有利用搜索引擎优化:搜索引擎的爬虫是读不懂无语义的span和div的,因此语义化标签能使爬虫抓取更多的有效信息;
- 有利于其他设备解析代码,如屏幕阅读器、盲人阅读器、移动设备等。
3、HTML5中的新特性有哪些?
- 语义化标签,例如: header、footer、main、section、aside;
- input元素新增的type类型,例如:email、color;
- 图形绘制: canvas、svg;
- 本地存储: localStorage、sessionStorage;
- 拖拽
- 地理定位
4、cookie、localStorage、sessionstorage的以及session的区别
首先,四者最大的区别在于cookie、localStorage、sessionStorage都是前端的本地存储,数据保存在浏览器中;而session是后端 的 本地存储,数据保存在服务器中。
- 数据有效期
- cookie:一般由服务器生成,可设置失效时间。如果在浏览器生成,默认是关闭浏览器后失效
- localStorage:除非手动删除,否则永久保存;
- sessionStorage:仅在当前会话有效,关闭浏览器或浏览器窗口后被清除;
- session:由服务器生成,可设置失效时间。
- 作用范围
- cookie:在所有同源窗口中共享;
- localStorage:在所有同源窗口中共享;在相同的协议、相同的主机名、相同的端口下,就能读取/修改到同一份localStorage数据。
- sessionStorage:只在当前窗口有效;(当前页面关闭的时候,自动销毁)
- 存储大小
- cookie: 4KB;
- localStorage:一般5MB;
- sessionStorage:一般5MB;
- 与服务器通信
- cookie:每次请求都会携带在HTTP请求头中,如果使用cookie 保存过多数据会带来性能问题
- localStorage,sessionStorage:不会主动把数据发送给服务器,仅在本地保存
CSS
5. css设置透明度的方式有哪些,区别是什么?
- opacity:0.5,background-color:rgba(255,255,255,0.5)
- 区别
- opacity:元素自身连同其内部子元素都会透明
- rgba:仅元素自身的背景会透明
6.css中清除浮动的方式有那些?
-
在父元素内部末尾添加一个空标签,设置clear:both 样式;
- 优点:通俗易懂,书写方便。
- 缺点:添加许多无意义的标签,结构化比较差。
- clear:both:本质就是闭合浮动, 就是让父盒子闭合出口和入口,不让子盒子出来 。
-
触发BFC,给父元素设置overflow:hidden 样式
- 优点:代码简洁
- 缺点:内容增多的时候容易造成不会自动换行导致内容被隐藏掉,无法显示要溢出的元素。
-
给父元素添加after伪元素清除浮动
-
div::after{ content: ""; display: block; clear:both; } div{ /* 触发 hasLayout */ *zoom: 1;/*ie6清除浮动的方式 *号只有IE6-IE7执行,其他浏览器不执行*/ }
-
优点:符合闭合浮动思想,结构语义化正确。
-
缺点:ie6-7不支持伪元素:after,使用zoom:1触发hasLayout。
-
-
给父元素使用before和after 双伪元素清除浮动
-
div::after,div::before{ content: ""; display: table; } div::after{ clear: both; } div{ *zoom: 1; }
-
优点:代码更简洁
-
缺点:用zoom:1触发hasLayout.
-
-
给父元素设置高度
- 缺点: 需要手动添加高度,如何后面的高度发生变化,还要再次修改高度,给后期的维护带来麻烦。
- 优点: 简单粗暴直接有效,清除了浮动带来的影响。
7.css隐藏元素的方式有那些,区别是什么
css 隐藏元素 | 是否保留元素位置 |
---|---|
display:none | 否 |
opacity:0 | 是 |
visibility:hidden | 是 |
8.css中定位属性有哪些,区别是什么
定位属性 | 是否脱离文档流 | 相对位置 |
---|---|---|
static(默认) | 否 | 否 |
relative(相对定位) | 否 | 相对于自身进行定位,位置不变 |
absolute(绝对定位) | 是 | 相对于就近的带有定位属性(static 默认除外)的父级进行定位,如果没有,则相对于文档显示区进行定位 |
fixed(绝对定位) | 是 | 相对于文档显示区进行定位 |
sticky(粘性定位) | 否 | 相对于父级进行定位(屏幕内不定位,将要超出屏幕时) |
9.css中em和rem和px的区别是什么
-
前两者是响应式的单位,px是固定单位。
-
em:em是一种相对长度单位,相对于自身元素的字号大小,如果没有设置就参照父容器的字号大小或浏览器默认字号大小。
-
给父容器设置font-size:16px ,在给父容器设置宽度为10em,最后在浏览器中呈现出来的效果如下,换算为像素就是160px
-
rem: rem是css3的新标准也是一种相对长度单位,其相对于HTML根标签的字号大小。
- 给html设置font-size为14px,容器设置宽度为10rem,最后在浏览器中呈现出来的效果如下,换算为像素就是140px
11、css 中flex: 1表示什么
- flex为flex-grow、flex-shrink、flex-basis三个属性的缩写。
- flex属性默认值为:0 1 auto (不放大会缩小),常用属性值有none:0 0 auto (不放大也不缩小)、auto:1 1 auto (放大且缩小)。
- flex:n(非负数字)代表 flex-grow:n;flex-shrink:1;flex-basis:0%;
- flex:n1,n2(两个非负数字)代表flex-grow:n1;flex-shrink:n2; flex-basis:0%;
- flex:L(长度或百分比)代表 flex-grow:1;flex-shrink:1;flex-basis:L;
- flex:n,L(一个非负数字、一个长度或百分比)代表flex-grow:n;flex-shrink:1;flex-basis:L;
- flex:1即为flex-grow:1;flex-shrink:1;flex-basis:0%;经常用作自适应布局,内容区会自动放大占满剩余空间。
12、什么是重绘和回流
- 重绘:当页面中节点的样式(例如背景颜色)发生改变,但没有影响页面布局时,浏览器就会进重绘
- 回流:当页面因为节点大小、布局、隐藏等变化导致页面需要重新构建,这个过程称为回流。页面第一次加载时,就会执行第一次回流
- 回流必将引起重绘,而重绘不—定会引起回流。
如何让一个盒子在水平方向和垂直方向都居中
-
使用弹性布局flex ,justifly-conent:center, align-items:center
.father { width: 200px; height: 200px; background-color: aqua; display: flex; justify-content: center; align-items: center; } .son { width: 50px; height: 50px; background-color: brown; }
-
利用子绝父相和左、上外边距实现
- 先为父盒子设置相对定位,再为子盒子设置绝对定位,且绝对定位的四个方向的位移都设为0,然后将外边距margin属性值设置为auto即可。
.father { width: 200px; height: 200px; background-color: aqua; position: relative; } .son { position: absolute; left: 50%; top: 50%; margin-top: -25px; margin-left: -25px; width: 50px; height: 50px; background-color: brown; }
-
利用文本水平居中text-align: center和行高line-height进行实现
-
先为父盒子设置相对定位,再为子盒子设置绝对定位,且将子盒子分别向右、向下移动父盒子的一半,然后利用外边距margin将子盒子分别向左、向上移动子盒子的一半。
-
.father{ width: 200px; height: 200px; background-color: aqua; text-align: center; line-height: 200px; } .son{ display: inline-block; width: 50px; height: 50px; background-color: brown; vertical-align: middle; }
-
-
利用子绝父相和位移实现
-
先为父盒子设置相对定位,再为子盒子设置绝对定位,且将子盒子分别向右、向下移动父盒子的一半,然后利用位移transform: translate;将子盒子分别向左、向上移动子盒子的一半
.father {
width: 200px;
height: 200px;
background-color: aqua;
position: relative;
}
.son {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 50px;
height: 50px;
background-color: brown;
}
less和sass比css有什么优势
- 可以嵌套,更便捷
- 可以使用变量
- 代码的重用
如何做响应式布局或者如何适配
- 响应式布局 是同一页面在不同的屏幕上有不同的布局
- 百分比布局
- rem布局
- 媒体查询 @media screen
- 弹性布局
雪碧图的优缺点
- 雪碧图:实际是指CSS中的图片拼合技术,将多个背景图拼合在同一张图片上,在使用时按照需求对图片位置进行改动。
- 优点:当多个图片合成一张图片时,减少了加载网页时对图片的加载次数,减轻了服务器的压力,提高了页面加载的速度
- 缺点:后期维护比较差
css3,和h5新特性
-
css3 :属性选择器 ,结构伪类选择器 ,伪元素选择器 ,盒子模型 box-sizing ,CSS 渐变,过渡,动画,2D转换
-
属性选择器
- 属性选择器可以根据元素特定属性的来选择元素。这样就可以不用借助于类或者id选择器。
简介 选择 E[att]
选择具有att属性的E元素 E[att:val
选择具有att属性且属性值等于val的E元素 E[att^=val]
匹配具有att属性且值以val开头的E元素 E[att$=val]
匹配具有att属性且值以val结尾的E元素 E[att*=val]
匹配具有att属性且值中含有val的E元素 -
结构伪类选择器
-
结构伪类选择器主要根据文档结构来选择器元素,常用于根据父级选择器里面的子元素
选择符 简介 E: first-child
匹配父元素中的第一个子元素E E: last-child
匹配父元素中最后一个E元素 E: nth-child(n)
匹配父元素中的第n个子元素E E: first-of-type
指定类型E的第一个 E: last-of-type
指定类型E的最后一个 E: nth-of-type(n)
指定类型E的第n个 -
重点:
E: nth-child(key)
-
key
可以是整数、关键字(even/odd
)、公式(n/2n/2n+1
) -
公式
-
-
-
伪元素选择器
选择符 简介 ::before
在元素内部的前面插入内容 ::after
在元素内部的后面插入内容 -
盒子模型 box-sizing
-
CSS 渐变 (两个或多个指定颜色之间显示平滑过渡 )
- 线性渐变(Linear Gradients):向下/向上/向左/向右/对角方向,用
linear-gradient()
函数定义 - 径向渐变(Radial Gradients):由它们的中心定义,用
radial-gradient()
函数定义 - 语法:background: linear-gradient(direction, color1, color2, …);
- 线性渐变(Linear Gradients):向下/向上/向左/向右/对角方向,用
-
过渡(transition) transition: 要过渡的属性 花费时间 运动曲线 何时开始;
-
动画( animation )
-
2D转换(
transform
)- 移动:transform:
translate
() - 旋转:transform:
rotate
() - 缩放:transform:
scale
()
- 移动:transform:
-
-
HTML5:
- 语义化标签
<header>
:头部标签,<nav>
:导航标签 - 新增多媒体标签 视频
<vedio>
音频<audio>
- 新增input属性
type="email"``type="number"
- 新增表单属性
required
必填placeholder
表单的提示信息
- 语义化标签
JavaScript
数据类型
13.JavaScript的数据类型有那些
- 基本类型
- Number(数字): 比如1.9 1 -0.9 0 -30
- String(字符串):被一对引号包围起来的一段文字。 比如”这是一段文字”、’邓乃文’、”90”、””
- Boolean(布尔型):只能是
true
或false
。用于表示逻辑上的正确或错误,true为正确,false为错误。比如1大于2 的结果是正确 - undefined:本身是一种特殊的数据类型。数据只能是
undefined
,自成”一派”。表示未定义,一般是指变量没有数据,同时也是变量的默认值 - null:本身是一种特殊的数据类型,数据只能是
null
,自成”一派”。表示数据为空。一般是用于设置为对象的默认值。 - Symbol(符号 ):ES6新增,主要用于表示数据的唯一性,一般用于对象的属性或迭代器。
- 无穷大bigint(ES10)
- 引入类型
- 对象object (
function、 Data、Array
):一种复合的数据类型。即一个对象里面可能多个其他类型的数据。其中数组、函数都是属于对象
- 对象object (
14、Biglnt是什么?
- BigInt是一种新的数据类型,BigInt 可以表示任意大的整数 用于当整数值大于Number数据类型支持的范围时。这种数据类型允许我们安全地对大整数执行算术操作,表示高分辨率的时间戳,使用大整数ID等等,而不需要使用库。
15、基本数据类型和引用数据类型有什么区别?
- 存储位置:
- 基本类型的变量是保存在栈中的,引用类型的变量是栈中存放变量标识符和指向堆中该变量的指针。基本类型比较是值的比较,引用类型是引用地址的比较
- 访问赋值:基本类型的数据在访问赋值时是进行值传递,引用类型的数据在访问赋值时是进行引用地址的传递
16、数据类型检查的方式有哪些?
-
typeof 检测一些基本数据类型
- 语法:typeof 后面加不加括号都是可以用的
console.log(typeof ([]))
;//objectconsole.log(typeof 123)
;//number - 注意:
正则、{}、[]、null
输出结果为object
- 语法:typeof 后面加不加括号都是可以用的
-
A instanceof B 检测当前实例是否隶属于某各类
-
双目运算符 a instanceof b ,判断a的构造器是否为b,返回值为布尔值
-
function b(){} let a = new b; console.log(a instanceof b);//true console.log(b instanceof Object);//true let arr = [1,2,3,4]; console.log(arr instanceof Array);//true
-
-
Object.prototype.toString.call()
-
Object.prototype.toString.call(12)//[boject Number] Object.prototype.toString.call(true)//[boject Boolean] console.log(toString.call(123)); //[object Number]
-
-
Array.isArray(object)
-
constructor 构造函数
- 语法: 实例.constructor 对象的原型链下(构造函数的原型下)有一个属性,叫constructor var a = { id: 123 }
var a = { id: 123 }
console.log(a.constructor);
- **缺点:**constructor并不可靠,容易被修改(只有参考价值)。即使被修改了,也不会影响代码的正常运行。正常开发的时候,constructor不小心被修改了,为了方便维护,和开发,可以手动更正constructor的指向。
- 语法: 实例.constructor 对象的原型链下(构造函数的原型下)有一个属性,叫constructor var a = { id: 123 }
17、typeof判断数据类型,返回的结果有哪些。
- number、string.boolean、object、function、undefined、symbol
- 注意:
正则、{}、[]、null
输出结果为object
18、instanceof 操作符的原理。
- instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上
object instanceof constructor
object为实例对象,constructor为构造函数 - 构造函数通过new可以实例对象,instanceof 能判断这个对象是否是之前那个构造函数生成的对象 也就是顺着原型链去找,直到找到相同的原型对象,返回true,否则为false
19、typeof和instanceof的区别是什么?
- typeof会返回一个变量的基本类型,instanceof返回的是一个布尔值
- instanceof 可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型 ,而 typeof 也存在弊端,它虽然可以判断基础数据类型(null 除外),但是引用数据类型中,除了 function 类型以外,其他的也无法判断
20、判断一个数据是不是数组的方式有哪些?
//1.instanceof
let arr = [1,2,3,4];
console.log(arr instanceof Array);//true
//2.Array.isArray(object)
console.log(Array.isArray(arr)); //true
//3.Object.prototype.toString.call()
console.log(Object.prototype.toString.call(arr))//[boject Array]
console.log(toString.call(arr)) //[boject Array]
//4.constructor
console.log(arr.constructor); //ƒ Array() { [native code] }
console.log(arr.constructor === Array); //true
21.谈一下你对作用域的了解
- 作用域是一个标识符(变量和函数)可使用的范围,这个范围就是这个标识符的作用域
- 在ES6前分为全局作用域和局部作用域 ES6 出现块级作用域
- 作用域链:当我们使用一个变量时,如果在当前作用域内没有找到,会去他外层作用域查找,如果还没有,就再往外找,一直到全局作用域,还没有找到则会报错。
22.谈一下你对原型的理解
- 每个构造函数都有一个原型对象prototype,在prototype里面有一个constructor的属性,指向的是构造函数本身,每次构造函数创建新的实例上有一个-——proto ——属性, 通过这个属性可访问到原型对象
- 访问对象属性时,会从实例上开始查找,如果没有存在该属性,会访问原型对象获取属性。如果查找对象属性的实例指向的原型,是其他类型的实例,则又会从该实例和其指向原型继续查找,这样不断向上查找就形成了原型链的基本思想
- 每个对象拥有一个原型对象,通过
__proto__
指针指向上一个原型 ,并从中继承方法和属性,同时原型对象也可能拥有原型,这样一层一层,最终指向null
。这种关系被称为原型链 (prototype chain),通过原型链一个对象会拥有定义在其他对象中的属性和方法。 (null 表示“没有对象”,即该处不应该有值。这句话也意味着 Object.prototype 没有原型)
23.什么是闭包
- 闭包是有权访问另一个函数作用域变量的函数
- 优点:隐藏变量以及防止变量被篡改和污染,从而实现封装
- 缺点:函数执行完后,函数内的局部变量没有释放,占用内存时间变长,容易造成内存泄漏
24.如何修改函数的this指向,这些方法的区别是是什么?
- call apply bind
- 区别:
- call和apply会立即调用函数,bind会返回一个改变了this指向的新函数
- apply第二个参数接收一个数组,call和bind接收一个逗号分割的参数序列。
25.事件委托或事件代理的原理是什么?
- 事件冒泡 利用事件冒泡在它们父元素上指定一个事件处理程序
26.事件冒泡和事件捕获的区别
- 事件冒泡:事件从目标事件源开始到document对象逐层向上触发,即是一个从子到父的过程。
- 事件捕获:与事件冒泡相反,事件从document对象开始逐层向下触发,直到事件源,即是一个从父到子的过程。
27.ES6新特性
- let const
- 解构赋值
- 模板字符串
- 简化对象写法
- 箭头函数
- 扩展运算符
- symbol
- promise
- Set Map
28.js异步编程方式有那几种
-
回调函数
- 优点:简单、容易理解和部署。
- 缺点:不利于代码的阅读和维护,各个部分高度耦合,多个异步操作下容易形成回调地狱。
-
Promise
- Promise的构造函数接收一个参数,是函数,并且传入两个参数:resolve,reject,分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数。
- Promise将异步处理变成了链式操作,解决了回调地狱的问题
-
Generator
-
Generator函数是协程在ES6中的实现,最大特点就是可以交出函数的执行权,整个Generator函数就是一个封装的异步任务,或者说是异步任务的容器,异步任务中需要暂停的地方,都用yield语句注明。
function* gen(x) { let y = yield x + 2 return y } const g = gen(1) g.next() // { value:3,done:false} g.next() // { value:undefined,done:true}
- 在调用gen函数时 gen(1), 会返回一个内部指针(即遍历器)g。 这是Generator函数不同于普通函数的另一个地方,即执行它(调用函数)不会返回结果, 返回的一个指针对象 。**调用指针g的next方法,会移动内部指针(即执行异步任务的第一阶段),指向第一个遇到的yield语句,**这里我们是x + 2,但是实际上这里只是举例,实际上 x + 2 这句应该是一个异步操作,比如ajax请求。 换言之,next方法的作用是分阶段执行Generator函数。每次调用next方法,会返回一个对象,表示当前阶段的信息(value属性和done属性)。 value属性是yield语句后面表达式的值,表示当前阶段的值;done属性是一个布尔值,表示Generator函数是否执行完毕,即是否还有下一个阶段。
-
每当调用生成器对象的next的方法时,就会运行到下一个yield表达式。 之所以称这里的gen()为生成器函数,是因为区别如下:
- 普通函数使用function来声明,而生成器函数使用 function * 来声明。
- 普通函数使用return来返回值,而生成器函数使用yield来返回值。
- 普通函数式run to completion模式 ,即一直运行到末尾; 而生成器函数式 run-pause-run 模式, 函数可以在执行过程中暂停一次或者多次。并且暂停期间允许其他代码执行。
-
-
async await
- 异步代码同步执行,被称为异步编程终极解决方案,基于 Promise 使用 async/await来优化then的调用,也是 Generator函数的语法糖。
- async函数返回的是一个 Promise 对象,当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
29.promise有几种状态
-
进行中(pending)、已完成(fulfilled)、已拒绝(rejected)
-
快速创建一个成功的Promise:Promise.resolve()
-
快速创建一个失败的Promise:Promise.reject()
-
Promise.all() Promise.allSttled Promise.race()
30.js如何浅拷贝和深拷贝一个对象
-
基本数据类型的数据是没有深浅拷贝之分的,深浅拷贝只针对于引用类型的数据。
-
浅拷贝:拷贝出来的目标对象的指针和源对象的指针指向的内存空间是同一块空间。浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。
-
方法:Object.assign()、扩展运算符
let obj1 = { name: '张三', action: { say: 'hi' } } let obj2 = Object.assign({}, obj1) obj2.name = '李四' obj2.action.say = 'hello' console.log('obj1', obj1) // obj1 { name: '张三', action: { say: 'hello'} console.log('obj2', obj2) // obj2 { name: '李四', action: { say: 'hello'} let obj1 = { name: '张三', action: { say: 'hi' } } let obj2 = { ...obj1 }; obj2.name = '李四'
? obj2.action.say = ‘hello’
console.log(‘obj1’, obj1)
// obj1 { name: ‘张三’, action: { say: ‘hello’}
console.log(‘obj2’, obj2)
// obj2 { name: ‘李四’, action: { say: ‘hello’} -
-
深拷贝:创造一个一模一样的对象,新对象和源对象不共享内存,修改新对象不会影响源对象。
-
JSON.parse(JSON.stringify()) 递归
-
//深拷贝 let obj1 = { name: '张三', action: { say: 'hi'}; let obj2 = JSON.parse(JSON.stringify(obj1)); obj2.name = '李四'; obj2.action.say = 'hello' console.log('obj1',obj1) // obj1 { name: '张三', action: { say: 'hi'} console.log('obj2',obj2) // obj2 { name: '李四', action: { say: 'hello'} * JSON.stringify() * 存在的问题: * 1. 如果 obj 里有时间对象,则时间对象会变成字符串格式 * 2. 如果 obj 里有RegExp、Error对象 则会变成空对象 * 3. 如果 obj 里有函数、undefined 则会丢失 * 4. 如果 obj 里有NaN、Infinity、-Infinity 则会变成null //递归 var deepCopy = function (obj) { if (typeof obj !== 'object') return; var newObj = obj instanceof Array ? [] : {}; for (var key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key]; } } return newObj; } let newObj = deepCopy(obj1) newObj.name = '李四'; newObj.action.say = 'hello' console.log('obj1', obj1); // obj1 { name: '张三', action: { say: 'hi'} console.log('newObj', newObj); // obj2 { name: '李四', action: { say: 'hello'}
-
31.for循环中break和continue的区别是什么?
- break结束整个循环,continue跳出当前循环。
32.如何用原生js给一个按钮的点击事件绑定两个事件处理函数
-
使用addEventListener
<button id="btn">冬运会</button> <script> //事件监听 绑定多个事件; var btn = document.getElementById("btn"); btn.addEventListener("click", bing); btn.addEventListener("click", xue); function bing() { alert("hello 冰墩墩"); } function xue() { alert("hello 雪容融"); } </script>
33.js引擎如何实现异步的
-
JS引擎本身是单线程的,异步其实是借助浏览器内核多线程来实现的。现代浏览器使用的都是多进程架构(如下图),而一个进程可以包含一个或多个线程。JS引擎处于渲染进程,异步也是通过此进程中的各个线程的协调来完成的。
- GUI线程:主要用于渲染布局
- JS引擎线程:用于解析、执行JS代码;它与GUI线程是互斥的,因为JS里可以操作DOM,如果与GUI同时执行,可能会引起页面渲染混乱
- 定时触发器线程:用于执行定时任务,setTimeout,setInterval
- 事件触发线程:将满足条件的事件加入任务队列
- 异步HTTP请求线程:XHR所在线程,用于处理AJAX请求
-
多线程之间的配合实现异步:
- 定时器,异步请求线程可以独立于JS引擎主线程同时运行
- 定时器任务定时完成后,会通知事件触发线程,将定时器的回调任务加入任务队列
- 异步HTTP请求完成时,如果有回调函数,就会通知事件触发线程往任务队里添加事件
- 通过Event Loop机制,浏览器依次执行完任务队列里的所有任务
-
处理异步需要Event Loop:主线程从任务队列中读取事件,这个过程是循环不断的 也叫做事件循环,是指浏览器或Node环境的一种解决javaScript单线程运行时不会阻塞的一种机制,也就是实现异步的原理 浏览器中的Event Loop由执行栈Execution Stack、后台线程Background Threads、宏任务Macrotask 、微任务Microtask组成。
-
js代码运行
-
首先执行全局script,script可以包含同步任务和异步任务,同步任务执行完就出栈,异步任务则通过异步处理机制加入任务队列
-
当所有同步任务执行完成,首先检查微任务队列,一次执行完所有微任务
-
当所有微任务执行完以后,从任务队列中取出最早的宏任务,宏任务执行前,再次检查微任务队列,如果有新的微任务,先清空微任务,再执行宏任务,执行完成后,依次从队列中取出后面的宏任务,重复此步骤,直到执行完所有宏任务,Stack清空
- Event Loop处理模型
-
-
https://www.jianshu.com/p/b95d47921ebb
34.什么是EventLoop
- Event Loop:也叫做事件循环,是指浏览器或Node环境的一种解决javaScript单线程运行时不会阻塞的一种机制,也就是实现异步的原理。作为一种单线程语言,javascript本身是没有异步这一说法的,是由其宿主环境提供的。
- 由于JavaScript是单线程语言,单线程就意味着所有任务都需要排队,只有前一个任务执行完了,才会去执行下一个任务,如果前一个任务耗时很长,那么后一个任务就不得不一直等着,这样导致的问题是:如果js执行时间过长就会造成页面渲染不连贯,导致页面加载渲染阻塞的感觉, 网页出现假死的状态。为了解决这个问题,所以JS将任务分为同步任务和异步任务:
- 同步任务:在主线程上执行,形成一个执行栈,只有前一个任务执行完毕,才会执行后一个任务。
- 异步任务:不进入主线程,而是进入任务队列,当主线程的任务执行完毕,才会从任务队列中取出异步任务放入主线程中执行。
- 异步任务又分为宏任务和微任务
- 异步运行机制如下
- 所有同步任务都在主线程上执行,形成一个执行栈;
- 主线程之外,还有一个任务队列,只要异步任务有了结果,就在任务队列中放置一个事件;
- 执行栈中所有同步任务执行完毕,系统就会读取任务队列,看看有哪些事件,那些对应的异步任务,于是结束等待,进入执行栈,开始执行。
- http://t.csdn.cn/TRaWv
- https://www.jianshu.com/p/b95d47921ebb
35.宏任务和微任务的区别
-
JavaScript 把异步任务又做了进一步的划分,异步任务又分为两类,分别是:
-
宏任务(macrotask):
- 宏任务的概念我理解的其实就是 常规的任务 就是我们通常说的js执行的任务
-
微任务(microtask:
- 当前(此次事件循环中)宏任务执行完,在下一个宏任务开始之前需要执行的任务,可以理解为回调事件。
-
宏任务(Macrotask) 微任务(Microtask) 谁发起的 宿主(Node、浏览器 JS引擎 具体事件 1.setTimeout,setInterval 2. MessageChannel(消息通道) 3.异步 Ajax 请求、 4.setImmediate(Node环境) 5. script(整体代码块) … 1.MutationObserver(浏览器环境)2.Promise.[ then/catch/finally ] 3.process.nextTick(Node环境) 4.queueMicrotask … 谁先运行 后运行 先运行 会触发新一轮Tick吗 会 不会
-
-
宏任务和微任务的执行顺序
- 每一个宏任务执行完之后,都会检查是否存在待执行的微任务,
- 如果有,则执行完所有微任务之后,再继续执行下一个宏任务。
36.什么是函数柯里化?
-
函数柯里化:把接受多个参数的函数转变为接受⼀个单⼀参数的函数,并且 返回接受余下的参数且返回结果的新函数的技术。 即 把一个函数传递多个参数完成的事情改变成一个函数传递一个参数的多个函数形式
作用 提前返回 避免重复去判断某一条件是否符合,不符合则return 不再继续执行下面的操作 延迟执行 避免重复的去执行程序,等真正需要结果的时候再执行 参数复用 需要输入多个参数,最终只需输入一个,其余通过arguments来获取 -
function isType(type, value) { return Object.prototype.toString.call(value) === `[object ${type}]` } console.log(isType('String', '9999')); console.log(isType('Number', '9999')); function isNewType(type) { return function (value) { return Object.prototype.toString.call(value) === `[object ${type}]` } } let isString = isNewType('String') let isNumber = isNewType('Number') console.log(isString('999')); console.log(isNumber(333)); console.log(isNewType('string')('520'));
| 参数复用 | 需要输入多个参数,最终只需输入一个,其余通过arguments来获取 |
-
function isType(type, value) { return Object.prototype.toString.call(value) === `[object ${type}]` } console.log(isType('String', '9999')); console.log(isType('Number', '9999')); function isNewType(type) { return function (value) { return Object.prototype.toString.call(value) === `[object ${type}]` } } let isString = isNewType('String') let isNumber = isNewType('Number') console.log(isString('999')); console.log(isNumber(333)); console.log(isNewType('string')('520'));