src和href的区别
src 用于替换当前元素,href 用于在当前文档和引用资源之间确立联系。
(1)src,src 是 source 的缩写,指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在位置;在请求 src 资源时会将其指向的资源下载并应用到文档内,例如 js 脚本,img 图片和 frame 等元素。当浏览器解析到该元素时,会暂停其他资源的下载和处理,直到将该资源加载、编译、执行完毕,图片和框架等元素也如此,类似于将所指向资源嵌入当前标签内。这也是为什么将js 脚本放在底部而不是头部。
(2)href,href 是 Hypertext Reference 的缩写,指向网络资源所在位置,建立和当前元素(锚点)或当前文档(链接)之间的链接,浏览器会识别该文档为 css 文件,就会并行下载资源并且不会停止对当前文档的处理。 这也是为什么建议使用 link 方式来加载 css,而不是使用@import 方式。
HTML5的离线储存怎么使用,它的工作原理是什么
离线存储指的是:在用户没有与因特网连接时,可以正常访问站点或应用,在用户与因特网连接时,更新用户机器上的缓存文件。
原理:
HTML5的离线存储是基于一个新建的 .appcache 文件的缓存机制(不是存储技术),通过这个文件上的解析清单离线存储资源,这些资源就会像cookie一样被存储了下来。之后当网络在处于离线状态下时,浏览器会通过被离线存储的数据进行页面展示
使用方法: (1)创建一个和html同名的manifest文件,然后在页面头部加入 manifest属性:
<html lang="en" manifest="index.manifest">
(2)在cache.manifest文件中编写需要离线存储的资源:
CACHE MANIFEST #v0.11 CACHE: js/app.js css/style.css NETWORK: resourse/logo.png FALLBACK: / /offline.html
- **CACHE**: 表示需要离线存储的资源列表,由于包含 manifest 文件的页面将被自动离线存储,所以不需要把页面自身也列出来。
-
NETWORK: 表示在它下面列出来的资源只有在在线的情况下才能访问,他们不会被离线存储,所以在离线情况下无法使用这些资源。不过,如果在 CACHE 和 NETWORK 中有一个相同的资源,那么这个资源还是会被离线存储,也就是说 CACHE 的优先级更高。
-
FALLBACK: 表示如果访问第一个资源失败,那么就使用第二个资源来替换他,比如上面这个文件表示的就是如果访问根目录下任何一个资源失败了,那么就去访问 offline.html 。
(3)在离线状态时,操作 window.applicationCache 进行离线缓存的操作。
如何更新缓存:
(1)更新 manifest 文件
(2)通过 javascript 操作
(3)清除浏览器缓存
注意事项:
(1)浏览器对缓存数据的容量限制可能不太一样(某些浏览器设置的限制是每个站点 5MB)。
(2)如果 manifest 文件,或者内部列举的某一个文件不能正常下载,整个更新过程都将失败,浏览器继续全部使用老的缓存。
(3)引用 manifest 的 html 必须与 manifest 文件同源,在同一个域下。
(4)FALLBACK 中的资源必须和 manifest 文件同源。
(5)当一个资源被缓存后,该浏览器直接请求这个绝对路径也会访问缓存中的资源。
(6)站点中的其他页面即使没有设置 manifest 属性,请求的资源如果在缓存中也从缓存中访问。
(7)当 manifest 文件发生改变时,资源请求本身也会触发更新。
HTML5的离线储存资源进行管理的规则:
在线情况: 浏览器发现html头部有manifest属性,它会请求manifest文件,如果是第一次访问页面,那么浏览器就会根据manifest文件的内容下载相应的资源并且进行离线存储。如果已经访问过页面并且资源已经进行离线存储了,那么浏览器就会使用离线的资源加载页面,然后浏览器会对比新的manifest文件与旧的manifest文件,如果文件没有发生改变,就不做任何操作,如果文件改变了,就会重新下载文件中的资源进行离线存储。
离线的情况下,浏览器会直接使用离线存储的资源。
Canvas和SVG的区别
(1)SVG: SVG可缩放矢量图形(Scalable Vector Graphics)是基于可扩展标记语言XML描述的2D图形的语言,SVG基于XML就意味着SVG DOM中的每个元素都是可用的,可以为某个元素附加Javascript事件处理器。在 SVG 中,每个被绘制的图形均被视为对象。如果 SVG 对象的属性发生变化,那么浏览器能够自动重现图形。
其特点如下:
- 不依赖分辨率
- 支持事件处理器
- 最适合带有大型渲染区域的应用程序(比如谷歌地图)
- 复杂度高会减慢渲染速度(任何过度使用 DOM 的应用都不快)
- 不适合游戏应用
(2)Canvas: Canvas是画布,通过Javascript来绘制2D图形,是逐像素进行渲染的。其位置发生改变,就会重新进行绘制。
其特点如下:
- 依赖分辨率
- 不支持事件处理器
- 弱的文本渲染能力
- 能够以 .png 或 .jpg 格式保存结果图像
- 最适合图像密集型的游戏,其中的许多对象会被频繁重绘
注:矢量图,也称为面向对象的图像或绘图图像,在数学上定义为一系列由线连接的点。矢量文件中的图形元素称为对象。每个对象都是一个自成一体的实体,它具有颜色、形状、轮廓、大小和屏幕位置等属性。
script标签中defer和async的区别
如果没有defer或async属性,浏览器会立即加载并执行相应的脚本。 它不会等待后续加载的文档元素,读取到就会开始加载和执行,这样就阻塞了后续文档的加载。
其中蓝色代表js脚本网络加载时间,红色代表js脚本执行时间,绿色代表html解析。
defer 和 async属性都是去异步加载外部的JS脚本文件,它们都不会阻塞页面的解析,
其区别如下:
●执行顺序:多个带async属性的标签,不能保证加载的顺序;多个带defer属性的标签,按照加载顺序执行;
●脚本是否并行执行:
async属性,表示后续文档的加载和执行与js脚本的加载和执行是并行进行的,即异步执行;
defer属性,加载后续文档的过程和js脚本的加载(此时仅加载不执行)是并行进行的(异步),js脚本需要等到文档所有元素解析完成之后才执行,DOMContentLoaded事件触发执行之前。
iframe 有那些优点和缺点?
iframe 元素会创建包含另外一个文档的内联框架(即行内框架)。
优点:(1)用来加载速度较慢的内容(如广告)(2)可以使脚本可以并行下载(3)可以实现跨子域通信 (4)最简单的微前端模块化方案 缺点:(1)iframe 会阻塞主页面的 onload 事件(2)无法被一些搜索引擎索识别(3)会产生很多页面,不容易管理(4)动态地址宽高不好控制
渐进增强和优雅降级之间的区别
渐进增强(progressive enhancement):主要是针对低版本的浏览器进行页面重构,保证基本的功能情况下,再针对高级浏览器进行效果、交互等方面的改进和追加功能,以达到更好的用户体验。从一个非常基础的,能够起作用的版本开始的,并在此基础上不断扩充,以适应未来环境的需要
优雅降级 (graceful degradation): 一开始就构建完整的功能,然后再针对低版本的浏览器进行兼容。优雅降级是从复杂的现状开始的,并试图减少用户体验的供给
为什么有时候⽤translate来改变位置⽽不是定位**?**
translate 是 transform 属性的⼀个值。改变transform或opacity不会触发浏览器重新布局(reflow)或重绘(repaint),只会触发复合(compositions)。
⽽改变绝对定位会触发重新布局,进⽽触发重绘和复合。
transform使浏览器为元素创建⼀个 GPU 图层,但改变绝对定位会使⽤到 CPU。 因此translate()更⾼效,可以缩短平滑动画的绘制时间。 ⽽translate改变位置时,元素依然会占据其原始空间,绝对定位就不会发⽣这种情况。
null和undefined区别
首先 Undefined 和 Null 都是基本数据类型,这两个基本数据类型分别都只有一个值,就是 undefined 和 null。
undefined 代表的含义是未定义有声名,null 代表的含义是空对象。
一般变量声明了但还没有定义的时候会返回 undefined,null主要用于赋值给一些可能会返回对象的变量,作为初始化。
undefined 在 JavaScript 中不是一个保留字,这意味着可以使用 undefined 来作为一个变量名,但是这样的做法是非常危险的,它会影响对 undefined 值的判断。我们可以通过一些方法获得安全的 undefined 值,比如说 void 0。
当对这两种类型使用 typeof 进行判断时,Null 类型化会返回 “object”,这是一个历史遗留的问题。二进制null是0001
当使用双等号对两种类型的值进行比较时会返回 true,使用三个等号时会返回 false。
如何获取安全的 undefined 值?
因为 undefined 是一个标识符,所以可以被当作变量来使用和赋值,但是这样会影响 undefined 的正常判断。表达式 void ___ 没有返回值,因此返回结果是 undefined。void 并不改变表达式的结果,只是让表达式不返回值。因此可以用 void 0 来获得 undefined。
双向数据绑定的原理
Vue.js 是采用数据劫持结合发布者 - 订阅者模式的方式,通过 Object.defineProperty() 来劫持各个属性的 setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
主要分为以下几个步骤:
(1)需要 observe 的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter 和 getter 这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化
(2)compile 解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图。
(3)Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁,主要做的事情是:
①在自身实例化时往属性订阅器 (dep) 里面添加自己
②自身必须有一个 update()方法
③待属性变动 dep.notice()通知时,能调用自身的 update()方法,并触发 Compile 中绑定的回调,则功成身退。
(4)MVVM 作为数据绑定的入口,整合 Observer、Compile 和 Watcher 三者,通过 Observer 来监听自己的 model 数据变化,通过 Compile 来解析编译模板指令,最终利用 Watcher 搭起 Observer 和 Compile 之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化 (input) -> 数据 model 变更的双向绑定效果。
使用 Object.defineProperty() 来进行数据劫持有什么缺点?
对属性进行操作时,使用这种方法无法拦截,比如通过下标方式修改数组数据或者给对象新增属性,这都不能触发组件的重新渲染,因为 Object.defineProperty 不能拦截到这些操作。更精确的来说,对于数组而言,大部分操作都是拦截不到的,只是 Vue 内部通过重写函数的方式解决了这个问题。
在 Vue3.0 中已经不使用这种方式了,而是通过使用 Proxy 对对象进行代理,从而实现数据劫持。使用Proxy 的好处是它可以完美的监听到任何方式的数据改变,唯一的缺点是兼容性的问题,因为 Proxy 是 ES6 的语法。
Computed 和 Watch 的区别
Computed:
(1)它支持缓存,只有依赖的数据发生了变化,才会重新计算
(2)不支持异步,当Computed中有异步操作时,无法监听数据的变化
(3)computed的值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data声明过,或者父组件传递过来的props中的数据进行计算的。
(4)如果一个属性是由其他属性计算而来的,这个属性依赖其他的属性,一般会使用computed
(5)如果computed属性的属性值是函数,那么默认使用get方法,函数的返回值就是属性的属性值;在computed中,属性有一个get方法和一个set方法,当数据发生变化时,会调用set方法。
Watch:(
(1)不支持缓存,数据变化时,它就会触发相应的操作
(2)支持异步监听
(3)监听的函数接收两个参数,第一个参数是最新的值,第二个是变化之前的值
(4)当一个属性发生变化时,就需要执行相应的操作 监听数据必须是data中声明的或者父组件传递过来的props中的数据,当发生变化时,会触发其他操作,函数有两个的参数:
(1)immediate:组件加载立即触发回调函数
(2)deep:深度监听,发现数据内部的变化,在复杂数据类型中使用,例如数组中的对象发生变化。需要注意的是,deep为true,就可以监测到对象中每个属性的变化,它会一层层遍历,给这个对象的所有属性都加上这个监听器。当想要执行异步或者昂贵的操作以响应不断的变化时,就需要使用watch。
总结:(1)computed 计算属性 : 依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值。(2)watch 侦听器 : 更多的是观察的作用,无缓存性,类似于某些数据的监听回调,每当监听的数据变化时都会执行回调进行后续操作。 运用场景: (1)当需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时都要重新计算。 (2)当需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许执行异步操作 ( 访问一个 API ),限制执行该操作的频率,并在得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
$nextTick 原理及作用
Vue 的 nextTick 其本质是对 JavaScript 执行原理 EventLoop 的一种应用。
nextTick 的核心是利用了如 Promise 、MutationObserver、setImmediate、setTimeout的原生 JavaScript 方法来模拟对应的微/宏任务的实现,本质是为了利用 JavaScript 的这些异步回调任务队列来实现 Vue 框架中自己的异步回调队列。
nextTick 不仅是 Vue 内部的异步队列的调用方法,同时也允许开发者在实际项目中使用这个方法来满足实际应用中对 DOM 更新数据时机的后续逻辑处理。
nextTick 是典型的将底层 JavaScript 执行原理应用到具体案例中的示例,
引入异步更新队列机制的原因∶
(1)如果是同步更新,则多次对一个或多个属性赋值,会频繁触发 UI/DOM 的渲染,可以减少一些无用渲染
(2)同时由于 VirtualDOM 的引入,每一次状态发生变化后,状态变化的信号会发送给组件,组件内部使用 VirtualDOM 进行计算得出需要更新的具体的 DOM 节点,然后对 DOM 进行更新操作,每次更新状态后的渲染过程需要更多的计算,而这种无用功也将浪费更多的性能,所以异步渲染变得更加至关重要。Vue采用了数据驱动视图的思想,但是在一些情况下,仍然需要操作DOM。有时候,可能遇到这样的情况,DOM1的数据发生了变化,而DOM2需要从DOM1中获取数据,那这时就会发现DOM2的视图并没有更新,这时就需要用到了nextTick了。由于Vue的DOM操作是异步的,所以,在上面的情况中,就要将DOM2获取数据的操作写在$nextTick中。
对React-Fiber的理解,它解决了什么问题?
React V15 在渲染时,会递归比对 VirtualDOM 树,找出需要变动的节点,然后同步更新它们, 一气呵成。这个过程期间, React 会占据浏览器资源,这会导致用户触发的事件得不到响应,并且会导致掉帧,导致用户感觉到卡顿。为了给用户制造一种应用很快的“假象”,不能让一个任务长期霸占着资源。 可以将浏览器的渲染、布局、绘制、资源加载(例如 HTML 解析)、事件响应、脚本执行视作操作系统的“进程”,需要通过某些调度策略合理地分配 CPU 资源,从而提高浏览器的用户响应速率, 同时兼顾任务执行效率。
所以 React 通过Fiber 架构,让这个执行过程变成可被中断。“适时”地让出 CPU 执行权,除了可以让浏览器及时地响应用户的交互,
还有其他好处:
(1)分批延时对DOM进行操作,避免一次性操作大量 DOM 节点,可以得到更好的用户体验;
给浏览器一点喘息的机会,它会对代码进行编译优化(JIT)及进行热代码优化,或者对 reflow 进行修正。
(2)核心思想:Fiber 也称**协程或者纤程**。它和线程并不一样,协程本身是没有并发或者并行能力的(需要**配合线程**),
它只是一种控制流程的让出机制。让出 CPU 的执行权,让 CPU 能在这段时间执行其他的操作。
渲染的过程可以被中断,可以将控制权交回浏览器,让位给高优先级的任务,浏览器空闲后再恢复渲染。
React.Component 和 React.PureComponent 的区别
PureComponent表示一个纯组件,可以用来优化React程序,减少render函数执行的次数,从而提高组件的性能。
在React中,当prop或者state发生变化时,可以通过在shouldComponentUpdate生命周期函数中执行return false来阻止页面的更新,从而减少不必要的render执行。
React.PureComponent会自动执行 shouldComponentUpdate。不过,pureComponent中的 shouldComponentUpdate() 进行的是浅比较,也就是说如果是引用数据类型的数据,只会比较不是同一个地址,而不会比较这个地址里面的数据是否一致。浅比较会忽略属性和或状态突变情况,其实也就是数据引用指针没有变化,而数据发生改变的时候render是不会执行的。如果需要重新渲染那么就需要重新开辟空间引用数据。PureComponent一般会用在一些纯展示组件上。
使用pureComponent的好处:当组件更新时,如果组件的props或者state都没有改变,render函数就不会触发。省去虚拟DOM的生成和对比过程,达到提升性能的目的。这是因为react自动做了一层浅比较。
对有状态组件和无状态组件的理解及使用场景
(1)有状态组件 特点:
(1)是类组件
(2)有继承
(3)可以使用this
(4)可以使用react的生命周期
(5)使用较多,容易频繁触发生命周期钩子函数,影响性能
(6)内部使用 state,维护自身状态的变化,有状态组件根据外部组件传入的 props 和自身的 state进行渲染。
使用场景
(1)需要使用到状态的。
(2)需要使用状态操作组件的(无状态组件的也可以实现新版本react hooks也可实现)
总结: 类组件可以维护自身的状态变量,即组件的 state ,
类组件还有不同的生命周期方法,可以让开发者能够在组件的不同阶段(挂载、更新、卸载),对组件做更多的控制。
类组件则既可以充当无状态组件,也可以充当有状态组件。
当一个类组件不需要管理自身状态时,也可称为无状态组件。
(2)无状态组件 特点:
(1)不依赖自身的状态state
(2)可以是类组件或者函数组件。
(3)可以完全避免使用 this 关键字。(由于使用的是箭头函数事件无需绑定)
(4)有更高的性能。当不需要使用生命周期钩子时,应该首先使用无状态函数组件
(5)组件内部不维护 state ,只根据外部组件传入的 props 进行渲染的组件,当 props 改变时组件重新渲染。
使用场景:
组件不需要管理 state,纯展示
优点:
(1)简化代码、专注于 render
(2)组件不需要被实例化,无生命周期,提升性能。 输出(渲染)只取决于输入(属性),无副作用
(3)视图和数据的解耦分离
缺点:
(1)无法使用 ref
(2)无生命周期方法
(3)无法控制组件的重渲染,因为无法使用shouldComponentUpdate 方法,当组件接受到新的属性时则会重渲染
总结:
组件内部状态且与外部无关的组件,可以考虑用状态组件,这样状态树就不会过于复杂,易于理解和管理。
当一个组件不需要管理自身状态时,也就是无状态组件,应该优先设计为函数组件。比如自定义的 、 等组件。
webpack的构建流程?
Webpack 的运⾏流程是⼀个串⾏的过程,从启动到结束会依次执⾏以下流程:
1.初始化参数:从配置⽂件和 Shell 语句中读取与合并参数,得出最终的参数;
2**.开始编译**:⽤上⼀步得到的参数初始化 Compiler 对象,加载所有配置的插件,执⾏对象的 run ⽅法开始执⾏编译;
3.确定⼊⼝:根据配置中的 entry 找出所有的⼊⼝⽂件;
4.编译模块:从⼊⼝⽂件出发,调⽤所有配置的 Loader 对模块进⾏翻译,再找出该模块依赖的模块,再递归本步骤直到所有⼊⼝依赖的⽂件都经过了本步骤的处理;
5.完成模块编译:在经过第4步使⽤ Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
6.输出资源:根据⼊⼝和模块之间的依赖关系,组装成⼀个个包含多个模块的 Chunk,再把每个 Chunk 转换成⼀个单独的⽂件加⼊到输出列表,这步是可以修改输出内容的最后机会;
7.输出完成:在确定好输出内容后,根据配置确定输出的路径和⽂件名,把⽂件内容写⼊到⽂件系统。
在以上过程中,Webpack 会在特定的时间点⼴播出特定的事件,插件在监听到感兴趣的事件后会执⾏特定的逻辑,并且插件可以调⽤ Webpack 提供的 API 改变 Webpack 的运⾏结果。
HTTP 1.1 和 HTTP 2.0 的区别
(1)二进制协议:HTTP/2 是一个二进制协议。
在 HTTP/1.1 版中,报文的头信息必须是文本(ASCII 编码),数据体可以是文本,也可以是二进制。
HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧",
可以分为头信息帧和数据帧。 帧的概念是它实现多路复用的基础。
(2)多路复用:HTTP/2 实现了多路复用
HTTP/2 仍然复用 **TCP 连接**,但是在一个连接里,客户端和服务器都可以同时发送多个请求或回应,
而且不用按照顺序一一发送,这样就避免了"队头堵塞"【1】的问题。
(3)数据流:HTTP/2 使用了数据流的概念,
因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的请求。
因此,必须要对数据包做标记,指出它属于哪个请求。HTTP/2 将每个请求或回应的所有数据包,称为一个数据流。
每个数据流都有一个独一无二的编号。数据包发送时,都必须标记数据流 ID ,用来区分它属于哪个数据流。
(4)头信息压缩:
HTTP/2 实现了头信息压缩,由于 HTTP 1.1 协议不带状态,每次请求都必须附上所有信息。
所以,请求的很多字段都是重复的,比如 Cookie 和 User Agent ,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。
HTTP/2 对这一点做了优化,引入了头信息压缩机制。一方面,头信息使用 gzip 或 compress 压缩后再发送;
另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,
只发送索引号,这样就能提高速度了。
(5)服务器推送:
HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送。
使用服务器推送提前给客户端推送必要的资源,这样就可以相对减少一些延迟时间。
这里需要注意的是 http2 下服务器主动推送的是**静态资源**,和 WebSocket 以及使用 SSE 等方式向客户端发送即时数据的推送是不同的。
什么是 XSS 攻击?
(1)概念:XSS 攻击指的是**跨站脚本攻击**,是一种代码注入攻击。攻击者通过在网站**注入恶意脚本**,使之在用户的浏览器上运行,从而盗取用户的信息如 cookie 等。
XSS 的本质是因为网站没有对恶意代码进行过滤,与正常的代码混合在一起了,
浏览器没有办法分辨哪些脚本是可信的,从而导致了恶意代码的执行。
攻击者可以通过这种攻击方式可以进行以下操作:
(1)获取页面的**数据**,如DOM、cookie、localStorage;
(2)**DOS攻击**,发送合理请求,占用服务器资源,从而使用户无法访问服务器;
(3)破坏页面结构;
(4)流量劫持(将链接指向某网站);
(2)攻击类型 XSS 可以分为存储型、反射型和 DOM 型:
(1)存储型指的是恶意脚本会存储在目标服务器上,当浏览器请求数据时,脚本从服务器传回并执行。
(2)反射型指的是攻击者诱导用户访问一个带有恶意代码的 URL 后,服务器端接收数据后处理,
然后把带有恶意代码的数据发送到浏览器端,浏览器端解析这段带有 XSS 代码的数据后当做脚本执行,最终完成 XSS 攻击。
(3)DOM 型指的通过修改页面的 DOM 节点形成的 XSS。
**存储型 XSS 的攻击步骤:**
1.攻击者将恶意代码提交到⽬标⽹站的数据库中。
2.⽤户打开⽬标⽹站时,⽹站服务端将恶意代码从数据库取出,拼接在 HTML 中返回给浏览器。
3.⽤户浏览器接收到响应后解析执⾏,混在其中的恶意代码也被执⾏。
4.恶意代码窃取⽤户数据并发送到攻击者的⽹站,或者冒充⽤户的⾏为,调⽤⽬标⽹站接⼝执⾏攻击者指定的操作。
这种攻击常⻅于带有⽤户保存数据的⽹站功能,如论坛发帖、商品评论、⽤户私信等。
**反射型 XSS 的攻击步骤**:
1.攻击者构造出特殊的 URL,其中包含恶意代码。
2.⽤户打开带有恶意代码的 URL 时,⽹站服务端将恶意代码从 URL 中取出,拼接在 HTML 中返回给浏览器。
3.⽤户浏览器接收到响应后解析执⾏,混在其中的恶意代码也被执⾏。
4.恶意代码窃取⽤户数据并发送到攻击者的⽹站,或者冒充⽤户的⾏为,
调⽤⽬标⽹站接⼝执⾏攻击者指定的操作。
**反射型 XSS 跟存储型 XSS 的区别是:**
存储型 XSS 的恶意代码存在数据库⾥,
反射型 XSS 的恶意代码存在 URL ⾥。
反射型 XSS 漏洞常⻅于通过 URL 传递参数的功能,如⽹站搜索、跳转等。
由于需要⽤户主动打开恶意的 URL 才能⽣效,攻击者往往会结合多种⼿段诱导⽤户点击。
**DOM 型 XSS 的攻击步骤:**
1.攻击者构造出特殊的 URL,其中包含恶意代码。
2.⽤户打开带有恶意代码的 URL。
3.⽤户浏览器接收到响应后解析执⾏,前端 JavaScript 取出 URL 中的恶意代码并执⾏。
4.恶意代码窃取⽤户数据并发送到攻击者的⽹站,或者冒充⽤户的⾏为,调⽤⽬标⽹站接⼝执⾏攻击者指定的操作。
DOM 型 XSS 跟前两种 XSS 的区别:
DOM 型 XSS 攻击中,取出和执⾏恶意代码由**浏览器端完成**,属于**前端JavaScript ⾃身的安全漏洞**,⽽其他两种 XSS 都属于服务端的安全漏洞。
如何防御 XSS 攻击? 可以看到XSS危害如此之大, 那么在开发网站时就要做好防御措施,具体措施如下:
(1)可以从浏览器的执行来进行预防,一种是使用纯前端的方式,不用服务器端拼接后返回(不使用服务端渲染)。
另一种是对需要插入到 HTML 中的代码做好**充分的转义**。
对于 DOM 型的攻击,主要是前端脚本的不可靠而造成的,对于数据获取**渲染**和字符串拼接的时候应该对可能出现的恶意代码情况**进行判断**。
(2)使用 CSP ,CSP 的本质是建立一个白名单,告诉浏览器哪些外部资源可以加载和执行,从而防止恶意代码的注入攻击。
1.CSP 指的是内容安全策略,它的本质是建立一个白名单,告诉浏览器哪些外部资源可以加载和执行。
我们只需要配置规则,如何拦截由浏览器自己来实现。
2.通常有两种方式来开启 CSP,一种是设置 HTTP 首部中的 Content-Security-Policy,
一种是设置 meta 标签的方式 对一些敏感信息进行保护,比如 cookie 使用 http-only,使得脚本无法获取。
也可以使用验证码,避免脚本伪装成用户执行一些操作。
死锁产生的原因? 如果解决死锁的问题?
所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。
系统中的资源可以分为两类:
(1)可剥夺资源,是指某进程在获得这类资源后,该资源可以再被其他进程或系统剥夺,CPU和主存均属于可剥夺性资源;
(2)不可剥夺资源,当系统把这类资源分配给某进程后,再不能强行收回,只能在进程用完后自行释放,如磁带机、打印机等。
产生死锁的原因:
(1)竞争资源 产生死锁中的竞争资源之一指的是竞争不可剥夺资源(例如:系统中只有一台打印机,可供进程P1使用,假定P1已占用了打印机,若P2继续要求打印机打印将阻塞) 产生死锁中的竞争资源另外一种资源指的是竞争临时资源(临时资源包括硬件中断、信号、消息、缓冲区内的消息等),通常消息通信顺序进行不当,则会产生死锁
(2)进程间推进顺序非法 若P1保持了资源R1,P2保持了资源R2,系统处于不安全状态,因为这两个进程再向前推进,便可能发生死锁。例如,当P1运行到P1:Request(R2)时,将因R2已被P2占用而阻塞;当P2运行到P2:Request(R1)时,也将因R1已被P1占用而阻塞,于是发生进程死锁
产生死锁的必要条件:
(1)互斥条件:进程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为一进程所占用。
(2)请求和保持条件:当进程因请求资源而阻塞时,对已获得的资源保持不放。
(3)不剥夺条件:进程已获得的资源在未使用完之前,不能剥夺,只能在使用完时由自己释放。
(4)环路等待条件:在发生死锁时,必然存在一个进程——资源的环形链。
预防死锁的方法:
(1)资源一次性分配:一次性分配所有资源,这样就不会再有请求了(破坏请求条件)
(2)只要有一个资源得不到分配,也不给这个进程分配其他的资源(破坏请保持条件)
(3)可剥夺资源:即当某进程获得了部分资源,但得不到其它资源,则释放已占有的资源(破坏不可剥夺条件)
(4)资源有序分配法:系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反(破坏环路等待条件)
如何实现浏览器内多个标签页之间的通信?
实现多个标签页之间的通信,本质上都是通过中介者模式来实现的。 因为标签页之间没有办法直接通信,因此我们可以找一个中介者,让标签页和中介者进行通信,然后让这个中介者来进行消息的转发。
通信方法如下:
(1)使用 websocket 协议,因为** websocket 协议可以实现服务器推送**,所以服务器就可以用来当做这个中介者。标签页通过向服务器发送数据,然后由服务器向其他标签页推送转发。
(2)使用 ShareWorker 的方式,shareWorker 会在页面存在的生命周期内创建一个唯一的线程,并且开启多个页面也只会使用同一个线程。这个时候共享线程就可以充当中介者的角色。标签页间通过共享一个线程,然后通过这个共享的线程来实现数据的交换。
(3)使用 localStorage 的方式,我们可以在一个标签页对 localStorage 的变化事件进行监听,然后当另一个标签页修改数据的时候,我们就可以通过这个监听事件来获取到数据。这个时候 localStorage 对象就是充当的中介者的角色。
(4)使用 postMessage 方法,如果我们能够获得对应标签页的引用,就可以使用postMessage 方法,进行通信。
如何进行网站性能优化
Content方面
1.减少HTTP请求:合并文件、CSS精灵、inline Image
2.减少DNS查询:DNS查询完成之前浏览器不能从这个主机下载任何任何文件。方法:DNS缓存、将资源分布到恰当数量的主机名,平衡并行下载和DNS查询
3.避免重定向:多余的中间访问
4.使Ajax可缓存
5.非必须组件延迟加载
6.未来所需组件预加载
7.减少DOM元素数量
8.**将资源放到不同的域下**:浏览器同时从一个域下载资源的数目有限,增加域可以提高并行下载量
9.减少iframe数量
10.不要404
Server方面
11.使用CDN
12.添加Expires或者Cache-Control响应头
13.对组件使用Gzip压缩
14.配置ETag
15.Flush Buffer Early
16.Ajax使用GET进行请求
17.避免空src的img标签
Cookie方面
18.减小cookie大小
19.引入资源的域名不要包含cookie
Css方面
20.将样式表放到页面顶部
21.不使用CSS表达式
22.使用不使用@import
23.不使用IE的Filter
Javascript方面
24.将脚本放到页面底部
25.将javascript和css从外部引入
26.压缩javascript和css
27.删除不需要的脚本
28.减少DOM访问
29.合理设计事件监听器
图片方面
30.优化图片:根据实际颜色需要选择色深、压缩
31.优化css精灵
32.不要在HTML中拉伸图片
33.保证favicon.ico小并且可缓存
移动方面
34.保证组件小于25k
35.Pack Components into a Multipart Document