关于几次面试总结的前端发展学习方向

自离职以后,一直陆陆续续的面试了几家公司 ,当然有通过的也有没过的,虽然最后都因为种种原因不尽人意,不过还是觉得自己收获挺大,同时也在渐渐的找回丢失已久的方向。下面我来讲讲现在出去前端面试一般会问和需要掌握的几项技术能力吧

一、前端工程化

    所谓前端工程化似乎也没有一个完整的定义,目前的理解就是,只要能提高前端工作开发效率的,即为前端工程化。其实现在主流的几个前端框架如 vue , react 都有自己的脚手架工具,大大的提升开发效率,再也不像从前的开发,因为前期项目结构搭建从而花费一两天的时间去自己正确配置webpack。同时由于mvvm框架组件化的开发思想,以及git版本控制工具以及npm包管理工具的使用,已经能够使一个项目在不同人员,不同pc之间实现并行开发,前端工程化的作用可见一斑。

    当然这里最重要的部分可以说就是脚手架工具的使用,而脚手架一般是基于webpack来搭建的。因此,在工程需要更改配置或者新增配置的过程中,也要求我们对webpack基础的了解,能够在脚手架的基础上更改配置,甚至能够自己搭建符合自己项目的脚手架工具,这就需要我们对webpack或者 glup,grunt的了解了,因此为了提示竞争力,还是得去了解基本的构建工具使用方法,以至于能够开发出符合自己项目的脚手架。

二、前端性能优化

    关于前端性能优化一直是一个老生常谈的问题,不管是代码优化,还是减少http请求都是优化的一种手段。接下来具体谈谈vue-cli构建后的优化。

    由于vue-cli一般打包后的页面都是spa的形式,因此不可避免的会导致最后生成的app.js文件体积过大,这里涉及到两个方面,一个是资源的按需引入,还有是否使用分模块 或者分路由的方式打包项目。

    关于路由的按需加载,目前总共有三种形式:

{ // 这种情况会将组件单独的打包为一个js文件
    path: '/demo',
    name: 'demo',
    component: resolve => require(['../components/demo'], resolve)
}
{ // 这种情况同样将组件单独的打包为一个js文件
    path: '/demo',
    name: 'demo',
    component: () => import('../components/demo')
}

    以上两种情况都可以实现路由按需加载,但是每个路由组件都会单独的生成一个js文件,在路由比较多且组件量级小的情况下,太多的 js 文件也是没有必要的,因此有了接下来的模块化打包的方法:

{ // 这种情况会将 require.ensure 末尾参数chunkName相同的路由组件打包为同一个js文件
    path: '/demo',
    name: 'demo',
    component: resolve => require.ensure([], () => resolve(require('../components/demo')), 'demo')
},
{            
    path: '/demo2',
    name: 'demo2',
    component: demo2
    component: resolve => require.ensure([], () => resolve(require('../components/demo2')), 'demo')
}
{ // 同上会将指定webpackChunkName相同的路由组件打包为同一个js文件
    path: '/demo',
    name: 'demo',
    component: () => import(/* webpackChunkName:'demo'*/ '../component/demo.vue')
},
{            
    path: '/demo2',
    name: 'demo2',
    component: demo2
    component: () => import(/* webpackChunkName:'demo'*/ '../component/demo2.vue')
}

    通过以上方式,我们可以将互相之间关联性比较强的路由组件或者相同功能模块下的路由组件打包为一个js文件,既减少了app.js的体积也不至于生成太多的js文件添加请求的数量。

    当然vue-cli build以后生成的js文件不仅仅只有app.js 还有 vendor.js 和 manifest.js 关于这几个js文件的作用如下:

    app.js:基本就是你实际编写的那个app.vue(.vue或.js?),没这个页面跑不起来。

    vendor.js: vue-cli全家桶默认配置里面这个chunk就是将所有从node_modules/里require(import)的依赖都打包到这里,所以这个就是所有node_modules/下的被require(import)的js文件。这里需要注意在使用ui框架的时候,尽量使用按需引用组件的方式,因为一个ui框架实际上有很多组件我们是使用不到的,瞒目的全局引入整个ui框架的组件会导致引入一些用不到的组件代码,增大打包后文件的体积。

    manifest.js: 最后一个chunk,被注入了webpackJsonp的定义及异步加载相关的定义(webpack调用CommonsChunkPlugin处理后模块管理的核心,因为是核心,所以要第一个进行加载,不然会报错).

    以上为脚手架工具build分模块打包减少文件体积的优化方式,其他的还有如: 雪碧图,iconfont,图片压缩,cdn技术等优化。

三、浏览器缓存机制

    什么是浏览器缓存呢?简单来说,浏览器缓存其实就是浏览器保存一些通过HTTP获取的资源,是浏览器将网络资源存储在本地的一种行为。

    浏览器缓存的好处:当浏览器发起请求,如果请求资源被命中缓存,将直接返回本地浏览器缓存的内容,不再向服务器发起请求。减少了网络请求的时间以及服务器的负担(改场景为强缓存,且不同浏览器实现方案不一致,有些浏览器虽然命中强缓存返回缓存内容后还是会向服务器发起一个请求)。

    浏览器缓存又分为强缓存和协议缓存。

