【Javascript】基础概述
2017-08-22 本文已影响0人
NinthG
JavaScript语言的历史
- 1990年底,欧洲核能研究组织(CERN)科学家Tim Berners-Lee,在全世界最大的电脑网络——互联网的基础上,发明了万维网(World Wide Web),从此可以在网上浏览网页文件。最早的网页只能在操作系统的终端里浏览,也就是说只能使用命令行操作,网页都是在字符窗口中显示,这当然非常不方便。
- 1992年底,美国国家超级电脑应用中心(NCSA)开始开发一个独立的浏览器,叫做Mosaic。这是人类历史上第一个浏览器,从此网页可以在图形界面的窗口浏览。
- 1994年10月,NCSA的一个主要程序员Marc Andreessen联合风险投资家Jim Clark,成立了Mosaic通信公司(Mosaic Communications),不久后改名为Netscape。这家公司的方向,就是在Mosaic的基础上,开发面向普通用户的新一代的浏览器Netscape Navigator。
- 1994年12月,Navigator发布了1.0版,市场份额一举超过90%。
- 1995年,Netscape公司雇佣了程序员Brendan Eich开发这种网页脚本语言。Brendan Eich有很强的函数式编程背景,希望以Scheme语言(函数式语言鼻祖LISP语言的一种方言)为蓝本,实现这种新语言。
- 1995年5月,Brendan Eich只用了10天,就设计完成了这种语言的第一版。
- 1995年12月4日,Netscape公司与Sun公司联合发布了JavaScript语言。
- 1996年3月,Navigator 2.0浏览器正式内置了JavaScript脚本语言。
- 1996年8月,微软模仿JavaScript开发了一种相近的语言,取名为JScript(JavaScript是Netscape的注册商标,微软不能用),首先内置于IE 3.0。Netscape公司面临丧失浏览器脚本语言的主导权的局面。
- 1996年11月,Netscape公司决定将JavaScript提交给国际标准化组织ECMA(European Computer Manufacturers Association),希望JavaScript能够成为国际标准,以此抵抗微软。
- 1997年7月,ECMA组织发布262号标准文件(ECMA-262)的第一版,规定了浏览器脚本语言的标准,并将这种语言称为ECMAScript。这个版本就是ECMAScript 1.0版。
- 1998年6月,ECMAScript 2.0版发布。
- 1999年12月,ECMAScript 3.0版发布,成为JavaScript的通行标准,得到了广泛支持。
- 2007年10月,ECMAScript 4.0版草案发布,对3.0版做了大幅升级,预计次年8月发布正式版本。草案发布后,由于4.0版的目标过于激进,各方对于是否通过这个标准,发生了严重分歧。以Yahoo、Microsoft、Google为首的大公司,反对JavaScript的大幅升级,主张小幅改动;以JavaScript创造者Brendan Eich为首的Mozilla公司,则坚持当前的草案。
- 2008年7月,由于对于下一个版本应该包括哪些功能,各方分歧太大,争论过于激进,ECMA开会决定,中止ECMAScript 4.0的开发(即废除了这个版本),将其中涉及现有功能改善的一小部分,发布为ECMAScript 3.1,而将其他激进的设想扩大范围,放入以后的版本,由于会议的气氛,该版本的项目代号起名为Harmony(和谐)。会后不久,ECMAScript 3.1就改名为ECMAScript 5。
- 2009年12月,ECMAScript 5.0版正式发布。Harmony项目则一分为二,一些较为可行的设想定名为JavaScript.next继续开发,后来演变成ECMAScript 6;一些不是很成熟的设想,则被视为JavaScript.next.next,在更远的将来再考虑推出。TC39的总体考虑是,ECMAScript 5与ECMAScript 3基本保持兼容,较大的语法修正和新功能加入,将由JavaScript.next完成。当时,JavaScript.next指的是ECMAScript 6。第六版发布以后,将指ECMAScript 7。TC39预计,ECMAScript 5会在2013年的年中成为JavaScript开发的主流标准,并在此后五年中一直保持这个位置。
- 2011年6月,ECMAscript 5.1版发布,并且成为ISO国际标准(ISO/IEC 16262:2011)。到了2012年底,所有主要浏览器都支持ECMAScript 5.1版的全部功能。
- 2013年3月,ECMAScript 6草案冻结,不再添加新功能。新的功能设想将被放到ECMAScript 7。
- 2013年12月,ECMAScript 6草案发布。然后是12个月的讨论期,听取各方反馈。
- 2015年6月,ECMAScript 6正式发布,并且更名为“ECMAScript 2015”。这是因为TC39委员会计划,以后每年发布一个ECMAScirpt的版本,下一个版本在2016年发布,称为“ECMAScript 2016”。
浏览器的渲染机制
以图为例
浏览器渲染机制- 解析 HTML 标签, 构建 DOM 树
- 解析 CSS 标签, 构建 CSSOM 树
- 把 DOM 和 CSSOM 组合成 渲染树 (render tree)
- 在渲染树的基础上进行布局, 计算每个节点的几何结构
- 把每个节点绘制到屏幕上 (painting)
CSS、JS 在 HTML 中的放置
浏览器的解析方式
浏览器解析html页面首先浏览器先下载html,然后在内存中把html代码转化成Dom Tree,
然后浏览器根据Dom Tree上的Node分析css和Images,当文档下载遇到js时,js独立下载。
CSS和JS的加载机制
js是阻塞加载,会影响页面加载的速度,如果js文件比较大,算法也比较复杂的话,影响更大。
CSS放在前端是页面渲染时首先是根据DOM结构生成一个DOM树然后加上CSS样式生成一个渲染树,如果CSS放在后面可能页面会出现闪跳的感觉,
或者是白屏或者布局混乱样式很丑直到CSS加载完成。
一般的解决方法
- js非阻塞加载解决方案
- 用defer标签
- 用createElement来动态生成,但是这样有一个问题就是加载顺序在IE下不一定会是按代码写的顺序来加载,可能会影响到依赖项,有些文件就是必须在另一个文件前引用。火狐跟opera是按顺序加载的
- 用ajax加载,也是非阻塞似的但是这种方法不支持CDN
- CSS的一般处理
一般来说css放头部js放底部来确保用户至少能早一点看到界面,让网站看起来至少反应快一点,不过如果css稍微有点多了,会让屏幕白屏时间更长
最优放置方法
把必须的js和css放顶部,把不那么重要的css和js放底部。
白屏和 FOUC
- 不同的浏览器对于CSS和HTML的处理方式不同
- 有的是等待CSS加载完成之后,对HTML元素进行渲染和展示(白屏问题)
- 有的是先对HTML元素进行展示,然后等待CSS加载完成之后重新对样式进行修改(FOUC无样式内容闪烁)
- 如果把CSS样式放在底部
- 对于IE浏览器,在某些场景下(新窗口打开,刷新等)页面会出现白屏,而不是内容逐步展现,如果使用 @import标签,即使 CSS 放入 link, 并且放在头部,也可能出现白屏。
- 对于IE浏览器,在某些场景下(点击链接,输入URL,使用书签进入等),会出现 FOUC 现象(逐步加载无样式的内容,等CSS加载后页面突然展现样式).对于 Firefox 会一直表现出 FOUC 。
- 如果把js文件放在头部,脚本会阻塞后面内容的呈现,脚本会阻塞其后组件的下载,出现白屏问题。
repaint&reflow
概念参考
- repaint
遍历所有的节点检测各节点的可见性、颜色、轮廓等可见的样式属性,然后根据检测的结果更新页面的相应部分。 - reflow
reflow指的是计算页面布局。某个节点reflow时会重新计算节点的尺寸和位置,而且还有可能触发其子节点、祖先节点和页面上的其他节点reflow。在这之后再触发一次repaint。reflow对性能的影响非常大,但是很不幸,reflow很容易被触发。
触发reflow的一些操作
- 插入、删除或者更新页面(文档树)中的节点。
- 修改页面的内容,例如在input标签中输入内容。
- 移动节点。
- 页面中的动画效果。
- 获取节点的尺寸,例如获取节点的offsetHeight,或者使用getComputedStyle函数获取节点尺寸。
- 改变节点样式。
- 改变节点的className属性。
- 增加或者删除样式表文件。
- window的resize。
- 滚动滚动条,即scroll。
改进方式
除了期待浏览器机制的迭代改进之外,还有一些点是在平常工作中需要注意的
- 避免多次设置行内样式,避免分别单独设置样式。比如node.style.height = ''; node.style.width = '';这都会多次触发reflow(现代浏览器好一些,远古浏览器不行)。
- 使用className,并且在尽可能内层的节点上做修改。className可以满足多个样式一次修改,只进行一次reflow。
- 当要批量操作某一个DOM树时可以先将其在文档树中移除,待操作完成后在添加到文档树中,这样可避免多次reflow。
- 避免频繁的获取节点尺寸,可以使用标量缓存节点尺寸,这也是以空间换时间的思想。
- 当某一区域需要频繁的dom操作时可以将其外部包裹一个fixed或者absolute布局。
- 避免使用table布局,table布局会触发更多的reflow。
异步加载脚本
在通过<script src="#"></script>
引入JS脚本时,如果没有特殊的标签属性,那么浏览器解析到这里的时候会立即执行该脚本(“立即”指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行。)
有两个标签属性可以控制异步加载脚本
- async
<script async src="script.js"></script>
加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步)。但并不保证加载顺序 - defer
<script defer src="script.js"></script>
加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。强调顺序,脚本将延迟到元素的解析和限时后执行