HTTP请求报文的是什么样的?
请求报?有4部分组成:
- 请求?
- 请求头部
- 空?
- 请求体
其中: (1)请求?包括:请求?法字段、URL字段、HTTP协议版本字段。它们?空格分隔。例如,GET /index.html HTTP/1.1。
(2)请求头部:请求头部由关键字/值对组成,每??对,关键字和值?英?冒号“:”分隔
- User-Agent:产?请求的浏览器类型。
- Accept:客户端可识别的内容类型列表。
- Host:请求的主机名,允许多个域名同处?个IP地址,即虚拟主机。
JSONP
JSONP 核心原理:script 标签不受同源策略约束,所以可以用来进行跨域请求,优点是兼容性好,但是只能用于 GET 请求;
const jsonp = ({ url, params, callbackName }) => {
const generateUrl = () => {
let dataSrchttps://www.it610.com/article/= ''
for (let key in params) {
if (params.hasOwnProperty(key)) {
dataSrc += `${key}=${params[key]}&`
}
}
dataSrc += `callback=${callbackName}`
return `${url}?${dataSrc}`
}
return new Promise((resolve, reject) => {
const scriptEle = document.createElement('script')
scriptEle.src = https://www.it610.com/article/generateUrl()
document.body.appendChild(scriptEle)
window[callbackName] = data => {
resolve(data)
document.removeChild(scriptEle)
}
})
}
事件传播机制(事件流)
冒泡和捕获
什么是HTTPS协议?
超文本传输安全协议(Hypertext Transfer Protocol Secure,简称:HTTPS)是一种通过计算机网络进行安全通信的传输协议。HTTPS经由HTTP进行通信,利用SSL/TLS来加密数据包。HTTPS的主要目的是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。 HTTP协议采用明文传输信息,存在信息窃听、信息篡改和信息劫持的风险,而协议TLS/SSL具有身份验证、信息加密和完整性校验的功能,可以避免此类问题发生。
安全层的主要职责就是对发起的HTTP请求的数据进行加密操作 和 对接收到的HTTP的内容进行解密操作。
伪元素和伪类的区别和作用?
- 伪元素:在内容元素的前后插入额外的元素或样式,但是这些元素实际上并不在文档中生成。它们只在外部显示可见,但不会在文档的源代码中找到它们,因此,称为“伪”元素。例如:
p::before {content:"第一章:";
}
p::after {content:"Hot!";
}
p::first-line {background:red;
}
p::first-letter {font-size:30px;
}
- 伪类:将特殊的效果添加到特定选择器上。它是已有元素上添加类别的,不会产生新的元素。例如:
a:hover {color: #FF00FF}
p:first-child {color: red}
总结: 伪类是通过在元素选择器上加?伪类改变元素状态,?伪元素通过对元素的操作进?对元素的改变。
setTimeout 模拟 setInterval
描述:使用
setTimeout
模拟实现setInterval
的功能。【滴滴前端二面面试题】实现:
const mySetInterval(fn, time) {
let timer = null;
const interval = () => {
timer = setTimeout(() => {
fn();
// time 时间之后会执行真正的函数fn
interval();
// 同时再次调用interval本身
}, time)
}
interval();
// 开始执行
// 返回用于关闭定时器的函数
return () => clearTimeout(timer);
}// 测试
const cancel = mySetInterval(() => console.log(1), 400);
setTimeout(() => {
cancel();
}, 1000);
// 打印两次1
行内元素有哪些?块级元素有哪些? 空(void)元素有那些?
- 行内元素有:
a b span img input select strong
; - 块级元素有:
div ul ol li dl dt dd h1 h2 h3 h4 h5 h6 p
;
- 常见的有:
、、
文章图片
文章图片
文章图片
文章图片
文章图片
文章图片
如何对项目中的图片进行优化?
- 不用图片。很多时候会使用到很多修饰类图片,其实这类修饰图片完全可以用 CSS 去代替。
- 对于移动端来说,屏幕宽度就那么点,完全没有必要去加载原图浪费带宽。一般图片都用 CDN 加载,可以计算出适配屏幕的宽度,然后去请求相应裁剪好的图片。
- 小图使用 base64 格式
- 将多个图标文件整合到一张图片中(雪碧图)
- 选择正确的图片格式:
- 对于能够显示 WebP 格式的浏览器尽量使用 WebP 格式。因为 WebP 格式具有更好的图像数据压缩算法,能带来更小的图片体积,而且拥有肉眼识别无差异的图像质量,缺点就是兼容性并不好
- 小图使用 PNG,其实对于大部分图标这类图片,完全可以使用 SVG 代替
- 照片使用 JPEG
(2) Chrome 浏览器内核:统称为 Chromium 内核或 Chrome 内核,以前是 Webkit 内核,现在是 Blink内核;
(3) Firefox 浏览器内核:Gecko 内核,俗称 Firefox 内核;
(4) Safari 浏览器内核:Webkit 内核;
(5) Opera 浏览器内核:最初是自己的 Presto 内核,后来加入谷歌大军,从 Webkit 又到了 Blink 内核;
(6) 360浏览器、猎豹浏览器内核:IE + Chrome 双内核;
(7) 搜狗、遨游、QQ 浏览器内核:Trident(兼容模式)+ Webkit(高速模式);
(8) 百度浏览器、世界之窗内核:IE 内核;
(9) 2345浏览器内核:好像以前是 IE 内核,现在也是 IE + Chrome 双内核了;
(10)UC 浏览器内核:这个众口不一,UC 说是他们自己研发的 U3 内核,但好像还是基于 Webkit 和 Trident ,还有说是基于火狐内核。
如何提?webpack的打包速度?
(1)优化 Loader 对于 Loader 来说,影响打包效率首当其冲必属 Babel 了。因为 Babel 会将代码转为字符串生成 AST,然后对 AST 继续进行转变最后再生成新的代码,项目越大,转换代码越多,效率就越低。当然了,这是可以优化的。
首先我们优化 Loader 的文件搜索范围
module.exports = { module: { rules: [ { // js 文件才使用 babel test: /\.js$/, loader: 'babel-loader', // 只在 src 文件夹下查找 include: [resolve('src')], // 不会去查找的路径 exclude: /node_modules/ } ] } }
对于 Babel 来说,希望只作用在 JS 代码上的,然后node_modules
中使用的代码都是编译过的,所以完全没有必要再去处理一遍。
当然这样做还不够,还可以将 Babel 编译过的文件缓存起来,下次只需要编译更改过的代码文件即可,这样可以大幅度加快打包时间
loader: 'babel-loader?cacheDirectory=true'
(2)HappyPack 受限于 Node 是单线程运行的,所以 Webpack 在打包的过程中也是单线程的,特别是在执行 Loader 的时候,长时间编译的任务很多,这样就会导致等待的情况。
HappyPack 可以将 Loader 的同步执行转换为并行的,这样就能充分利用系统资源来加快打包效率了
module: { loaders: [ { test: /\.js$/, include: [resolve('src')], exclude: /node_modules/, // id 后面的内容对应下面 loader: 'happypack/loader?id=happybabel' } ] }, plugins: [ new HappyPack({ id: 'happybabel', loaders: ['babel-loader?cacheDirectory'], // 开启 4 个线程 threads: 4 }) ]
(3)DllPlugin DllPlugin 可以将特定的类库提前打包然后引入。这种方式可以极大的减少打包类库的次数,只有当类库更新版本才有需要重新打包,并且也实现了将公共代码抽离成单独文件的优化方案。DllPlugin的使用方法如下:
// 单独配置在一个文件中 // webpack.dll.conf.js const path = require('path') const webpack = require('webpack') module.exports = { entry: { // 想统一打包的类库 vendor: ['react'] }, output: { path: path.join(__dirname, 'dist'), filename: '[name].dll.js', library: '[name]-[hash]' }, plugins: [ new webpack.DllPlugin({ // name 必须和 output.library 一致 name: '[name]-[hash]', // 该属性需要与 DllReferencePlugin 中一致 context: __dirname, path: path.join(__dirname, 'dist', '[name]-manifest.json') }) ] }
然后需要执行这个配置文件生成依赖文件,接下来需要使用DllReferencePlugin
将依赖文件引入项目中
// webpack.conf.js module.exports = { // ...省略其他配置 plugins: [ new webpack.DllReferencePlugin({ context: __dirname, // manifest 就是之前打包出来的 json 文件 manifest: require('./dist/vendor-manifest.json'), }) ] }
(4)代码压缩 在 Webpack3 中,一般使用UglifyJS
来压缩代码,但是这个是单线程运行的,为了加快效率,可以使用webpack-parallel-uglify-plugin
来并行运行UglifyJS
,从而提高效率。
在 Webpack4 中,不需要以上这些操作了,只需要将mode
设置为production
就可以默认开启以上功能。代码压缩也是我们必做的性能优化方案,当然我们不止可以压缩 JS 代码,还可以压缩 HTML、CSS 代码,并且在压缩 JS 代码的过程中,我们还可以通过配置实现比如删除console.log
这类代码的功能。
(5)其他 可以通过一些小的优化点来加快打包速度
resolve.extensions
:用来表明文件后缀列表,默认查找顺序是['.js', '.json']
,如果你的导入文件没有添加后缀就会按照这个顺序查找文件。我们应该尽可能减少后缀列表长度,然后将出现频率高的后缀排在前面resolve.alias
:可以通过别名的方式来映射一个路径,能让 Webpack 更快找到路径module.noParse
:如果你确定一个文件下没有其他依赖,就可以使用该属性让 Webpack 不扫描该文件,这种方式对于大型的类库很有帮助
强缓存:
- Expires
- Cache-Control
- Etag、If-None-Match
- Last-Modified、If-Modified-Since
全局的对象( global objects )或称标准内置对象,不要和 "全局对象(global object)" 混淆。这里说的全局的对象是说在
全局作用域里的对象。全局作用域中的其他对象可以由用户的脚本创建或由宿主程序提供。
标准内置对象的分类:
(1)值属性,这些全局属性返回一个简单值,这些值没有自己的属性和方法。例如 Infinity、NaN、undefined、null 字面量
(2)函数属性,全局函数可以直接调用,不需要在调用时指定所属对象,执行结束后会将结果直接返回给调用者。例如 eval()、parseFloat()、parseInt() 等
(3)基本对象,基本对象是定义或使用其他对象的基础。基本对象包括一般对象、函数对象和错误对象。例如 Object、Function、Boolean、Symbol、Error 等
(4)数字和日期对象,用来表示数字、日期和执行数学计算的对象。例如 Number、Math、Date
(5)字符串,用来表示和操作字符串的对象。例如 String、RegExp
(6)可索引的集合对象,这些对象表示按照索引值来排序的数据集合,包括数组和类型数组,以及类数组结构的对象。例如 Array
(7)使用键的集合对象,这些集合对象在存储数据时会使用到键,支持按照插入顺序来迭代元素。
例如 Map、Set、WeakMap、WeakSet
(8)矢量集合,SIMD 矢量集合中的数据会被组织为一个数据序列。
例如 SIMD 等
(9)结构化数据,这些对象用来表示和操作结构化的缓冲区数据,或使用 JSON 编码的数据。例如 JSON 等
(10)控制抽象对象
例如 Promise、Generator 等
(11)反射。例如 Reflect、Proxy
(12)国际化,为了支持多语言处理而加入 ECMAScript 的对象。例如 Intl、Intl.Collator 等
(13)WebAssembly
(14)其他。例如 arguments
总结: js 中的内置对象主要指的是在程序执行前存在全局作用域里的由 js 定义的一些全局值属性、函数和用来实例化其他对象的构造函数对象。一般经常用到的如全局变量值 NaN、undefined,全局函数如 parseInt()、parseFloat() 用来实例化对象的构造函数如 Date、Object 等,还有提供数学计算的单体内置对象如 Math 对象。
函数柯里化
什么叫函数柯里化?其实就是将使用多个参数的函数转换成一系列使用一个参数的函数的技术。还不懂?来举个例子。
function add(a, b, c) { return a + b + c } add(1, 2, 3) let addCurry = curry(add) addCurry(1)(2)(3)
现在就是要实现 curry 这个函数,使函数从一次调用传入多个参数变成多次调用每次传一个参数。
function curry(fn) { let judge = (...args) => { if (args.length == fn.length) return fn(...args) return (...arg) => judge(...args, ...arg) } return judge }
手写发布订阅
class EventListener { listeners = {}; on(name, fn) { (this.listeners[name] || (this.listeners[name] = [])).push(fn) } once(name, fn) { let tem = (...args) => { this.removeListener(name, fn) fn(...args) } fn.fn = tem this.on(name, tem) } removeListener(name, fn) { if (this.listeners[name]) { this.listeners[name] = this.listeners[name].filter(listener => (listener != fn && listener != fn.fn)) } } removeAllListeners(name) { if (name && this.listeners[name]) delete this.listeners[name] this.listeners = {} } emit(name, ...args) { if (this.listeners[name]) { this.listeners[name].forEach(fn => fn.call(this, ...args)) } } }
文档声明(Doctype)和有何作用? 严格模式与混杂模式如何区分?它们有何意义?
文档声明的作用: 文档声明是为了告诉浏览器,当前HTML
文档使用什么版本的HTML
来写的,这样浏览器才能按照声明的版本来正确的解析。
的作用:的作用就是让浏览器进入标准模式,使用最新的
HTML5
标准来解析渲染页面;如果不写,浏览器就会进入混杂模式,我们需要避免此类情况发生。
严格模式与混杂模式的区分:
- 严格模式: 又称为标准模式,指浏览器按照
W3C
标准解析代码; - 混杂模式: 又称怪异模式、兼容模式,是指浏览器用自己的方式解析代码。混杂模式通常模拟老式浏览器的行为,以防止老站点无法工作;
DTD
,直接影响到使用的是严格模式还是浏览模式,可以说DTD
的使用与这两种方式的区别息息相关。
- 如果文档包含严格的
DOCTYPE
,那么它一般以严格模式呈现(严格 DTD ——严格模式); - 包含过渡
DTD
和URI
的DOCTYPE
,也以严格模式呈现,但有过渡DTD
而没有URI
(统一资源标识符,就是声明最后的地址)会导致页面以混杂模式呈现(有 URI 的过渡 DTD ——严格模式;没有 URI 的过渡 DTD ——混杂模式); DOCTYPE
不存在或形式不正确会导致文档以混杂模式呈现(DTD不存在或者格式不正确——混杂模式);HTML5
没有DTD
,因此也就没有严格模式与混杂模式的区别,HTML5
有相对宽松的 法,实现时,已经尽可能大的实现了向后兼容(HTML5 没有严格和混杂之分)。
PWA使用过吗?serviceWorker的使用原理是啥?
渐进式网络应用(PWA)
是谷歌在2015年底提出的概念。基本上算是web应用程序,但在外观和感觉上与原生app
类似。支持PWA
的网站可以提供脱机工作、推送通知和设备硬件访问等功能。
Service Worker
是浏览器在后台独立于网页运行的脚本,它打开了通向不需要网页或用户交互的功能的大门。 现在,它们已包括如推送通知和后台同步等功能。 将来,Service Worker
将会支持如定期同步或地理围栏等其他功能。 本教程讨论的核心功能是拦截和处理网络请求,包括通过程序来管理缓存中的响应。
代码输出结果
Promise.reject('err!!!') .then((res) => { console.log('success', res) }, (err) => { console.log('error', err) }).catch(err => { console.log('catch', err) })
输出结果如下:
error err!!!
我们知道,.then
函数中的两个参数:
- 第一个参数是用来处理Promise成功的函数
- 第二个则是处理失败的函数
Promise.resolve('1')
的值会进入成功的函数,Promise.reject('2')
的值会进入失败的函数。
在这道题中,错误直接被then
的第二个参数捕获了,所以就不会被catch
捕获了,输出结果为:error err!!!'
但是,如果是像下面这样:
Promise.resolve() .then(function success (res) { throw new Error('error!!!') }, function fail1 (err) { console.log('fail1', err) }).catch(function fail2 (err) { console.log('fail2', err) })
在then
的第一参数中抛出了错误,那么他就不会被第二个参数不活了,而是被后面的catch
捕获到。
数组去重
使用 indexOf/includes 实现function unique(arr) { var res = []; for(var i = 0; i < arr.length; i++) { if(res.indexOf(arr[i]) === -1) res.push(arr[i]); // if(!res.includes(arr[i])) res.push(arr[i]); } return res; }
使用 filter(forEach) + indexOf/includes 实现// filter function unique(arr) { var res = arr.filter((value, index) => { // 只存第一个出现的元素 return arr.indexOf(value) === index; }); return res; } // forEach function unique(arr) { var res = []; arr.forEach((value) => { if(!res.includes(value)) res.push(value); }); return res; }
非 API 版本(原生)实现function unique(arr) { var res = []; for(var i = 0; i < arr.length; i++) { var flag = false; for(var j = 0; j < res.length; j++) { if(arr[i] === res[j]) { flag = true; break; } } if(flag === false) res.push(arr[i]); } return res; }
ES6 使用 Set + 扩展运算符(...)/Array.from() 实现function unique(arr) { // return [...new Set(arr)]; return Array.from(new Set(arr)); }
如何使用for...of遍历对象
for…of是作为ES6新增的遍历方式,允许遍历一个含有iterator接口的数据结构(数组、对象等)并且返回各项的值,普通的对象用for..of遍历是会报错的。
如果需要遍历的对象是类数组对象,用Array.from转成数组即可。
var obj = { 0:'one', 1:'two', length: 2 }; obj = Array.from(obj); for(var k of obj){ console.log(k) }
如果不是类数组对象,就给对象添加一个[Symbol.iterator]属性,并指向一个迭代器即可。
//方法一: var obj = { a:1, b:2, c:3 }; obj[Symbol.iterator] = function(){ var keys = Object.keys(this); var count = 0; return { next(){ if(count
替换元素的概念及计算规则
通过修改某个属性值呈现的内容就可以被替换的元素就称为“替换元素”。
替换元素除了内容可替换这一特性以外,还有以下特性:
- 内容的外观不受页面上的CSS的影响:用专业的话讲就是在样式表现在CSS作用域之外。如何更改替换元素本身的外观需要类似appearance属性,或者浏览器自身暴露的一些样式接口。
- 有自己的尺寸:在Web中,很多替换元素在没有明确尺寸设定的情况下,其默认的尺寸(不包括边框)是300像素×150像素,如
- 在很多CSS属性上有自己的一套表现规则:比较具有代表性的就是vertical-align属性,对于替换元素和非替换元素,vertical-align属性值的解释是不一样的。比方说vertical-align的默认值的baseline,很简单的属性值,基线之意,被定义为字符x的下边缘,而替换元素的基线却被硬生生定义成了元素的下边缘。
- 所有的替换元素都是内联水平元素:也就是替换元素和替换元素、替换元素和文字都是可以在一行显示的。但是,替换元素默认的display值却是不一样的,有的是inline,有的是inline-block。
- 固有尺寸: 指的是替换内容原本的尺寸。例如,图片、视频作为一个独立文件存在的时候,都是有着自己的宽度和高度的。
- HTML尺寸: 只能通过HTML原生属性改变,这些HTML原生属性包括的width和height属性、的size属性。
- CSS尺寸: 特指可以通过CSS的width和height或者max-width/min-width和max-height/min-height设置的尺寸,对应盒尺寸中的content box。
(1)如果没有CSS尺寸和HTML尺寸,则使用固有尺寸作为最终的宽高。
(2)如果没有CSS尺寸,则使用HTML尺寸作为最终的宽高。
(3)如果有CSS尺寸,则最终尺寸由CSS属性决定。
(4)如果“固有尺寸”含有固有的宽高比例,同时仅设置了宽度或仅设置了高度,则元素依然按照固有的宽高比例显示。
(5)如果上面的条件都不符合,则最终宽度表现为300像素,高度为150像素。
(6)内联替换元素和块级替换元素使用上面同一套尺寸计算规则。
对keep-alive的理解
HTTP1.0 中默认是在每次请求/应答,客户端和服务器都要新建一个连接,完成之后立即断开连接,这就是短连接。当使用Keep-Alive模式时,Keep-Alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接,这就是长连接。其使用方法如下:
- HTTP1.0版本是默认没有Keep-alive的(也就是默认会发送keep-alive),所以要想连接得到保持,必须手动配置发送
Connection: keep-alive
字段。若想断开keep-alive连接,需发送Connection:close
字段; - HTTP1.1规定了默认保持长连接,数据传输完成了保持TCP连接不断开,等待在同域名下继续用这个通道传输数据。如果需要关闭,需要客户端发送
Connection:close
首部字段。
- 客户端向服务器在发送请求报文同时在首部添加发送Connection字段
- 服务器收到请求并处理 Connection字段
- 服务器回送Connection:Keep-Alive字段给客户端
- 客户端接收到Connection字段
- Keep-Alive连接建立成功
- 客户端向服务器只是发送内容报文(不包含Connection字段)
- 服务器收到请求并处理
- 服务器返回客户端请求的资源并关闭连接
- 客户端接收资源,发现没有Connection字段,断开连接
- 客户端向服务器发送Connection:close字段
- 服务器收到请求并处理connection字段
- 服务器回送响应资源并断开连接
- 客户端接收资源并断开连接
- 较少的CPU和内存的使?(由于同时打开的连接的减少了);
- 允许请求和应答的HTTP管线化;
- 降低拥塞控制 (TCP连接减少了);
- 减少了后续请求的延迟(?需再进?握?);
- 报告错误?需关闭TCP连;
- 长时间的Tcp连接容易导致系统资源无效占用,浪费系统资源。
CDN一般会用来托管Web资源(包括文本、图片和脚本等),可供下载的资源(媒体文件、软件、文档等),应用程序(门户网站等)。使用CDN来加速这些资源的访问。
(1)在性能方面,引入CDN的作用在于:
- 用户收到的内容来自最近的数据中心,延迟更低,内容加载更快
- 部分资源请求分配给了CDN,减少了服务器的负载
- 针对DDoS:通过监控分析异常流量,限制其请求频率
- 针对MITM:从源服务器到 CDN 节点到 ISP(Internet Service Provider),全链路 HTTPS 通信
说一下HTTP和HTTPS协议的区别?
1、HTTPS协议需要CA证书,费用较高; 而HTTP协议不需要 2、HTTP协议是超文本传输协议,信息是明文传输的,HTTPS则是具有安全性的SSL加密传输协议; 3、使用不同的连接方式,端口也不同,HTTP协议端口是80,HTTPS协议端口是443; 4、HTTP协议连接很简单,是无状态的; HTTPS协议是具有SSL和HTTP协议构建的可进行加密传输、身份认证的网络协议,比HTTP更加安全
说一下vue3.0你了解多少?
代码输出问题
window.number = 2; var obj = { number: 3, db1: (function(){ console.log(this); this.number *= 4; return function(){ console.log(this); this.number *= 5; } })() } var db1 = obj.db1; db1(); obj.db1(); console.log(obj.number); // 15 console.log(window.number); // 40
这道题目看清起来有点乱,但是实际上是考察this指向的:
- 执行db1()时,this指向全局作用域,所以window.number 4 = 8,然后执行匿名函数, 所以window.number 5 = 40;
- 执行obj.db1(); 时,this指向obj对象,执行匿名函数,所以obj.numer * 5 = 15。
推荐阅读
- 美团前端面试题(附答案)
- 阿里前端一面面试题(附答案)
- 滴滴前端一面必会面试题
- 高级前端二面高频面试题合集
- 社招前端二面常见面试题
- 腾讯前端面试题
- 京东前端二面高频面试题
- 字节前端面试题
- 字节前端必会面试题