2周刷完100道前端优质面试真题
发布于 3 个月前 作者 yeinbeingliu 427 次浏览 来自 面试宝典

前端面试技能总结 - 2周刷完100道前端优质面试真题

vue中MVVM的实现原理 答:由于我读过vue的源码,所以可以比较清楚的说明这其中的原理。主要是数据劫持、模板解析、依赖收集这几个过程。这道题也是被问到最多的一道题。可以参考:剖析Vue实现原理 - 如何实现双向绑定mvvm

Object.defineProperty方法有什么作用?有哪些参数?可以通过描述对象来设置哪些特性? 答:这道题是上一道题的拓展。Object.defineProperty方法可以给一个对象设置相关的属性,这个方法一共有三个参数,第一个参数是目标对象,第二个参数是属性名,第三个参数可以是一个描述对象。描述对象一个有如下特性:value – 设置属性值、configurable – 表示是否可删除属性,能否修改属性的特性、writable – 是否是只读属性、enumerable – 是否是可枚举属性、get – 读取属性时调用的函数、set – 设置属性时调用的函数。

for in可以遍历原型链上的属性吗?可以遍历不可枚举属性吗?Object.keys可以遍历到不可枚举属性吗?怎么遍历到对象的不可枚举属性? 答:这道题也是上一道题中提及的枚举特性的拓展。for in 可以遍历到原型链上的属性,但是遍历不到不可枚举属性。Object.keys不能遍历到原型链上的属性也不能遍历到不可枚举属性。可以通过Object.getOwnPropertyNames()方法访问到不可枚举属性(最后一小问没有回答出来)。

react中的事件跟js原生的事件有什么区别? 答:react中的事件是合成事件,通过事件冒泡的原理绑定在根元素上。普通的事件时绑定在目标元素上。

事件捕获和事件冒泡机制。 答:在一个有层次的多个元素之间,事件会先经过捕获阶段,捕获阶段是从最顶层元素一直到目标元素。当捕获阶段结束之后事件会从目标元素向底层元素进行传递也就是冒泡阶段。具体细节可以参考《javascript 高级程序设计》的第十三章事件流。

说一下对Promise的理解。Promise有哪些常用的静态方法?Promise.all()方法的作用是什么?可以传入哪些类型的参数? 答:Promise是一个构造函数,实例化的过程中可以传入一个函数,这个函数有两个参数。在函数内部可以通过resolve、reject来修改Promise的状态,状态发生变化后会在当前事件队列的末尾去执行then或者catch里面的方法。常用的静态方法有Promise.all、Promise.race、Promise.resolve、Promise.reject等。Promise.all方法可以传入一个数组,数组中的每一项都是一个Promise实例,只有数组中所有的Promise的状态都是成功时才会去改变Promise.all方法对应的Promise状态。Promise.all方法除了可以传入数组还可以传入所有具有iterator的对象。具体可以参考阮老师的es6入门Promise。

正则表达式有哪些常用的符号?略

列举常用的数组方法,哪些方法会改变原数组?略

for of可以遍历哪些数据类型? 答:可以遍历具有iterator接口的对象。可以参考阮老师的es6入门Iterator 和 for…of 循环

CSS中overflow有哪些属性值?分别是什么作用?默认值是什么?略

webpack中有哪些常用的loader?css-loader与style-loader的作用分别是什么? 答:常用的有css-loader、babel-loader、vue-loader、style-loader、url-loader等。css-loader是用来解析css文件的,因为webpack会将所有的东西都当成是模块,但是没有办法去解析css文件以及分析css文件中的依赖项所以需要css-loader去进行分析。style-loader会将通过css-loader编译好的模块提取出来通过style标签的形式插入到html文件中。

webpack中有哪些常用的plugin?怎么做代码分割? 答:由于我用的webpack3.x的版本,所以回答的也是该版本中一些常用的plugin。常用的有htmlWebpackPlugin、extractTextPlugin、commonChunkPlugin等。

简要描述js的事件循环。 答:可以参考事件循环

简要描述浏览器的渲染原理。 答:我就简单说了说浏览器的渲染过程和一些概念:DOM树、CSSOM树、render、paint。可以参考你真的了解回流和重绘吗?

