高性能JavaScript

# JavaScript简介
## 设计目标
JavaScript最初的目标是改善网页的用户体验。JavaScript能代替服务器处理页面中类似表单验证的简单任务,这样节省了与服务器连接的大量时间
## JavaScript引擎
**浏览器使用JavaScript引擎解释执行JavaScript代码,作为浏览器的组成部分之一,JavaScript引擎一般情况下都是由浏览器开发商自行开发的,(如IE9的Chakra、Firefox的TraceMonkey、Chrome的V8),其中Chrome所使用的V8进行了极大的性能升级,作为一款为JavaScript打造的实时编译引擎,它将JavaScript转换为机器码来执行,极大地提升了JS的执行效率**
> **解释器和编译器的主要区别**
> * 编译器无法直接执行源代码,而是先将源代码编译后生成中间码或者是机器码(典型的使用编译器的语言有:C/C++/Java/C#);而解释器则是直接逐行解析源代码并执行(典型的使用解释器的语言有JavaScript/html)
>* 编译型语言的源代码有错误的话无法通过编译,无法生成可执行代码,更无法执行程序;而解释型语言只有执行时才会判断是否出错,即使一句出错,也可以继续执行下一句
>* 编译型的语言都为强类型,类型检验较为严格,而解释型语言多为弱类型,如js中的var a,a可以为字符串也可以为整形
>* 编译型语言的执行效率要大大优于解释型语言,因为编译器在编译过程中会根据不同的平台自动优化源代码,并且一次编译后生产的字节码或者是机器码可以到处执行;而解释型语言缺少编译优化的过程,并且逐行执行效率低下,每次执行都要重新解释一遍,并且安全性较低
## JavaScript语言特性
* **单线程** 由于Javascript作为浏览器脚本语言,主要的用途是和用户互动,以及操作DOM节点,这决定了它只能是单线程,否则会带来很复杂的同步问题。所以,为了避免复杂性,从诞生起,Javascript就是单线程的,这已经成为这门语言的核心特征,将来也不会改变
* **任务队列** 由于JavaScript是单线程的,所以所有的任务需要排队执行,但是如果前一个任务耗时很长(例如一些从网络读取数据的操作)的话,后一个任务就不得不等待执行。为此JS将任务分为两种,一张是同步任务,另一种是异步任务
>* **同步任务** 在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务
>* **异步任务** 不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行
>* **同步任务和异步任务运行机制**
>>* 所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)
>>* 主线程之外,还存在一个任务队列(task queue),只要异步任务有了执行结果,就会在任务队列中放置一个事件
>>* 一旦执行栈中的同步任务执行完毕,系统就会读取任务队列,看看里面有哪些事件,那些对应的异步任务就结束等待状态,进入执行栈开始执行
>>* 主线程不断重复上面的步骤
* **事件和回调函数** 任务队列是一个事件的队列,IO设备完成一项任务,就在任务队列中添加一个事件,表示相关的异步任务可以进入执行栈了,主线程读取任务队列,就会读取里面有哪些事件。任务队列中的事件,除了IO设备的事件以外,还包括一些用户产生的事件(比如鼠标点击,页面滚动等),只要指定过回调函数,这些事件发生时就会进入任务队列,等待主线程读取所谓"回调函数"(callback),就是那些会被主线程挂起来的代码。异步任务必须指定回调函数,当主线程开始执行异步任务,就是执行对应的回调函数。
"任务队列"是一个先进先出的数据结构,排在前面的事件,优先被主线程读取。主线程的读取过程基本上是自动的,只要执行栈一清空,"任务队列"上第一位的事件就自动进入主线程。但是,由于存在后文提到的"定时器"功能,主线程首先要检查一下执行时间,某些事件只有到了规定的时间,才能返回主线程。
* **Event Loop** 主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)
* **定时器** 除了放置异步任务的事件,"任务队列"还可以放置定时事件,即指定某些代码在多少时间之后执行。这叫做"定时器"(timer)功能,也就是定时执行的代码。定时器功能主要由setTimeout()和setInterval()这两个函数来完成,它们的内部运行机制完全一样,区别在于前者指定的代码是一次性执行,后者则为反复执行

# JavaScript加载与执行
**JavaScript具有阻塞特性,由于脚本执行过程中可能会修改页面内容,所以在遇到<script>标签时,无论当前JavaScript代码是内嵌的还是包含在外链文件中,页面的下载和渲染都必须等待脚本下载(外链脚本)和执行完毕**

## 脚本位置
HTML4规范指出<script>标签可以放在HTML文档的<head>或<body>中,并且允许出现多次。按照惯例,<head>中的<script>标签用来加载外链JavaScript文件,挨着的<link>标签用来加载外部CSS文件或者其他页面元信息,理论上说,把与样式和行为有关的脚本放在一起,并先加载它们,有助于确保页面渲染和交互的正确性
> 但是与此同时,在<head>中加载过多的外链JavaScript文件会带来严重的性能问题,因为脚本会阻塞页面渲染,所以直到所有的脚本下载并执行完成之后,页面的渲染才会继续
> 目前多数浏览器都支持并行下载JavaScript文件,但是脚本阻塞问题仍然存在,页面的渲染仍然需要等待所有JS代码下载并执行完毕才能继续
> 由于脚本会阻塞页面的渲染过程,因此还是建议将所有<script>标签放在<body>标签的底部

## 组织脚本
**考虑到Http请求会带来额外的性能开销,因此下载单个100KB文件将比下载4个25KB的文件更快,有一些离线的打包工具或者在线服务可以进行多个js文件的整合**

posted on 2017-11-07 10:18  -Sunfan314-  阅读(89)  评论(0)    收藏  举报

导航