一、前端性能优化
网页的生成过程,大致可以分成五步。耗时的是第四步和第五步
- HTML代码转化成DOM
- CSS代码转化成CSSOM(CSS Object Model)
- 结合DOM和CSSOM,生成一棵渲染树(包含每个节点的视觉信息)
- 生成布局(layout),即将所有渲染树的所有节点进行平面合成
- 将布局绘制(paint)在屏幕上
重排和重绘会不断触发,这是不可避免的。但是,它们非常耗费资源,是导致网页性能低下的根本原因。提高网页性能,就是要降低"重排"和"重绘"的频率和成本,尽量少触发重新渲染。
- 减少HTTP请求
- 使用CDN
- 添加Expires头
- 压缩组件
- 将样式表放在头部
- 将脚本放在底部
- 避免CSS表达式
- 使用外部的JavaScript和CSS
- 减少DNS查找
- 精简JavaScript
- 避免重定向
- 删除重复脚本
提高性能的九个技巧
第一条,DOM 的多个读操作(或多个写操作),应该放在一起。不要两个读操作之间,加入一个写操作。
第二条,如果某个样式是通过重排得到的,那么最好缓存结果。避免下一次用到的时候,浏览器又要重排。
第三条,不要一条条地改变样式,而要通过改变class,或者csstext属性,一次性地改变样式。
第四条,尽量使用离线DOM,而不是真实的网面DOM,来改变元素样式。比如,操作Document Fragment对象,完成后再把这个对象加入DOM。再比如,使用 cloneNode() 方法,在克隆的节点上进行操作,然后再用克隆的节点替换原始节点。
第五条,先将元素设为display: none
(需要1次重排和重绘),然后对这个节点进行100次操作,最后再恢复显示(需要1次重排和重绘)。这样一来,你就用两次重新渲染,取代了可能高达100次的重新渲染。
第六条,position属性为absolute
或fixed
的元素,重排的开销会比较小,因为不用考虑它对其他元素的影响。
第七条,只在必要的时候,才将元素的display属性为可见,因为不可见的元素不影响重排和重绘。另外,visibility : hidden
的元素只对重绘有影响,不影响重排。
第八条,使用虚拟DOM的脚本库,比如React等。
第九条,使用 window.requestAnimationFrame()、window.requestIdleCallback() 这两个方法调节重新渲染。
1. 页面DOM节点太多,会出现什么问题?如何优化?
卡顿问题
本部分参考链接:https://blog.csdn.net/u013929284/article/details/56483035
2. 如何做性能监测
Chrome浏览器开发者工具的Timeline面板,是查看"刷新率"的最佳工具。左上角有一个灰色的圆点,这是录制按钮,按下它会变成红色。然后,在网页上进行一些操作,再按一次按钮完成录制。
Timeline面板提供两种查看方式:横条的是"事件模式"(Event Mode),显示重新渲染的各种事件所耗费的时间;竖条的是"帧模式"(Frame Mode),显示每一帧的时间耗费在哪里。
注:chrome57之后的版本timeline面板改为了performance面板
先看"事件模式",你可以从中判断,性能问题发生在哪个环节,是JavaScript的执行,还是渲染?
不同的颜色表示不同的事件。
- 蓝色:网络通信和HTML解析
- 黄色:JavaScript执行
- 紫色:样式计算和布局,即重排
- 绿色:重绘
哪种色块比较多,就说明性能耗费在那里。色块越长,问题越大。
window.requestAnimationFrame()方法。它可以将某些代码放到下一次重新渲染时执行。
我们可以使用window.requestAnimationFrame()
,让读操作和写操作分离,把所有的写操作放到下一次重新渲染。
function doubleHeight(element) { var currentHeight = element.clientHeight; window.requestAnimationFrame(function () { element.style.height = (currentHeight * 2) + 'px'; }); } elements.forEach(doubleHeight);
页面滚动事件(scroll)的监听函数,就很适合用 window.requestAnimationFrame() ,推迟到下一次重新渲染。
$(window).on('scroll', function() { window.requestAnimationFrame(scrollHandler); });
动画是最适用的场景
3. SEO和语义化
SEO(Search Engine Optimization)翻译为搜索引擎优化。seo是专门利用搜索引擎的搜索规则来提高目前网站在有关搜索引擎内的自然排名的方式。
搜索引擎看网页主要有三大标签最为重要:
title标签
keywords 标签
description标签
3.1 网站页面优化
- 主要优化网站的界面,布局清晰合理,导航条醒目实用,不要使用大面积广告占用页面。
- 代码标签优化,百度SEO优化,制作网站地图。
3.2 内容优化
- SEO优化重点在于长尾关键词,也就是内容页的优化。通常讲的28法则决定了关键词的优化主次。
- 不同页面需设置各异的标题(title),描述(description)以及关键字(keyword)。
- 标题title的定位:首页有标题与描述,栏目页有标题与描述,内容页有标题,同时网站中的多个页面标题不要相同。内容主体图文结合,且给每一张图片都添加alt属性,SEO排名,图片周边也要有相关关键词做补充。内容页标题设置:内容页标题名称 – 网站名称。内容页标题中有需要获取排名的关键字的,内容中须同时出现。
- 网站需保持有规律的更新和发布内容,不要发布杂乱无章的信息,因为站内原创文章标题的价值非常高。
3.3 内部链接优化
- 针对网站内所有的链接进行路径优化,SEO网站排名,尽量使用行间文字型链接,不要出现死链。
3.4 外部链接操作
导航是一个网站不可缺少的部分,网站导航一般分为主导航、副导航和分类导航
。导航一般出现在网站头部,或者网站底部,甚至也可以在内容部分,主要是为了方便小蜘蛛的爬取和用户的快速定位所需板块。以sf
为例,从SEO
的角度讲,导航应尽量以文字为主,而最好不要采取图片,若要采用图片的话,也应在图片部分加上必要的title
内容和alt
内容。
优化可以看看这个,写的很好:http://dy.163.com/v2/article/detail/EAQC3QG40518ST6L.html
本部分摘自:http://www.ruanyifeng.com/blog/2015/09/web-page-performance-in-depth.html
二、微信小程序
微信小程序和h5差异:
小程序与H5APP开发有一定的相似性,然而微信团队为小程序提供了独特的文件格式 WXML和WXSS分别对应H5APP的HTML和CSS。
1.Javascript的限制
出于安全考虑,通过传入字符串来执行代码的能力都被禁用了(new Function,eval,Generator).
由于小程序并非运行在浏览器中所以,与浏览器相关的对象模型(BOM)相关的API都没有,所以document,window对象不能使用,也没有cookie,非要传递cookie只能通过请求Header发送.
wx.request({ header:{cookie:''}, url:'', data:{}, success:function(){}, fail:function(){} });
2.小程序用storage代替了localstorage,sessionstorage.strage对每个程序的大小是5M,支持同步和异步.
3.打开的页面有五个的数量限制.
4.WXML,WXSS和传统的HTML,CSS有一定差异.
三、git
1. git状态码转换图
- Git 管理代码,保证代码版本迭代连续性,即:向A分支merge或者push代码时,A分支代码必须是当前代码的上一个版本,不然会产生冲突。(换句话说:Git确保当前的本地的代码为最新)
- Git有修改就有提交,就有新的代码版本,git管理维护的是修改。
- Git分支存储的是代码副本。
- push :实际上就是将本地分支合并到远端库分支;pull:实际就是将远端分支合并到本地分支。
2. 本地常用操作指令
2.1 创建git库
git init #在当前目录中生成一个.git 目录(含有.git目录的目录即是git仓库)
2.2 注册git用户
用于在团队合作开发中,表明代码作者。
git config --global user.name XXX #用户名
git config --global user.email XXX #用户邮箱
git config --list #查看用户信息
注:加--global,全局设置。
2.3 向git库添加修改
git add [path] #会把对应目录或文件,添加到stage状态
git add . #会把当前所有的untrack files和changed but not updated添加到stage状态
实际上是为修改内容添加index索引。
2.4 向版本库提交修改
git commit –m “XXXX” #提交修改,添加注释
注:git 提示: 未有add红色字体,未有commit绿色字体,已提交则worktree是干净的
2.5 查看当前代码库的状态
git status
2.6 查看版本信息
实际是查看修改提交信息
git log
git log --graph #以图形化(节点)展示当前git库的提交信息。
2.7 查看指定版本信息
git show sdjf974654dd…. #(show后面为每次提交系统自动生成的一串哈希值)
git show sdji97 #一般只使用版本号的前几个字符即可
2.8 撤销修改
git reset
① 撤销整体修改
git reset --hard #回到原来编辑的地方,改动会丢失。(同样适用于团队对于其他人的修改恢复)
git reset --hard sdv143kvf…... #可回到指定的版本#(hard后面为每次提交系统自动生成的一串哈希值)
git reset [path] 会改变path指定的文件或目录的stage状态,到非stage状态。
git reset 会将所有stage的文件状态,都改变成非stage状态。
② 撤销某次修改
回退1个change的写法就是git reset HEAD^,
2个为HEAD^^,
3个为HEAD~3,以此类推。
2.9 向远端库推送修改(提交修改)
git push origin 分支名
2.10 暂存修改
git stash可以把当前的改动(stage和unstage,但不包括untrack的文件)暂存。
然后通过git stash list查看。
并通过git stash apply重新取出来。但apply之前要保证worktree是干净的。
3. Git团队开发常用操作指令
3.1 获取远端库项目
git clone/pull
3.2 团队开发的基本流程(多分支合并一个分支)
git add . #添加改动的文件
git commit #(提交至本地)
git pull --rebase #(将服务器项目与本地项目合并)
git push #(将本地项目上传至远端库)
注:在提交前要git pull --rebase 一下,确保当前的本地的代码为最新。
4. Git 分支管理
4.1 建立分支
git branch AAA #建立分支AAA
4.2 分支切换
git checkout AAA #从当前分支切换到AAA分支 (若AAA分支不存在,则自动新建)
4.3 将分支与主枝master合并
git checkout master #(首先切换回主枝)
git merge AAA #(将分支AAA与主枝合并)
注:git merge:默认情况下,Git执行"快进式合并"(fast-farward merge),会直接将Master分支指向Develop分支。
使用--no-ff参数后,会执行正常合并,在Master分支上生成一个新节点。为了保证版本演进的清晰(保持提交曲线为直线),建议采用这种方法。
4.4 当前分支查看
git branch #默认有master(也称为主枝)
git branch -r #查看远端库分支
git branch –a #查看当前所有分支(包括本地分支和远端库分支)
4.5 删除分支
git branch –d AAA #删除分支AAA
4.6 切下远端库A分支到本地库A分支
git checkout -b A origin/A (若本地A分支不存在,则自动新建)
注:上面只是一些基本的操作命令,更多的命令可通过帮助文档查询。
帮助文档的使用:man git- <需查询的指令> #(git后面有“-”) 如commit的查询为 man git-commit
5. 本地代码上传Github
- Gtthub上建立远端仓库,复制下载链接。
- 本地指定目录下,Gitbash粘贴远端仓库下载链接拉取远端仓库代码。
- 复制本地需要提交的代码到远端仓库目录。
- Git add、commit、push 提交本地代码至Github远端仓库。
本部分内容摘自:https://www.cnblogs.com/gavincoder/p/9073368.html
四、移动端
1. 自适应
本部分参考链接:https://segmentfault.com/a/1190000012225828
2. pwa
PWA(Progressive Web App), 即渐进式web应用。PWA本质上是web应用,目的是通过多项新技术,在安全、性能、体验等方面给用户原生应用的体验。而且无需像原生应用那样繁琐的下载、安装、升级等操作。这里解释下概念中的“渐进式”,意思是这个web应用还在不断地进步中。因为目前而言,PWA还没有成熟到一蹴而就的程度,想在安全、性能、体验上达到原生应用的效果还是有很多的提升空间的。一方面是构建PWA的成本问题,另一方面是目前各大浏览器、安卓和IOS系统对于PWA的支持和兼容性还有待提高。
Service Worker
Service Worker是PWA的核心技术,它能够为web应用提供离线缓存功能,当然不仅如此,下面列举了一些Service Worker的特性:
-
基于HTTPS 环境,这是构建PWA的硬性前提。(LAMP环境网站升级HTTPS解决方案)
-
是一个独立的 worker 线程,独立于当前网页进程,有自己独立的 worker context
-
可拦截HTTP请求和响应,可缓存文件,缓存的文件可以在网络离线状态时取到
-
能向客户端推送消息
-
不能直接操作 DOM
-
异步实现,内部大都是通过 Promise 实现
3. 移动端手势
本部分参考链接:https://www.jianshu.com/p/0754d5daa27e
五、附加
1. 无限滚动方案
- 首页直接从服务器获取数据,将此数据进行缓存。
- 然后每次滚动页面,滚动到需要加载数据的临界点时,直接从缓存中提取下一页或者上一页的数据,加载到页面数据中。
优化--预加载
采用一种检测手段,检测用户会不会继续往下看,如果会,就进行预加载,不必等到用户翻到最底部
本部分参考链接:https://www.jianshu.com/p/3125ae249058
优化--图片懒加载
图片进入用户视野才会进行加载,而不是在dom树一构建好就进行加载
本部分参考链接:https://www.jianshu.com/p/d707565e5fa1
2. 如何处理兼容性问题
本部分参考链接:https://blog.csdn.net/qq_18826911/article/details/77678744
3. ES6 class与ES5 function区别及联系
关于构造器
- 在
function
定义的构造函数中,其prototype.constructor
属性指向构造器自身 - 在
class
定义的类中,constructor
其实也相当于定义在prototype
属性上
重复定义
- function会覆盖之前定义的方法
- class会报错
原型或者类中方法的枚举
- class中定义的方法不可用Object.keys(Point.prototype)枚举到
- function构造器原型方法可被Object.keys(Point.prototype)枚举到,除过constructor
- 所有原型方法属性都可用Object.getOwnPropertyNames(Point.prototype)访问到
都可通过实例的__proto__属性向原型添加方法
- 推荐使用Object.getPrototypeOf()获取实例原型后再添加方法
class没有变量提升
class定义的类没有私有方法和私有属性
class静态方法与静态属性
- class定义的静态方法前加static关键字
- 只能通过类名调用
- 不能通过实例调用
- 可与实例方法重名
- 静态方法中的this指向类而非实例
- 静态方法可被继承
- 在子类中可通过super方法调用父类的静态方法
- class内部没有静态属性,只能在外面通过类名定义。
4. vue怎么监听数组
普通的watch
data() { return { frontPoints: 0 } }, watch: { frontPoints(newValue, oldValue) { console.log(newValue) } }
数组的watch
data() { return { winChips: new Array(11).fill(0) } }, watch: { winChips: { handler(newValue, oldValue) { for (let i = 0; i < newValue.length; i++) { if (oldValue[i] != newValue[i]) { console.log(newValue) } } }, deep: true } }
对象的watch
data() { return { bet: { pokerState: 53, pokerHistory: 'local' } } }, watch: { bet: { handler(newValue, oldValue) { console.log(newValue) }, deep: true } }
对象的具体属性
data() { return { bet: { pokerState: 53, pokerHistory: 'local' } } }, computed: { pokerHistory() { return this.bet.pokerHistory } }, watch: { pokerHistory(newValue, oldValue) { console.log(newValue) } }
5. 写过webpack loader吗
loader就是一个node模块,它输出了一个函数。当某种资源需要用这个loader转换时,这个函数会被调用。并且,这个函数可以通过提供给它的this上下文访问Loader API。
module.exports = function(src) { //src是原文件内容(abcde),下面对内容进行处理,这里是反转 var result = src.split('').reverse().join(''); //edcba //返回JavaScript源码,必须是String或者Buffer return `module.exports = '${result}'`; }