浏览器发起请求的整个过程。 答:这是一道老生常谈的题了,从DNS解析到三次握手到发送请求报文到服务端响应,具体答案可以自行百度。

常用的http请求头和响应头。与缓存相关的有哪些?http1.0与http1.1中关于缓存有些什么区别? 答:可以参考彻底弄懂HTTP缓存机制及原理

常用的http响应状态码。分别表示什么意思? 答:2xx、3xx、4xx、5xx

谈谈对websocket的理解。有哪些替代方案? 答:我对webscoket的理解比较有限,只知道是用来做全双工通讯的,是一个持久连接。建立连接的过程其实是通过http协议进行的,连接完成之后通过upgrade字段进行了协议升级,修改为websocket协议,该协议的请求头数据量比较少。当时回答的替代方案是ajax轮询和服务端推送,具体的推送方案不清楚。后来查了一些资料做了一点了解。可以参考《图解HTTP》这本书和《JavaScript高级程序设计》的第二十一章,里面提到了comet、SSE两种方案。

TCP与UDP的区别。 答:理解的不多,只知道TCP是可靠传输UDP是不可靠传输。

常用的web性能优化有哪些手段? 答:这道题我主要从http请求和页面渲染两个方面做得解答,http请求上主要是将代码分割,进行代码压缩,gZip编码,路由懒加载等一些手段来完成优化。页面渲染上主要涉及到DOM操作,减少重排、读写分离、动画上帧率跟浏览器的刷新频率保持一致。可以参考一下阮老师的博客网页性能管理详解

说一下作用域链。原型链。 答:说的主要是《JavaScript高级程序设计》这本书上的内容,说到原型链我一般会画一张原型链关系图。可以参考我写的一篇博客js总结系列(三)原型链

为什么0.1 + 0.2 === 0.3是false? 答:这道题我主要是说了一下小数在内存中的存储方案,取的是一个近似值导致的精度丢失。

如何实现js的继承?你说的这些继承方式各自有什么缺点?如何实现完美继承? 答:构造函数继承、原型链继承、组合继承、完美继承。这些都是高程中的内容,可以照搬。

常用的设计模式有哪些?分别有哪些应用场景? 答:对设计模式总结的比较少,回答的时候说到了单例模式:用来做全屏遮罩或一些模态框;观察者模式:举了vue中实现数据绑定的例子;装饰者模式:用来扩展对象;工厂模式:举了jQuery中生成jQuery对象的例子。大家可以专门做个总结。

如何实现一个可以设置过期时间的localstorage存储? 答:这题写了两三版,第一版考虑到的问题很少。在面试官的提示之下才有较高的完成度。主要是提供两个方法set和get,set的时候不仅要存储内容还需要存储过期时间,然后在get方法中判断是否已经过期。当然还有一些优化手段。

为什么会有跨域问题?常用的解决方案有哪些? 答:直接上阮老师博客浏览器同源政策及其规避方法、跨域资源共享 CORS 详解

常见的一些web安全问题 答:XSS、CSRF

let和var有哪些区别?略

new关键字有什么作用?如何实现一个new关键字的方法?略

外层div中有两个子元素,如何通过flex布局实现两个子元素垂直居中,左右分别顶到两边的布局?略

如何通过定位的方式实现一个不确定宽高元素的垂直水平居中?略

使用过node吗?主要做什么? 答:服务端node使用较少,主要是用来做一些打包时候的自定义功能脚本。平时做一些代理服务器啥的。后端的话主要是demo水平。

express和koa有什么区别? 答:了解的不多,主要是从回调的处理和中间件的使用不同两个方面

知道三次握手和四次挥手吗? 答:略

谈谈你对闭包的理解。 答:大家还是自行百度比较好。

虚拟DOM是什么?了解diff算法吗? 答:虚拟DOM使用js对象来模拟DOM树的结构。js对象中有标签名、属性、子元素。具体细节大家自行百度吧,比我说的专业。

vue和react中循环生成元素时的key有什么作用? 答:也是从diff算法的角度来说的,循环的时候key是虚拟DOM的唯一标志符,可以节约性能。

DNS解析过程 答:浏览器缓存、操作系统配置文件、DNS服务器

window.onload和document.ready有什么区别? 答:window.onload是页面多有的元素的已经渲染完成包括image等。document.ready是DOM元素渲染完成,一些图片请求并不一定已经完成。

