问题1requestAnimationFrame和setTimeout的对比优势当页面隐藏或最小化时,setTimeout仍然在后台执行动画。这时候页面不可见或者不可用,动画刷新也没有意义,很浪费CPU。rAF不同。当页面处于inactive状态时,页面的屏幕绘制任务也会被系统挂起,所以跟随系统的rAF也会停止渲染。当页面被激活时,动画会从上次停止的地方开始继续在本地执行,有效节省CPU开销。规范中好像是这样定义的:在重新渲染之前调用。宏任务后很可能不调用相比节流优点动画保持60fps(每帧16毫秒),渲染的最佳时间由浏览器内部决定简洁标准的API,后期维护成本低缺点需要启动/cancelanimation由开发人员控制,不像'.debounce'或'.throttle'由函数内部处理。当浏览器选项卡未处于活动状态时,不会执行任何操作。虽然所有现代浏览器都支持rAF,但IE9、OperaMini和旧版Android仍然需要打补丁。Node.js不支持,不能在服务器端用于文件系统事件。问题2DNS解析首先查看是否有对应的域名缓存,如果有则直接使用缓存的ip访问如果没有缓存,则寻找hosts文件,一般在c:\windows\system32\drivers\etc\hosts如果hosts文件没有找到你要解析的域名,就会将该域名发送到你自己配置的dns服务器,也叫本地dns服务器ipconfig/all。如果本地dns服务器有对应域名的记录,则返回该记录。如果电脑自己的服务器没有记录,就会去根服务器。全球只有13组根服务器,将找到其中一组。找到根服务器后,根服务器会根据请求的域名返回对应的“顶级域名服务器”。以此类推,地址最终会被发送到负责锁定和查询域名的最准确的dns,本地dns服务器可以得到查询结果,并将最终的分析结果返回给客户端。问题3XSSCSRFXSS是指黑客通过向HTML文件或DOM中注入恶意脚本,从而在用户浏览页面时利用注入的恶意脚本对用户进行攻击的一种手段。注入恶意脚本可以完成这些事情:窃取cookie来监控用户行为,比如输入账号密码后发送给黑客,在网页中生成浮窗广告,修改DOM,伪造登录表单一般来说,XSS的实现方式有3种攻击存储类型XSS攻击反射型XSS攻击基于DOM的XSS攻击防止XSS攻击的策略过滤或转码输入脚本使用CSP,此安全策略的实施基于名为Content-Security-Policy的HTTP标头。限制加载其他域下的资源文件,即使黑客插入JavaScript文件,也无法加载JavaScript文件;禁止向第三方域提交数据,以免用户数据泄露;提供报告机制可以帮助我们及时发现XSS攻击。禁止执行内联脚本和未经授权的脚本;利用HttpOnly。服务器可以将某些cookie设置为HttpOnly标志。HttpOnly表示服务器通过HTTP响应头设置CSRF,在黑客的网站中,利用用户的登录状态发起跨站请求。简单来说,CSRF攻击就是黑客利用用户的登录状态,通过第三方站点做一些坏事。保护策略验证码机制验证源站点。主要是通过HTTP请求头中的两个header,Origin只包含域名信息,Referer包含具体的URL路径。OriginHeaderRefererHeader使用了Cookie的SameSite属性。SameSite可以设置为三个值,Strict、Lax和None。在严格模式下,浏览器完全禁止第三方请求携带cookies。在Lax模式下,cookie只能在get方法提交表单或标签发送get请求时携带。在None模式下,cookies会在所有上下文中发送,即CSRFToken允许跨域发送。问题4开发一个loader和Pluginloader本质上是一个函数。当我们加载一些文件时,这个函数将执行开发加载器函数。此函数必须返回缓冲区或字符串才能使用此加载程序。我们使用resolveLoader配置项来指定loader查找文件路径。使用加载器时,可以直接指定加载器的名称resolveLoader:{//加载器路径搜索顺序从左到右modules:['node_modules','./']},module:{rules:[{test:/\.js$/,use:'myLoader'}]}plugins通常会在webpack打包的某个时间点做一些操作。我们在使用插件的时候,一般都是以newPlugin()的形式来使用的。所以,首先要明确plugins应该是一个类。插件类需要实现一个apply方法。此方法接受编译器作为参数。这个编译器是一个webpack实例。例如classDemoPlugin{constructor(){console.log('plugininit')}//编译器是一个webpack实例compile.tap('DemoPlugin',compilation=>{console.log(compilation)})//在生成资源到输出目录之前(异步)compiler.hooks.emit.tapAsync('DemoPlugin',(compilation,fn)=>{console.log(compilation)compilation.assets['index.md']={//文件内容source:function(){return'thisisademo'},//文件大小size:function(){return10}}fn()})}}module.exports=DemoPluginQuestion5TCP/IP/如何保证数据包的有序可靠传输Throttleandnumberingsegments由两种机制保证:ACK回复和超时重传。问题六:粘包分析与对策TCP粘包是指发送方发送的几包数据在接收方收到时被粘成一个包。从接收缓冲区开始,最后一包数据的头部跟在前一包数据的尾部之后。粘包的原因很简单。在流传输中,UDP不会有粘包,因为它有消息边界粘包。有两种情况。第二种情况是有不完整的包裹粘在一起。一个比较全面的对策是:接收方创建一个预处理线程,对接收到的数据包进行预处理,分离粘包。实验证明该方法是高效可行的。问题7如何避免重绘或重排?专注于改变样式,而不是一个一个地修改DOM样式。不要将DOM节点的属性值作为循环中的变量放入循环中。对动画HTML元素使用固定或绝对位置,然后修改它们的CSS将不会重排。不使用表格布局。因为一个小小的改动就可能导致整个表格重新布局。尽量只修改position:absolute或fixed元素,对其他元素影响不大。Animation启动GPU加速,translate利用3D变化升级为合成层。问题8浏览器在一帧中做什么AcceptinputeventsExecuteeventcallbacks在一帧中开始执行RAF(RequestAnimationFrame)页面布局,样式计算渲染执行RIC(RequestIdelCallback)问题9webpack中hash、fullhash、chunkhash和contenthash的区别从编译文件的开始到结束,模块加载、关闭、优化、block、hash、重构等都由它负责。这个时候,hash就是通过编译生成的。它关系到整个工程的建设。只要项目中有文件变化,整个项目构建的hash值就会发生变化,所有文件共享同一个hash值fullhash——全量hash是整个项目级别的。只要项目中任何一个文件的内容发生变化,打包后所有文件的哈希值都会发生变化。chunkhash--chunk,每个入口文件都是一个chunk,每个chunk由入口文件及其依赖组成,异步加载的文件也被视为一个chunk。每次编译模块时都会编译hunkhash,根据模块及其依赖的模块生成对应的chunkhash。当文件没有变化时,chunkhash没有变化,浏览器可以利用缓存机制快速加载。但是,每个chunk都有css和js,也就是说,当其中一个文件发生变化时,chunk会被重新编译,比如配置为filename:'bundle.[name].[chunkhash].js',一个js文件引入了css,修改后的js,css文件的hash值会发生变化。contenthash--为文件的内容生成不同的散列。仅当文件内容发生变化时才会重新生成哈希。使用mini-css-extract-plugin插件提取每个chunk的css文件,将css和js分离。然后改css,改哪个文件,哪个文件的hash值就会改,比如配置成newMiniCssExtractPlugin({//选项类似webpackOptions.output中同样的选项//两个选项都是可选的filename:"css/[name].[contenthash].css",chunkFilename:"css/[name].[contenthash].css"})问题106.toString()转换错误6.point有歧义,电脑不知道是不是是获取符号或小数点。如果把6用括号括起来,就不会报错{}.toString()转换错误,{}计算机不知道是代码块还是对象,括号把[objectObject]中的每个元素括起来[].toString()arraytooutput以字符串形式输出,这里输出空[]==[]false,比较引用,引用值不一样[]==![]true[]地址不为空,![]是false1。如果两个值类型相同,则比较它们的值或引用地址2.如果两个值类型不同,则可能相等。按照以下规则进行类型转换和比较:1.如果一个为null,另一个为undefined,则它们相等。2.如果一个是字符串,另一个是值,先把字符串转成值再比较。3.如果有一个值为真,则将其转换为1并进行比较;如果任何值为false,则将其转换为0并进行比较。4.如果一个是对象,另一个是值或字符串,则将对象转换为底层类型的值并进行比较。使用其toString或valueOf方法将对象转换为基础类型。问题11SVGCanvasSVG不依赖于分辨率(矢量图)每个图形都是一个DOM元素支持事件处理器适用于渲染区域较大的应用(谷歌地图)可以通过脚本和CSS修改只能通过脚本修改对象个数很小(<10k),图形越大性能越好不适合游戏应用Canvas取决于分辨率(位图)单个HTML元素,相当于不支持事件处理程序文本渲染能力差图形较小,对象当数量大(>10k),性能最好。适用于图像密集型游戏应用。问题12为什么可以调用'1'.toString()?vars=newObject('1');s.toString();s=空;创建Object类的实例。由于Symbol和BigInt的出现,对其调用new会报错。当前的ES6规范不推荐使用new来创建基本类型的包装类。调用实例方法。实例在方法执行后立即被销毁。整个过程体现了基本包装类型的性质,即属于基本数据类型,包括Boolean、Number、String。Issue13Object.isObject在严格相等的基础上修复了一些特殊情况下的错误,特别是+0和-0,NaN和NaN。functionis(x,y){if(x===y){//当运行到1/x===1/y时,x和y都为0,但是1/+0=+Infinity,1/-0=-Infinity,不一样returnx!==0||y!==0||1/x===1/y;}else{//NaN===NaN为false,这个是No,我们这里做截取,x!==x,那么一定是NaN,y也是一样的。//两者都是NaN时返回truereturnx!==x&&y!==y;}问题14.浏览器不支持Promise.allSettled当浏览器不支持Promise.allSettled时,可以polyfillif(!Promise.allSettled){constrejectHandler=reason=>({status:"rejected",reason})constresolveHandler=value=>({status:"fulfilled",value})Promise.allSettled=promises=>Promise.all(promises.map((promise)=>Promise.resolve(promise).then(resolveHandler,rejectHandler))//每个Promise都需要用Promise.resolve包裹//以防止传递非promise);}问题15如何使(a==1&&a==2&&a==3)为真?部署[Symbol.toPrimitive]interfaceleta={[Symbol.toPrimitive]:(function(hint){leti=1;returnfunction(){return我++;};})(),};或者数据劫持leti=1leta=newProxy({},{i:1,get:function(){return()=>this.i++}})
