2022.05.07
闭包
闭包其实只是一个绑定了执行环境的函数
闭包是一种能够在函数声明过程中,将环境信息与所属函数绑定在一起的数据结构。它是基于函数声明的文本位置的,因此也被称为围绕函数定义的静态作用域或词法作用域。
闭包不仅应用于函数式编程的高阶函数中,也可用于事件处理和回调中。
作用域链和闭包
作用域链
其实在每个执行上下文的变量环境中,都包含了一个外部引用,用来指向外部的执行上下文,我们把这个外部引用称为 outer。
词法作用域。这是因为在 JavaScript 执行过程中,其作用域链是由词法作用域决定的。
词法作用域
词法作用域就是指作用域是由代码中函数声明的位置来决定的,所以词法作用域是静态的作用域,通过它就能够预测代码在执行过程中如何查找标识符。
词法作用域是代码编译阶段就决定好的,和函数是怎么调用的没有关系。
根据词法作用域的规则,内部函数 getName 和 setName 总是可以访问它们的外部函数 foo 中的变量
在 JavaScript 中,根据词法作用域的规则,内部函数总是可以访问其外部函数中声明的变量,当通过调用一个外部函数返回一个内部函数后,即使该外部函数已经执行结束了,但是内部函数引用外部函数的变量依然保存在内存中,我们就把这些变量的集合称为闭包。比如外部函数是 foo,那么这些变量的集合就称为 foo 函数的闭包。
如果引用闭包的函数是一个全局变量,那么闭包会一直存在直到页面关闭;但如果这个闭包以后不再使用的话,就会造成内存泄漏。
如果该闭包会一直使用,那么它可以作为全局变量而存在;但如果使用频率不高,而且占用内存又比较大的话,那就尽量让它成为一个局部变量。
函数作用域链:如果在自身的函数作用域内并未找到变量, 就会往更上层作用域,例如函数或者全局作用域
讲讲你对 promise 的理解
1.对象的状态不受外界影响。Promise 对象代表一个异步操作,有三种状态:
pending: 初始状态,不是成功或失败状态
fulfilled: 意味着操作成功完成
rejected: 意味着操作失败
2.只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
Promise 对象的状态改变,只有两种可能:
1.从 Pending 变为 Resolved
2.从 Pending 变为 Rejected。
只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,再对 Promise 对象添加回调函数,也会立即得到这个结果
Promise 有哪些用法
Promise.all(): Promise.all 可以将多个 Promise 实例包装成一个新的 Promise 实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被 reject 失败状态的值。
Promise.all 获得的成功结果的数组里面的数据顺序和 Promise.all 接收到的数组顺序是一致的,即 p1 的结果在前,即便 p1 的结果获取的比 p2 要晚。这带来了一个绝大的好处:在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用 Promise.all 毫无疑问可以解决这个问题。
Promise.race: Promse.race 就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
Promise.any: 当传入的 promise 数组中有任意一个完成时就会终止,会忽略到所有被拒绝掉的 promise,直到第一个 promise 完成。若传入所有的 promise 被拒绝则会执行拒绝回调。
Promise.allSettled: 当给定的 promise 数组中的所有 promise 被拒绝后会返回一个拒绝的 promise 数组,与[]一一对应。
Promise.reject 里面写 try catch
try catch 不能捕获异步代码,所以不能捕获 promise.reject()的错误,并且 promise 期约故意将异步行为封装起来,从而隔离外部的同步代码
try catch 能对 promise 的 reject()落定状态的结果进行捕获
try catch 能捕捉到的异常,必须是
主线程执行
已经进入 try catch, 但 try catch 尚未执行完的时候抛出来的, 意思是如果将执行 try catch 分为前中后.只有中才能捕获到异常应该只在确切知道接下来该做什么的时候捕获错误(这里我单指 try catch)
try catch 不能捕获到 promise.resolve()的报错
讲讲你做了哪些主动发现问题的事情
旧版前端三剑客与现代框架 vue
视图和数据耦合起来,开始效率和定位问题的速度,其次就是他们对数据的处理,如果是数据的处理,我们可能会是,我们可能是直接 document.getElmentById 或者 class,我们只要在 vnode 层面的话 直接修改数据,框架层面会自动帮我们在视图上面修改,像 vue 的话相当于在虚拟 dom 层面 因为他这个虚拟 dom 是一个 js 对象,我们只要改这个对象的节点数据即可,他会比对完新旧 vnode 之后 去修改相对应的真实 dom。采用现代化的话 工程化层面会更好,如果做了工程化,页面的复用。
vue 和 jquery 的性能
你做了哪些工程化
(1) 使用 webpack 实现项目构建
设计架构这块
php 方面除了要提供挂载的 dom 给我们,还有一个权限之间的校验,前端做的层面的话会跟后端同学进行商量
性能方面的优化
在这里面有遇到什么困难吗
小程序登录流程
1.wx.login() 获取登录凭证 code,并回传到开发者服务器 2.调用 auth.code2Session 接口,获取用户唯一标识 OpenID、用户在微信开发平台账号下的唯一标识 uNionID 和回话密钥 session_key
临时登录凭证 code 只能使用一次
之后开发者服务器可以根据用户标识来生成自定义登录态,用于后续业务逻辑中前后端交互时识别用户身份。
对于小程序来说,也需要一个唯一的标识符来区分用户,也就是 session 来保持会话,但是小程序没有 cookie, 因此我们的唯一标识符会被存储在 localstorage 里面,每次发请求时,都会从 localStorage 里面拿到这个唯一标识符,带在请求中。
微信的 openid 和 code
openid 用来标识这个唯一的微信用户,也就是说,一个微信用户相对于一个公众号(主体)的 openid 是唯一的,是不会变的。
就是通过 code, 对于同一个用户,每次获取到的 code 都会改变,有有效期。我们把 code 作为参数,调用指定的微信服务器的接口,就可以拿到用户的 openid 。
如何拿到 code
微信内 h5 页面的方法是:跳到指定的微信的承接页面,再跳回到本页面,url 链接上就会被拼上 code 。 小程序的方法是: 通过调用 wx.login() 方法,就可以拿到用户的 code
微信小程序登录体系
通过 wx.login()获取到用户的 code
通过 wx.request() 方法请求我们自己的后端,我们自己的服务端把 appid , appsecret 和 code 一起发送到微信服务器。 appid 和 appsecret 都是微信提供的,可以在管理员后台找到
微信服务器返回了 openid
我们在自己的数据库中,查找 openid ,如果没有查到记录,说明该用户没有注册,如果有记录,则继续往下走 5.我们生成一个第三方 session , 也就是 session_id , 也就是用户唯一标识符。在 redis 中,把 session_id 和用户的身份存进去。 6.返回 3rd_session
小程序把 3rd_session 存到 storage 里面 8.下次请求时,先从 storage 里面读取,然后带给服务端 9.服务端从 redis 里面找到 3rd_session 对应的记录,然后校验有效期
讲讲 ssr 的流程
第一步: 服务端拼接 html 当用户请求某个页面的时候, server 端会拼接好一个页面的 html 结构返回给客户端, 例如下面的结构:
第二步: 客户端加载好的 html 展示出来了 上面的代码可以看出, html 结构加载完就可以展示出来了, 但是比如点击事假, 这类交互事件还是没有的, 需要加载/_ssr/2046328.js 后页面才能有交互(活起来), 所以我们还是要请求一堆 js 文件到本地。
第三步: js 执行 hydration 阶段完毕才可交互 hydration 字面意思类似'注水', 也就是通过 js 代码的执行, 动态的为当前页面上的 dom 绑定事件, 你可把当前获取到的 html 代码当做一根干货海参, js 代码理解成水, 而 hydration 过程就是用水把海参泡发, 达到可以食用的状态, 也就是页面可正常交互的状态。
看完上述 ssr 的流程后你有什么感觉? 有没有感觉 ssr 可能是个"视觉骗子", 我们简单罗列几个可优化的点:
虽然首屏展示的速度快了, 但是不可交互, 所以他的 tti(页面可交互时间)并没有太大的优化, 但不可否认也是有提升的只是不太多。 下载的 js 仍然是比较全量的 js 代码。 js 代码执行的时候, 仍然需要处理大量的逻辑, 还要重新处理一遍页面上的 dom。
组件基于 Vnode 来实现渲染 VNode 本身是 js 对象,兼容性极强,不依赖当前的执行的环境,从而可以在服务端渲染及原生渲染。虚拟 DOM 频繁修改,最后比较出真实 DOM 需要更改的地方,可以达到局部渲染的目的,减少性能损耗。
vue-server-renderer 是一个具有独立渲染应用程序能力的包,是 Vue 服务端渲染的核心代码。
浏览器渲染机制
如何变成合成层(GPU)
3D 或透视变换(perspective transform) CSS 属性
使用加速视频解码的 元素 拥有 3D
(WebGL) 上下文或加速的 2D 上下文的 元素
混合插件(如 Flash)
对自己的 opacity 做 CSS 动画或使用一个动画变换的元素
拥有加速 CSS 过滤器的元素
元素有一个包含复合层的后代节点(换句话说,就是一个元素拥有一个子元素,该子元素在自己的层里)
元素有一个 z-index 较低且包含一个复合层的兄弟元素(换句话说就是该元素在复合层上面渲染)
合成层的优点
一旦 renderLayer 提升为了合成层就会有自己的绘图上下文,并且会开启硬件加速,有利于性能提升
合成层的位图,会交由 GPU 合成,比 CPU 处理要快
当需要 repaint 时,只需要 repaint 本身,不会影响到其他的层
对于 transform 和 opacity 效果,不会触发 layout 和 paint
注意:
提升到合成层后合成层的位图会交 GPU 处理,但请注意,仅仅只是合成的处理(把绘图上下文的位图输出进行组合)需要用到 GPU,生成合成层的位图处理(绘图上下文的工作)是需要 CPU。 当需要 repaint 的时候可以只 repaint 本身,不影响其他层,但是 paint 之前还有 style, layout,那就意味着即使合成层只是 repaint 了自己,但 style 和 layout 本身就很占用时间。 仅仅是 transform 和 opacity 不会引发 layout 和 paint,那么其他的属性不确定。 总结合成层的优势:一般一个元素开启硬件加速后会变成合成层,可以独立于普通文档流中,改动后可以避免整个页面重绘,提升性能。
合成层的缺点
利用合成层可能踩到的坑 合成层占用内存的问题 层爆炸,由于某些原因可能导致产生大量不在预期内的合成层,虽然有浏览器的层压缩机制,但是也有很多无法进行压缩的情况,这就可能出现层爆炸的现象
获取随机数
最后更新于
这有帮助吗?