移动端1px问题产生的原因是什么?有什么解决方案? 答:直接上文章移动端 1px 像素问题及解决办法

rem的原理?还有哪些移动端布局方案? 答:说了一下根据屏幕宽度进行动态计算然后给html元素这是fontSize。其他的方案主要说了一下响应式、vw、vh、百分比布局等。

移动端为什么click事件会延迟300ms?如何禁止屏幕的缩放? 答:主要是iPhone为了判断用户是否发生了双击。禁止缩放通过设置视口的缩放比例。

PC、移动端、微信小程序开发你会分别选用什么框架?说明你的理由。 答:我给出的答案是PC业务场景复杂的情况下选用react,因为函数编程更加灵活;移动端选用vue,一般来说移动端场景不会很复杂,vue比较轻量化;小程序选用vue,有较为完善的框架。

了解SSR吗?有什么好处? 答:没用过,大概结合了node的服务端渲染说了一下自己的理解,好处是首屏性能和SEO

怎么判断一个数据的类型? 答:Object.property.toString.call(obj)

说一下vue的生命周期钩子?vue-router有哪些钩子?优先级是怎么样的?略

对于秒杀类的业务怎么确保倒计时的准确性? 答:随便想了想,我说可以在活动开始前的某个时间点发送一个请求获取服务端时间。现在想想好像也不太理想,感觉需要在初始化页面的时候服务端就返回一个相对的时间而不是绝对时间。

接口返回了一个非常庞大的数据怎么渲染到页面上? 答:面试官提到了数据层级很深,我提到了数据缓存、分页渲染、数据扁平化等一些手段。

常用的异步处理方案及它们的一些优缺点。 答:主要说了回调函数、Promise、generator、async/await

原生js给一个元素绑定事件有哪些形式?有什么区别? 答:onclick 和 addEventListener。前者只能绑定一次,多次绑定会发生覆盖,后者可以绑定多个事件处理函数,不会发生覆盖。

前端优质面试真题

1、什么是防抖和节流?有什么区别?如何实现? 参考答案 防抖

触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间

思路: 每次触发事件时都取消之前的延时调用方法

