前端面试题合集

您所在的位置:网站首页 etag算法 前端面试题合集

前端面试题合集

#前端面试题合集| 来源: 网络整理| 查看: 265

前端面试题合集-第一篇

🔔每周不定时更新!

⛄不要让自己失去竞争力!

☀️哪里都不是避风港,保持竞争力!

1. CSS选择器的优先级

!important>内联>id选择器>类选择器>标签选择器>通配符选择器>继承

在同一组属性设置表中有!important规则的优先级最大

2. 如何实现左侧宽度固定,右侧宽度自适应的布局

标签结构:

左侧固定宽度 右侧自适应 方法一:浮动 .way_1 #box .left { float: left; width: 100px; height: 100%; font-size: 12px; background-color: pink; } .way_1 #box .right { height: 100%; font-size: 12px; background-color: skyblue; } 方法二:flex .way_2 #box { display: flex; } .way_2 #box .left { width: 100px; height: 100%; font-size: 12px; background-color: pink; } .way_2 #box .right { flex: 1; height: 100%; font-size: 12px; background-color: skyblue; } 方法三:grid布局 .way_3 #box { display: grid; overflow: hidden; /* 属性定义每一列的列宽 */ grid-template-columns: 100px 100%; /* 属性定义每一列的行高 */ grid-template-rows: 300px; } .way_3 #box .left { width: 100px; height: 100%; font-size: 12px; background-color: pink; } .way_3 #box .right { height: 100%; font-size: 12px; background-color: skyblue; } 方法四:利用calc计算宽度 .way_4 #box { height: 300px; } .way_4 #box .left { width: 100px; height: 100%; float: left; font-size: 12px; background-color: pink; } .way_4 #box .right { width: calc(100% - 100px); float: right; height: 100%; font-size: 12px; background-color: skyblue; } 3.对跨域的了解 跨域行为 同源策略,安全性考虑 协议,IP和端口不一致都是跨域行为 跨域的几种解决方案

链接一

CORS(跨域资源共享) 1. 什么是cors 浏览器端回自动向请求头添加origin字段,表明当前请求来源。 服务器端需要设置响应头的Access-Control-Allow-Methods,Access-Control-Allow-Headers,Access-Control-Allow-Origin等字段,指定允许的方法,头部,源等信息。 请求分为简单请求和非简单请求,非简单请求会先进行一次OPTION方法进行预检,看是否允许当前跨域请求。 2. 后端的响应头信息 Access-Control-Allow-Origin:该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个 * ,标识接受任意域名的请求。 Access-Control-Allow-Credentials:该字段可选,值是布尔值,表示是否允许发送cookie。 Access-Control-Expose-Headers:该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma。如果想要拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。 4.HTTP2和HTTP1的不同

相对于HTTP1.0,HTTP1.1的优化:

缓存处理,多了Entity tag ,if-Unmodified-Since, if-Match等缓存信息。 带宽优化以及网络连接的使用 错误通知的管理 Host头的处理 长连接: HTTP1.1中默认开启Connetion:keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。

** 相对于HTTP1.1,HTTP2的优化:**

HTTP2支持二进制传送,HTTP1.x是字符串传送 HTTP2支持多路复用 HTTP2采用 HPACK压缩算法压缩头部,减少了传输体积 HTTP2支持服务端推送。 5.你了解缓存吗 graph LR A[缓存] B(强缓存) C(协商缓存) A --优先级高--> B A -.优先级低.-> C

当执行强缓存时,若缓存命中,则直接使用缓存数据库中的数据,不再进行缓存协商。

1.强缓存

Expires(HTTP1.0): Exprires的值为服务端返回的数据到期时间。当再次请求时的请求小于返回的此时间,则直接使用缓存数据。但由于服务端时间和客户端时间可能有误差,这也将导致缓存命中的误差。另一方面,Expires是HTTP1.0产物,故现在大多数使用Cache-Control替代。

缺点:使用的是绝对时间,如果服务端和客户端的时间产生偏差,那么会导致命中缓存产生偏差。

Cache-Control(HTTP1.1):有很多属性,不同的属性代表的意义也不同