强缓存

    浏览器在加载资源时,会先根据本地缓存资源的 header 中的信息判断是否命中强缓存,如果命中则直接使用缓存中的资源不会再向服务器发送请求(Response Header里面的Cache-Control和Expires这两个属性,当两个都存在时,Cache-Control优先级较高)。

    Expires: 该字段是 http1.0 时的规范,它的值为一个绝对时间的 GMT 格式的时间字符串,比如 Expires:Mon,18 Oct 2020 23:59:59 GMT。这个时间代表着这个资源的失效时间,在此时间之前,即命中缓存。这种方式有一个明显的缺点,由于失效时间是一个绝对时间,所以当服务器与客户端时间偏差较大时,就会导致缓存混乱。

    Cache-control: Cache-Control 是 http1.1 时出现的 header 信息,主要是利用该字段的 max-age 值来进行判断,它是一个相对时间,例如 Cache-Control:max-age=3600,代表着资源的有效期是 3600 秒。

协议缓存

    当强缓存没有命中的时候,浏览器会发送一个请求到服务器,服务器根据 header 中的部分信息来判断是否命中缓存。如果命中,则返回 304 ,告诉浏览器资源未更新,可使用本地的缓存。这里的 header 中的信息指的是 Last-Modify/If-Modify-Since 和 ETag/If-None-Match.

    Last-Modify/If-Modify-Since: 

    浏览器第一次请求一个资源的时候,服务器返回的 response header 中会加上 Last-Modify,Last-modify 是一个时间标识该资源的最后修改时间。

    当浏览器再次请求该资源时,request 的请求头中会包含 If-Modify-Since,该值为缓存之前返回的 Last-Modify。服务器收到 If-Modify-Since 后,根据资源的最后修改时间判断是否命中缓存。

    如果命中缓存,则返回 304,浏览器从缓存中获取资源。否则,说明资源修改过,服务器正常返回资源。

     缺点: 

    短时间内资源发生了改变,Last-Modified 并不会发生变化。

      周期性变化。如果这个资源在一个周期内修改回原来的样子了,我们认为是可以使用缓存的,但是 Last-Modified 可不这样认为,因此便有了 ETag。

ETag/If-None-Match:

    与 Last-Modify/If-Modify-Since 不同的是,Etag/If-None-Match 返回的是一个校验码。ETag 可以保证每一个资源是唯一的,资源变化都会导致 ETag 变化。服务器根据浏览器发送的 If-None-Match 值来判断是否命中缓存。

    与 Last-Modified 不一样的是,当服务器返回 304 Not Modified 的响应时,由于 ETag 重新生成过,response header 中还会把这个 ETag 返回,即使这个 ETag 跟之前的没有变化。

    Last-Modified 与 ETag 是可以一起使用的,服务器会优先验证 ETag,一致的情况下,才会继续比对 Last-Modified,最后才决定是否返回 304。

    补充:通过H5的pwa方案 已经可以通过 service worker 来操作浏览器的缓存内容了,即可通过前端js判断资源是否使用缓存内容,以及浏览器缓存的增删改查。

四、微前端的理解和实现方案

    微前端架构是一种类似于微服务的架构,它将微服务的理念应用于浏览器端,即将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。

    

17619523-e6015d5ddfc04825.png

微前端的优势

    1.运行时无关,在同个页面使用多个框架而不需要刷新页面(例如:vue、react、angular等等)

     2.独立开发,独立部署

     3.使用新框架编写代码,而无需重写现有应用程序

      4.独立运行时每个子应用之间状态隔离,运行时状态不共享


    主要思路:如果不考虑浏览器兼容性,通常第一个浮现到我们脑海里的方案会是 Web Components。基于 Web Components 的 Shadow DOM 能力,我们可以将每个子应用包裹到一个 Shadow DOM 中,保证其运行时的样式的绝对隔离。

    由于目前微前端实现的案例不多,褒贬不一,因此并没有一个权威或者比较能够认同的解决方案,https://github.com/umijs/qiankun 该git链接为蚂蚁金服开源的一套微前端解决方案,具体可参考官方文档。

五、前端的PWA方向

    什么是PWA?

    Progressive Web App, 简称 PWA,是提升 Web App 的体验的一种新方法,能给用户原生应用的体验。

    PWA 能做到原生应用的体验不是靠特指某一项技术,而是经过应用一些新技术进行改进,在安全、性能和体验三个方面都有很大提升,PWA 本质上是 Web App,借助一些新技术也具备了 Native App 的一些特性,兼具 Web App 和 Native App 的优点。

PWA 的主要特点包括下面三点:

  • 可靠 – 即使在不稳定的网络环境下,也能瞬间加载并展现

  • 体验 – 快速响应,并且有平滑的动画响应用户的操作

  • 粘性 – 像设备上的原生应用,具有沉浸式的用户体验,用户可以添加到桌面

    PWA 本身强调渐进式,并不要求一次性达到安全、性能和体验上的所有要求,开发者可以通过 PWA Checklist 查看现有的特征。

    总的来说 PWA 就是能让你开发的webapp给用户原生的体验,包括离线浏览(service worker缓存),消息推送,生成app独立图标等功能。

    具体功能实现方案可参考 https://lavas.baidu.com/pwa/README

总结

    通过最近几次的面试虽然还没有找到称心的工作,但是也算是找到了自己的一个前行方向,本来做技术就得不停的学习,但是很容易在日复一日的业务逻辑开发上迷失方向,因此除了关注业务本身的同时 还是得多花些时间关注前端的发展和热点。当然这里只提到了一部分的方向和内容,还有很多前端方向可以学习发展。只是希望自己不要再迷失方向,有一个前进的目标并为之努力。

         

参考文章

《html meta 标签和浏览器缓存关系》

《实践这一次,彻底搞懂浏览器缓存机制》

《微前端——概述(一)》

《可能是你见过最完善的微前端解决方案》

《什么是PWA》

发表评论

电子邮件地址不会被公开。 必填项已用*标注