function debounce(fn) { let timeout = null; // 创建一个标记用来存放定时器的返回值 return function () { clearTimeout(timeout); // 每当用户输入的时候把前一个 setTimeout clear 掉 timeout = setTimeout(() => { // 然后又创建一个新的 setTimeout, 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数 fn.apply(this, arguments); }, 500); }; } function sayHi() { console.log(‘防抖成功’); }

var inp = document.getElementById('inp');
inp.addEventListener('input', debounce(sayHi)); // 防抖

节流

高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率

思路: 每次触发事件时都判断当前是否有等待执行的延时函数

function throttle(fn) { let canRun = true; // 通过闭包保存一个标记 return function () { if (!canRun) return; // 在函数开头判断标记是否为true,不为true则return canRun = false; // 立即设置为false setTimeout(() => { // 将外部传入的函数的执行放在setTimeout中 fn.apply(this, arguments); // 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。当定时器没有执行的时候标记永远是false,在开头被return掉 canRun = true; }, 500); }; } function sayHi(e) { console.log(e.target.innerWidth, e.target.innerHeight); } window.addEventListener(‘resize’, throttle(sayHi)); 2、 get请求传参长度的误区、get和post请求在缓存方面的区别 误区:我们经常说get请求参数的大小存在限制,而post请求的参数大小是无限制的。

参考答案 实际上HTTP 协议从未规定 GET/POST 的请求长度限制是多少。对get请求参数的限制是来源与浏览器或web服务器,浏览器或web服务器限制了url的长度。为了明确这个概念,我们必须再次强调下面几点:

HTTP 协议 未规定 GET 和POST的长度限制 GET的最大长度显示是因为 浏览器和 web服务器限制了 URI的长度 不同的浏览器和WEB服务器,限制的最大长度不一样 要支持IE,则最大长度为2083byte,若只支持Chrome,则最大长度 8182byte 补充补充一个get和post在缓存方面的区别:

get请求类似于查找的过程,用户获取数据,可以不用每次都与数据库连接,所以可以使用缓存。 post不同,post做的一般是修改和删除的工作,所以必须与数据库交互,所以不能使用缓存。因此get请求适合于请求缓存。 3、模块化发展历程 可从IIFE、AMD、CMD、CommonJS、UMD、webpack(require.ensure)、ES Module、<script type="module"> 这几个角度考虑。

参考答案 模块化主要是用来抽离公共代码,隔离作用域,避免变量冲突等。

IIFE:使用自执行函数来编写模块化,特点:在一个单独的函数作用域中执行代码,避免变量冲突。

(function(){ return { data:[] } })() AMD:使用requireJS 来编写模块化,特点:依赖必须提前声明好。

define(’./index.js’,function(code){ // code 就是index.js 返回的内容 }) CMD:使用seaJS 来编写模块化,特点:支持动态引入依赖文件。

define(function(require, exports, module) {
var indexCode = require(’./index.js’); }) CommonJS:nodejs 中自带的模块化。

var fs = require(‘fs’); UMD:兼容AMD,CommonJS 模块化语法。

webpack(require.ensure):webpack 2.x 版本中的代码分割。

ES Modules:ES6 引入的模块化,支持import 来引入另一个 js 。

import a from ‘a’; 4、npm 模块安装机制,为什么输入 npm install 就可以自动安装对应的模块? 参考答案

  1. npm 模块安装机制: 发出npm install命令 查询node_modules目录之中是否已经存在指定模块 npm 向 registry 查询模块压缩包的网址 下载压缩包,存放在根目录下的.npm目录里 解压压缩包到当前项目的node_modules目录 若存在,不再重新安装 若不存在
  2. npm 实现原理 输入 npm install 命令并敲下回车后,会经历如下几个阶段(以 npm 5.5.1 为例):

执行工程自身 preinstall 当前 npm 工程如果定义了 preinstall 钩子此时会被执行。 确定首层依赖模块 首先需要做的是确定工程中的首层依赖,也就是 dependencies 和 devDependencies 属性中直接指定的模块(假设此时没有添加 npm install 参数)。工程本身是整棵依赖树的根节点,每个首层依赖模块都是根节点下面的一棵子树,npm 会开启多进程从每个首层依赖模块开始逐步寻找更深层级的节点。 获取模块 获取模块是一个递归的过程,分为以下几步: 获取模块信息。在下载一个模块之前,首先要确定其版本,这是因为 package.json 中往往是 semantic version(semver,语义化版本)。此时如果版本描述文件(npm-shrinkwrap.json 或 package-lock.json)中有该模块信息直接拿即可,如果没有则从仓库获取。如 packaeg.json 中某个包的版本是 ^1.1.0,npm 就会去仓库中获取符合 1.x.x 形式的最新版本。 获取模块实体。上一步会获取到模块的压缩包地址(resolved 字段),npm 会用此地址检查本地缓存,缓存中有就直接拿,如果没有则从仓库下载。 查找该模块依赖,如果有依赖则回到第1步,如果没有则停止。 模块扁平化(dedupe) 上一步获取到的是一棵完整的依赖树,其中可能包含大量重复模块。比如 A 模块依赖于 loadsh,B 模块同样依赖于 lodash。在 npm3 以前会严格按照依赖树的结构进行安装,因此会造成模块冗余。从 npm3 开始默认加入了一个 dedupe 的过程。它会遍历所有节点,逐个将模块放在根节点下面,也就是 node-modules 的第一层。当发现有重复模块时,则将其丢弃。 这里需要对重复模块进行一个定义,它指的是模块名相同且 semver 兼容。每个 semver 都对应一段版本允许范围,如果两个模块的版本允许范围存在交集,那么就可以得到一个兼容版本,而不必版本号完全一致,这可以使更多冗余模块在 dedupe 过程中被去掉。 比如 node-modules 下 foo 模块依赖 lodash@^1.0.0,bar 模块依赖 lodash@^1.1.0,则 ^1.1.0 为兼容版本。 而当 foo 依赖 lodash@^2.0.0,bar 依赖 lodash@^1.1.0,则依据 semver 的规则,二者不存在兼容版本。会将一个版本放在 node_modules 中,另一个仍保留在依赖树里。举个例子,假设一个依赖树原本是这样:node_modules – foo ---- lodash@version1– bar ---- lodash@version2假设 version1 和 version2 是兼容版本,则经过 dedupe 会成为下面的形式:node_modules – foo-- bar-- lodash(保留的版本为兼容版本)假设 version1 和 version2 为非兼容版本,则后面的版本保留在依赖树中:node_modules – foo – lodash@version1– bar ---- lodash@version2 安装模块 这一步将会更新工程中的 node_modules,并执行模块中的生命周期函数(按照 preinstall、install、postinstall 的顺序)。 执行工程自身生命周期 当前 npm 工程如果定义了钩子此时会被执行(按照 install、postinstall、prepublish、prepare 的顺序)。最后一步是生成或更新版本描述文件,npm install 过程完成。 5、ES5的继承和ES6的继承有什么区别? 参考答案 ES5的继承时通过prototype或构造函数机制来实现。ES5的继承实质上是先创建子类的实例对象,然后再将父类的方法添加到this上(Parent.apply(this))。

ES6的继承机制完全不同,实质上是先创建父类的实例对象this(所以必须先调用父类的super()方法),然后再用子类的构造函数修改this。

具体的:ES6通过class关键字定义类,里面有构造方法,类之间通过extends关键字实现继承。子类必须在constructor方法中调用super方法,否则新建实例报错。因为子类没有自己的this对象,而是继承了父类的this对象,然后对其进行加工。如果不调用super方法,子类得不到this对象。

ps:super关键字指代父类的实例,即父类的this对象。在子类构造函数中,调用super后,才可使用this关键字,否则报错。

6、setTimeout、Promise、Async/Await 的区别 参考答案

7、定时器的执行顺序或机制? 参考答案 **因为js是单线程的,浏览器遇到setTimeout或者setInterval会先执行完当前的代码块,在此之前会把定时器推入浏览器的待执行事件队列里面,等到浏览器执行完当前代码之后会看一下事件队列里面有没有任务,有的话才执行定时器的代码。**所以即使把定时器的时间设置为0还是会先执行当前的一些代码。

function test(){ var aa = 0; var testSet = setInterval(function(){ aa++; console.log(123); if(aa<10){ clearInterval(testSet); } },20); var testSet1 = setTimeout(function(){ console.log(321) },1000); for(var i=0;i<10;i++){ console.log(‘test’); } } test() 输出结果:

test //10次 undefined 123 321 8、[‘1’,‘2’,‘3’].map(parseInt) 输出什么,为什么? 参考答案 输出:[1, NaN, NaN]

首先让我们回顾一下,map函数的第一个参数callback: var new_array = arr.map(function callback(currentValue[, index[, array]]) { // Return element for new_array }[, thisArg])这个callback一共可以接收三个参数,其中第一个参数代表当前被处理的元素,而第二个参数代表该元素的索引。

而parseInt则是用来解析字符串的,使字符串成为指定基数的整数。parseInt(string, radix)接收两个参数,第一个表示被处理的值(字符串),第二个表示为解析时的基数。 了解这两个函数后,我们可以模拟一下运行情况 parseInt(‘1’, 0) //radix为0时,且string参数不以“0x”和“0”开头时,按照10为基数处理。这个时候返回1 parseInt(‘2’, 1) //基数为1(1进制)表示的数中,最大值小于2,所以无法解析,返回NaN parseInt(‘3’, 2) //基数为2(2进制)表示的数中,最大值小于3,所以无法解析,返回NaN map函数返回的是一个数组,所以最后结果为[1, NaN, NaN] 9、Doctype作用? 严格模式与混杂模式如何区分?它们有何意义? 参考答案 Doctype声明于文档最前面,告诉浏览器以何种方式来渲染页面,这里有两种模式,严格模式和混杂模式。

严格模式的排版和 JS 运作模式是 以该浏览器支持的最高标准运行。 混杂模式,向后兼容,模拟老式浏览器,防止浏览器无法兼容页面。 10、fetch发送2次请求的原因 参考答案 fetch发送post请求的时候,总是发送2次,第一次状态码是204,第二次才成功?

原因很简单,因为你用fetch的post请求的时候,导致fetch 第一次发送了一个Options请求,询问服务器是否支持修改的请求头,如果服务器支持,则在第二次中发送真正的请求。

location.href-- 返回或设置当前文档的URL location.search – 返回URL中的查询字符串部分。例如 http://www.dreamdu.com/dreamd… 返回包括(?)后面的内容?id=5&name=dreamdu location.hash – 返回URL#后面的内容,如果没有#,返回空 location.host – 返回URL中的域名部分,例如http://www.dreamdu.com location.hostname – 返回URL中的主域名部分,例如http://dreamdu.com location.pathname – 返回URL的域名后的部分。例如 http://www.dreamdu.com/xhtml/ 返回/xhtml/ location.port – 返回URL中的端口部分。例如 http://www.dreamdu.com:8080/xhtml/ 返回8080 location.protocol – 返回URL中的协议部分。例如 http://www.dreamdu.com:8080/xhtml/ 返回(//)前面的内容http: location.assign – 设置当前文档的URL location.replace() – 设置当前文档的URL,并且在history对象的地址列表中移除这个URL location.replace(url); location.reload() – 重载当前页面 history对象

history.go() – 前进或后退指定的页面数 history.go(num); history.back() – 后退一页 history.forward() – 前进一页 Navigator对象

navigator.userAgent – 返回用户代理头的字符串表示(就是包括浏览器版本信息等的字符串) navigator.cookieEnabled – 返回浏览器是否支持(启用)cookie 6、Cookie、sessionStorage、localStorage的区别 参考答案 共同点:都是保存在浏览器端,并且是同源的

Cookie:cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。而sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下,存储的大小很小只有4K左右。(key:可以在浏览器和服务器端来回传递,存储容量小,只有大约4K左右) sessionStorage:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保持,localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。(key:本身就是一个回话过程,关闭浏览器后消失,session为一个回话,当页面不同即使是同一页面打开两次,也被视为同一次回话) localStorage:localStorage 在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的。(key:同源窗口都会共享,并且不会失效,不管窗口或者浏览器关闭与否都会始终生效) 补充说明一下cookie的作用:

保存用户登录状态。例如将用户id存储于一个cookie内,这样当用户下次访问该页面时就不需要重新登录了,现在很多论坛和社区都提供这样的功能。cookie还可以设置过期时间,当超过时间期限后,cookie就会自动消失。因此,系统往往可以提示用户保持登录状态的时间:常见选项有一个月、三个 月、一年等。 跟踪用户行为。例如一个天气预报网站,能够根据用户选择的地区显示当地的天气情况。如果每次都需要选择所在地是烦琐的,当利用了 cookie后就会显得很人性化了,系统能够记住上一次访问的地区,当下次再打开该页面时,它就会自动显示上次用户所在地区的天气情况。因为一切都是在后 台完成,所以这样的页面就像为某个用户所定制的一样,使用起来非常方便 定制页面。如果网站提供了换肤或更换布局的功能,那么可以使用cookie来记录用户的选项,例如:背景色、分辨率等。当用户下次访问时,仍然可以保存上一次访问的界面风格。 7、Cookie如何防范XSS攻击 参考答案 XSS(跨站脚本攻击)是指攻击者在返回的HTML中嵌入javascript脚本,为了减轻这些攻击,需要在HTTP头部配上,set-cookie:

httponly-这个属性可以防止XSS,它会禁止javascript脚本来访问cookie。 secure - 这个属性告诉浏览器仅在请求为https的时候发送cookie。 结果应该是这样的:Set-Cookie=…

8、浏览器和 Node 事件循环的区别? 参考答案 其中一个主要的区别在于浏览器的event loop 和nodejs的event loop 在处理异步事件的顺序是不同的,nodejs中有micro event;其中Promise属于micro event 该异步事件的处理顺序就和浏览器不同.nodejs V11.0以上 这两者之间的顺序就相同了.

function test () { console.log(‘start’) setTimeout(() => { console.log(‘children2’) Promise.resolve().then(() => {console.log(‘children2-1’)}) }, 0) setTimeout(() => { console.log(‘children3’) Promise.resolve().then(() => {console.log(‘children3-1’)}) }, 0) Promise.resolve().then(() => {console.log(‘children1’)}) console.log(‘end’) }

test()

// 以上代码在node11以下版本的执行结果(先执行所有的宏任务,再执行微任务) // start // end // children1 // children2 // children3 // children2-1 // children3-1

// 以上代码在node11及浏览器的执行结果(顺序执行宏任务和微任务) // start // end // children1 // children2 // children2-1 // children3 // children3-1 9、简述HTTPS中间人攻击 参考答案 https协议由 http + ssl 协议构成,具体的链接过程可参考SSL或TLS握手的概述

中间人攻击过程如下:

服务器向客户端发送公钥。 攻击者截获公钥,保留在自己手上。 然后攻击者自己生成一个【伪造的】公钥,发给客户端。 客户端收到伪造的公钥后,生成加密hash值发给服务器。 攻击者获得加密hash值,用自己的私钥解密获得真秘钥。 同时生成假的加密hash值,发给服务器。 服务器用私钥解密获得假秘钥。 服务器用加秘钥加密传输信息 防范方法:

服务端在发送浏览器的公钥中加入CA证书,浏览器可以验证CA证书的有效性 10、说几条web前端优化策略 参考答案 (1). 减少HTTP请求数

这条策略基本上所有前端人都知道,而且也是最重要最有效的。都说要减少HTTP请求,那请求多了到底会怎么样呢?首先,每个请求都是有成本的,既包 含时间成本也包含资源成本。一个完整的请求都需要经过DNS寻址、与服务器建立连接、发送数据、等待服务器响应、接收数据这样一个“漫长”而复杂的过程。时间成本就是用户需要看到或者“感受”到这个资源是必须要等待这个过程结束的,资源上由于每个请求都需要携带数据,因此每个请求都需要占用带宽。

另外,由于浏览器进行并发请求的请求数是有上限的,因此请求数多了以后,浏览器需要分批进行请求,因此会增加用户的等待时间,会给 用户造成站点速度慢这样一个印象,即使可能用户能看到的第一屏的资源都已经请求完了,但是浏览器的进度条会一直存在。减少HTTP请求数的主要途径包括:

(2). 从设计实现层面简化页面

如果你的页面像百度首页一样简单,那么接下来的规则基本上都用不着了。保持页面简洁、减少资源的使用时最直接的。如果不是这样,你的页面需要华丽的皮肤,则继续阅读下面的内容。

(3). 合理设置HTTP缓存

缓存的力量是强大的,恰当的缓存设置可以大大的减少HTTP请求。以有啊首页为例,当浏览器没有缓存的时候访问一共会发出78个请求,共600多K 数据(如图1.1),而当第二次访问即浏览器已缓存之后访问则仅有10个请求,共20多K数据(如图1.2)。(这里需要说明的是,如果直接F5刷新页面 的话效果是不一样的,这种情况下请求数还是一样,不过被缓存资源的请求服务器是304响应,只有Header没有Body,可以节省带宽)

怎样才算合理设置?原则很简单,能缓存越多越好,能缓存越久越好。例如,很少变化的图片资源可以直接通过HTTP Header中的Expires设置一个很长的过期头;变化不频繁而又可能会变的资源可以使用Last-Modifed来做请求验证。尽可能的让资源能够 在缓存中待得更久。

(4). 资源合并与压缩

如果可以的话,尽可能的将外部的脚本、样式进行合并,多个合为一个。另外,CSS、Javascript、Image都可以用相应的工具进行压缩,压缩后往往能省下不少空间。

(5). CSS Sprites

合并CSS图片,减少请求数的又一个好办法。

(6). Inline Images

使用data: URL scheme的方式将图片嵌入到页面或CSS中,如果不考虑资源管理上的问题的话,不失为一个好办法。如果是嵌入页面的话换来的是增大了页面的体积,而且无法利用浏览器缓存。使用在CSS中的图片则更为理想一些。

(7). Lazy Load Images

这条策略实际上并不一定能减少HTTP请求数,但是却能在某些条件下或者页面刚加载时减少HTTP请求数。对于图片而言,在页面刚加载的时候可以只 加载第一屏,当用户继续往后滚屏的时候才加载后续的图片。这样一来,假如用户只对第一屏的内容感兴趣时,那剩余的图片请求就都节省了。有啊首页曾经的做法 是在加载的时候把第一屏之后的图片地址缓存在Textarea标签中,待用户往下滚屏的时候才“惰性”加载。

回到顶部