private:客户端可以缓存 Public:客户端和代理服务器都可以缓存 max-age=t:缓存内容将在t秒后失效 no-chche:需要使用协商缓存来验证缓存数据 no-store:所有内容都不会缓存

请注意no-cache指令很多人误以为是不缓存,这是不准确的,no-cache的意思是可以缓存,但每次用应该去让服务器验证缓存是否可用。no-store才是不缓存内容。当在首部字段Cache-Control 有指定 max-age 指令时,比起首部字段 Expires,会优先处理 max-age 指令。命中强缓存的表现形式:Firefox浏览器表现为一个灰色的200状态码。Chrome浏览器状态码表现为200 (from disk cache)或是200 OK (from memory cache)

2.协商缓存

协商缓存需要进行对比判断是否可以使用缓存。浏览器第一次请求数据时,服务器会将缓存标识与数据一起响应给客户端,客户端将它们备份至缓存中。再次请求时,客户端会将缓存中的标识发送给服务器,服务器根据此标识判断。若未失效,返回304状态码,浏览器拿到此状态码就可以直接使用缓存数据了

Last-Modified:服务器在响应请求时,会告诉浏览器资源的最后修改时间。 if-Modified-Since:浏览器再次请求服务器的时候,请求头会包含此字段,后面跟着在缓存中获得的最后修改时间。服务端收到此请求头发现有if-Modified-Since,则与被请求资源的最后修改时间进行对比,如果一致则返回304和响应报文头,浏览器只需要从缓存中获取信息即可 如果真的被修改:那么开始传输响应一个整体,服务器返回:200 OK 如果没有被修改:那么只需传输响应header,服务器返回:304 Not Modified if-Unmodified-Since: 从某个时间点算起, 是否文件没有被修改,使用的是相对时间,不需要关心客户端和服务端的时间偏差 如果没有被修改:则开始`继续'传送文件,服务器返回: 200 OK 如果文件被修改:则不传输,服务器返回:412 Precondition filed(预处理失败)

这两个的区别是一个是修改了才下载一个是没修改才下载。如果在服务器上,一个资源被修改了,但其实际内容根本没发生改变,会因为Last-Modified时间匹配不上而返回了整个实体给客户端(即使客户端缓存里有个一模一样的资源)。为了解决这个问题,HTTP1.1推出了Etag

Etag:服务器响应请求时,通过此字段告诉浏览器当前资源在服务器生成的唯一标识(生成规则由服务器决定) If-Match:条件请求,携带上一次请求中资源的ETag,服务器根据这个字段判断文件是否有新的修改 If-None-Match: 再次请求服务器时,浏览器的请求报文头部会包含此字段,后面的值为在缓存中获取的标识。服务器接收到次报文后发现If-None-Match则与被请求资源的唯一标识进行对比 不同,说明资源被改动过,则响应整个资源内容,返回状态码200。 相同,说明资源无心修改,则响应header,浏览器直接从缓存中获取数据信息。返回状态码304.

实际应用中由于Etag的计算是使用算法来的得出的,而算法会占用服务端计算资源,所有服务端的资源都是包贵的,所有很少使用Etag了。

浏览器地址中写入URL,回车浏览器发现缓存中有这个文件,不用继续请求了,直接去缓存拿(最快) F5就是告诉浏览器,不要再偷懒啦,去看看这个文件是不是过期了,别老拿过期的东西糊弄我。于是浏览器一个请求带上If-Mondify-since. Ctrl+F5告诉浏览器,把缓存中的文件删除,然后再去服务器请求个完整的资源文件来。于是客户端完成了强行更新的操作。 3.缓存场景

大部分的场景都可以使用缓存配合协商缓存解决,但是在特殊地方可能需要特殊的缓存策略。

对于某些不需要缓存的资源,可以使用Cache-contrlo:no-store,表示该资源不需要缓存。 对于频繁变动的资源,可以使用Cache-Control:no-cache并配合ETag使用,表示该资源已被缓存,但每次都会发送请求询问资源是否更新。 对于代码文件来说,通常使用Cache-Control:max-age=< seconds >并配合策略缓存使用。 6. 首屏加载优化方案 Vue-Router路由懒加载(利用Webpack的代码切割) { path: '/about', name: 'about', // 动态注册路由 component: () => import('../views/AboutView.vue') } 使用CDN加速,将通用的库从vendor进行抽离 Nginx的gzip压缩

在http块中或者单个server块里添加后重启nginx nginx(centOS)一般都安装在 usr/local/nginx/sbin

./nginx -s reload #开启gzip gzip on; #低于1kb的资源不压缩 gzip_min_length 1k; #压缩级别1-9,越大压缩率越高,同时消耗cpu资源也越多,建议设置在5左右。 gzip_comp_level 5; #需要压缩哪些响应类型的资源,多个空格隔开。不建议压缩图片. gzip_types text/plain application/javascript application/x-javascript text/javascript text/xml text/css; #配置禁用gzip条件,支持正则。此处表示ie6及以下不启用gzip(因为ie低版本不支持) gzip_disable "MSIE [1-6]\."; #是否添加“Vary: Accept-Encoding”响应头 gzip_vary on; Vue异步组件 服务端渲染SSR 如果使用了一些UI库,采用按需加载 Webpack开启gzip压缩 如果首屏为登录页,可以做成多入口 Service Worker缓存文件处理 使用link标签的rel属性设置 prefetch(这段资源将会在未来某个导航或者功能要用到,但是本资源的下载顺序权重比较低,prefetch通常用于加速下一次导航)、preload(preload将会把资源得下载顺序权重提高,使得关键数据提前下载好,优化页面打开速度) 7. Event Loop 为什么会有事件循环?

JavaScript的一大特点就是单线程,但单线程就导致很多任务需要排队,如果中间某个执行时间太长,就容器造成堵塞,为了提高效率加了事件循环机制。

JavaScript单线程任务被分为同步任务和异步任务

从上面流程图中可以看到,主线程不断从任务队列中读取事件,这个过程是循环不断的,这种运行机制就叫做Event Loop(事件循环)!

在JavaScript中,除了广义的同步任务和异步任务,还可以分为宏任务和微任务。

宏任务和微任务的顺序流程图:

每次宏任务执行完毕后,检查微任务队列是否为空,如果不为空,会按照先入先出的规则全部执行完微任务后,清空微任务队列,再执行下一个宏任务,如此循环。

如何区分宏任务与微任务 宏任务:macrotask,又称为task, 可以理解为每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)。

一般包括:script(可以理解为外层同步代码)、setTimeout、setInterval 、setImmediate、I/O操作

微任务:microtask, 又称为job, 可以理解是在当前 task 执行结束后立即执行的任务。包括:Promise.then/cath /finally回调(平时常见的)、 MutationObserver回调(html5新特性)

在当前的微任务没有执行完成时,是不会执行下一个宏任务的。

案例一: console.log("start"); setTimeout(() => { console.log("children2") Promise.resolve().then(() =>{ console.log("children3") }) }, 0) new Promise(function(resolve, reject){ console.log("children4") setTimeout(function(){ console.log("children5") resolve("children6") }, 0) }).then(res =>{ console.log("children7") setTimeout(() =>{ console.log(res) }, 0) })

首先将整个script代码块作为一个宏任务执行,输出start

接着遇到setTimeout,0ms后将其回调函数放入宏任务队列。

接下来遇到Promise,由于Promise本身是立即执行函数,所以先输出children4。

3.1 在promise代码块里遇到setTimeout,将其放入宏任务队列中,整体代码执行完毕。

之后检查所有的微任务,没有微任务,所以第一次事件循环结束,开始第二轮。

执行第2步放入的宏任务,输出children2

5.1 遇到Promise,并直接调用了resolve,将.then回调加入到微任务队列中。

检查并执行所有微任务,输出children3,没有多余的微任务,所以第二轮事件结束,开始第三轮事件循环。

执行3.1中放入的宏任务输出children5,并调用了resolve,所以将后面的.then回调放入到微任务队列中。

检查并执行所有微任务,先输出children7,遇到setTimeout,将其加入到宏任务队列中,开始四轮事件循环。

执行第8加入的宏任务,输出children6,没有微任务,第四轮事件循环结束。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3