Aimee

personal blog

欢迎来到我的个人站~


react相关

  • react项目中有哪些细节可以优化?实际开发中做过哪些优化?
  • 分包,减少资源加快首屏打开的速度
  • 由于react是父级props改变之后,所有于props不相关子组件在没有条件控制的情况下,也会触发render渲染,这是没有必要的,可以结合react的pureComponent以及React.memo等做浅比较
  • 最后就是保证整个应用的可用性,为组件创建错误边界,可以使用componentDidCatch来处理
  • 保证数据的不可变性
  • 使用唯一的键值迭代
  • 使用web worker 做密集型的任务处理
  • 不在render中处理数据
  • 不必要的标签用React.Fragments

  • 说一下进程与线程?node中的进程和线程是如何进行通信的?
  • 为什么说多个域名来存储网站资源会更有效?
    • 1.动静分离需求,使用不同的服务器处理请求,动态内容服务器只处理动态内容,不处理别的,提高效率,这样使得CDN缓存更方便
    • 突破浏览器并发限制,现阶段各大浏览器的同一域名最大并发请求数量是6个或者以上。
    • 节约cookie带宽,在访问服务器时,cookie会占用一定的带宽,使用多个域名进行分流
    • 节约主域名的连接数,从而提高客户端网络带宽的利用率,优化页面响应速度。每个域名所响应的客户端请求越少,反应时间也就越短,客户端页面可以更快下载数据
    • 避免不必要的安全问题,例如cookie的隔离,客户端对服务器进行请求时,发送数据到达的地址会用一个第三方的域名,防止上传恶意数据对cookie进行窃取
  • es6代码转es5代码实现思路
      1. 将代码字符串解析成抽象语法树,即所谓的AST
      1. 对AST进行处理,在这个阶段可以对ES6代码进行相应转换,即转成ES5代码
      1. 根据处理后的AST再生成代码字符串
  • babel原理
      1. 解析Parse: 将代码解析生成抽象语法树(即AST),也就是计算机理解我们代码的方式,而babel则是通过babylon实现的,简单来说就是一个队员js代码编译过程,进行了词法分析与语法分析的过程
      1. 转换Transform:对于AST进行变换一系列的操作,babel接受得到AST并通过balbel-traverse 对其进行遍历,在此过程进行添加、更新及移除等操作
      1. 生成Generate:将变换后的AST再转换为JS代码,使用的模块是babel-generator
  • 说下什么是Reflect?有什么作用?你对元编程是如何理解的?有没有实际应用的例子?
    • 定义:Relect 是ES6引入的一个新的对象,它提供拦截javascript操作方法。这些方法与proxy handles的方法相同。Reflect不是一个函数对象,因此它是不可构造的。
    • 与大多数全局对象不同Reflect并非一个构造函数,所以不能通过new运算符对其进行调用,或者将Reflect对象作为一个函数来调用。Reflect的所有属性和方法都是静态的

    他的主要作用有两点:

    • 一是将原生的一些零散分布在Object、Function或者全局函数里的方法(如:apply、delete、get、set),统一整合到Reflect上,这样可以更加方便统一的管理一些原生的API
    • 其次就是因为proxy可以改写默认的原生API,如果一旦原生API被改写可能就找不到了,所以Reflect也可以起到备份原生API的作用。
  • 元编程:从ES6开始,javascript获得了proxy和reflect对象的支持,允许你拦截并定义基本语言操作的自定义行为(例如:属性查找,赋值、枚举、函数调用等)。借助这两个对象,你可以在javascript元级别进行编程。能‘介入’到对象底层操作的进行过程中,并加以影响,元编程中的元的概念可以理解为程序本身。“元编程能让你拥有可以扩展程序自身能力”。

  • React事件绑定原理
    • React并不是将click事件绑定在真实的DOM上,而是在document处监听所有支持的事件,当事件发生并冒泡至document处时,React将事件内容封装并交由真正的处理函数运行,这样的方式不仅减少了内存消耗,还能在组件挂载销毁时统一订阅和移除事件。另外冒泡到document上的事件也不是原生浏览器事件,而是React自己实现的合成事件,因此我们不想要事件冒泡的话,调用event.stopPropagation是无效的,而应该调用event.preventDefault

    • 1.事件注册:

      • 组件装载、更新
      • 通过lastProps nextProps判断是否新增、删除事件分别调用事件注册、卸载方法
      • 调用eventPluginHub的enqueuePutListener进行事件存储
      • 获取document对象
      • 根据事件名称判断是进行冒泡还是捕获
      • 判断是否存在addEventListener方法,否则使用attachEvent(兼容IE)
      • 给document注册原生事件回调为disoatchEvent(统一的事件分发机制)
    • EventPluginHub负责管理React合成事件的callback,它将callback存储在listenerBank中,另外还存储了负责合成事件的Plugin
    • EventPluginHub的putListener方法是向存储容器中增加一个listener
    • 获取绑定事件的元素的唯一标识key
    • 将callback根据事件类型,元素的唯一标识key存储在listenerBank中
    • listenerBanck的结构是:listenerBanck[registrationName][key] ` - 触发documnet注册原生事件的回调dispatchEvent
    • 获取到触发这个事件最深一级的元素,这里的事件执行利用了React的批处理机制
    • 合成事件
      • 调用EventPluginHub的extractEvents方法
      • 循环所有类型的eventPlugin(用来处理不同事件的工具方法)
      • 在每个EventPlugin中根据不同的事件类型,返回不同的事件池
      • 在事件池中取出合成事件,如果事件池是空的,那么创建一个新的
      • 根据元素nodeid(唯一标识key)和事件类型从listenerBank中取出回调函数
      • 返回带有合成事件参数的回调函数
  • react 中setState后发生了什么?setState为什么默认是异步的?setState什么时候是同步的?
    • 在代码中调用setState函数后,React会将传入的参数对象与当前的组件的状态进行合并,然后触发所谓的调和过程,经过调和过程,React会以相对高效的方式根据新的状态构建React元素树并且着手重新渲染整个UI界面,在React得到元素树之后,React会自动计算出新的树与老的树节点差异,然后根据差异对界面进行最小化重渲染。在diff算法中,React能够相对精确的知道哪些位置发生了改变以及如何改变,这就保证了按需更新

    • setState默认是同步的,意味着每执行一次就会触发diff和dom的修改,这样性能不好,如果是异步,可以把多个同步的setState合并一次更新

    • setState什么时候是同步的?

      • 在setTimeout或者原生事件中,是同步的
  • iframe 的一些劣势: 使用Iframe 会大幅增加内存和计算资源,因为 iframe 内所承载的页面需要一个全新并且完整的文档环境 Iframe 与上层应用并非同一个文档上下文导致

事件冒泡不穿透到主文档树上,焦点在子应用时,事件无法传递上一个文档流

主应用劫持快捷键操作 事件无法冒泡顶层,针对整个应用统一处理时效

跳转路径无法与上层文档同步,刷新丢失路由状态 Iframe 内元素会被限制在文档树中,视窗宽高限制问题 Iframe 登录态无法共享,子应用需要重新登录 Iframe 在禁用三方 cookie 时,iframe 平台服务不可用 Iframe 应用加载失败,内容发生错误主应用无法感知 难以计算出 iframe 作为页面一部分时的性能情况

无法预加载缓存 iframe 内容 无法共享基础库进一步减少包体积 事件通信繁琐且限制多

key的作用?

主要用于diff算法中,它是fiber算法对象的唯一标识,其作用是用于判断节点是否可用,从而减少不必要的diff, 提高diff的效率

  • key 应该是唯一的,key 不要使用随机值,避免使用 index 作为 key,否则会导致非受控组件的 state (比如输入框) 可能相互篡改,会出现无法预期的变动

https://juejin.cn/post/6844903922453200904