游览器中javascript的执行过程(图文)


Posted in Javascript onMay 20, 2012

1. 大多数游览器的组件构成如图     

游览器中javascript的执行过程(图文)

在最底层的三个组件分别是网络,UI后端和js解释器。作用如下:
(1)网络- 用来完成网络调用,例如http请求,它具有平台无关的接口,可以在不同平台上工作
(2)UI 后端- 用来绘制类似组合选择框及对话框等基本组件,具有不特定于某个平台的通用接口,底层使用操作系统的用户接口
(3)JS解释器- 用来解释执行JS代码

ps:上图和知识点主要来自《HOW BROWSERS WORK: BEHIND THE SCENES OF MODERN WEB BROWSERS》 想深入了解的同学可以重点看下。
2. 大多数游览器(比如chrome)让一个单线程共用于执行javascrip和更新用户界面。这个线程通常被称为“游览器UI线程”, 每个时刻只能执行其中一种操作,这意味着当Javascript代码正在执行时用户界面无法响应输入,反之亦然。这样做是因为javascript代码的作用就是操作DOM更新用户界面,用同一个线程来做负责这两件事情可以更高效
3. 游览器UI线程的工作基于一个简单的队列系统,任务会被保存到队列中直到进程空闲。一旦空闲,队列中的下一个任务就被重新提取出来并运行。这些任务要么是运行javascript代码,要么执行UI更新,包括重绘和重排。
4. 重点再强调下,javascript是单线程运行,千万别被setTimeout()和setInterVal()这种函数迷惑而误以为它是多线程。
ok,基础点讲解完毕,让我们进入正题,来讲解在游览器中javascript的执行过程。
一、原理
一般而言,<script>标签每次出现都会霸道地让页面等待脚本的解析和执行,无论当前的Javascript是内嵌的还是包含了外链文件,页面的下载和渲染都必须停下来等待脚本执行完成。这在页面的生存周期中是必要的,因为脚本执行过程中可能修改页面内容,一个典型的例子就是在页面中使用document.write()。
当javascript代码是内嵌在html里面时,这点还是比较容易理解,但当javascript是外链文件时稍微有点负载,因为存在一个加载过程,而且游览器加载好这个js文件之后往往还对其缓存。
首先,我们用以下这个例子来说明下缓存问题

<html> 
<head> 
<script type='text/javascript' src='js/f2.js'></script> 
</head> 
<body> 
</body> 
</html>

第一次打开页面时:

游览器中javascript的执行过程(图文)

    第二次打开页面时:

游览器中javascript的执行过程(图文)

    从上例中可以明显看出,像chrome之类的高版本游览器会对js文件进行缓存,作用是不言而喻,减少网络请求。

其次,第二个问题,当一个javascript文件被加载时是否会阻塞其他javascript文件或者其他文件的加载。《高性能Javascript》一书中对这个问题做了较好的解答:各种游览器的低版本的处理是当一个javascript文件在加载时,会同时阻塞页面其他文件的加载(包括其他javascript文件),但IE8,Firfox3.5,Safari 4和Chrome 2都允许并行下载javascript文件,但遗憾的是,javascript下载过程仍然会组舍其他资源的下载,比如图片。尽管javascript脚本的下载过程不会相互影响,但页面仍然必须等待所有的javascript代码下载并执行完成才能继续。

这里说句题外话:游览器对同一域名下的并发链接数也是有限制的,其他一些参数如下:
游览器中javascript的执行过程(图文)
二、技巧
1. 脚本位置
由于脚本会阻塞页面其他资源的下载,因此推荐将所有的<script>标签放到<body>标签的底部,已尽量减少对整个页面下载的影响。
2. 将能合并的js文件合并
3. 无阻塞脚本
现在比较常用的方法就是动态加载执行脚本。你的原理是通过DOM,你几乎可以用Javascript动态创建HTML中的所有内容,其根本在于,<script>标签与页面中其他元素并无差异:都能通过DOM引用,都能在文档中移动,删除和创建。文件在改该<script>元素被添加到页面时开始现在,它不会阻止其他文件下载,只在执行阶段阻塞渲染。特别强调:《高性能javascript》一文中说“这种技术的重点在于:无论何时启动下载,文件的下载和执行都不会阻塞页面其他进程”,这并不是说它在执行不会阻塞其他javascript代码,而是要强调不会阻塞其他资源的下载等其他任务。
具体的代码如下:

function loadScript(url){ 
var ga = document.createElement('script'); 
ga.type = 'text/javascript'; 
ga.async = true; 
ga.src = url; 
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ga); 
}

4. 神奇的setTimeout()
这里我不过多的将setTimeout()的原理,有兴趣的读者可以具体去看《高性能javascript》的第六章。我重点强调下,setTimeout的第二个参数并不是一个精确的时间,二是必须在javascript线程空闲时才能运行。利用这个特性,如下代码简单可以实现等待其他js代码执行完毕后再执行function里面的代码。
setTimeout(function(){ 
// do some before other javascripe codes had processed 
}, 25)

但在function里面不要使用document.write()方法,因为执行setTimeout里面函数时往往已经到了页面onload之后,此时再执行 document.write 将导致当前页面的内容被清空,因为它会自动触发 document.open 方法。
《高性能Javascript》
HOW BROWSERS WORK: BEHIND THE SCENES OF MODERN WEB BROWSERS
Google Chrome源码剖析【一】:多线程模型
javascript异步加载详解
Javascript 相关文章推荐
JS和JQUERY获取页面大小,滚动条位置,元素位置(示例代码)
Dec 14 Javascript
原生javaScript做得动态表格(注释写的很清楚)
Dec 29 Javascript
JavaScript访问CSS属性的几种方式介绍
Jul 21 Javascript
js识别不同浏览器基于userAgent做判断
Jul 29 Javascript
基于Angularjs实现分页功能
May 30 Javascript
AngularJS教程之简单应用程序示例
Aug 16 Javascript
Servlet实现文件上传,可多文件上传示例
Dec 05 Javascript
JS实现获取进今年第几天是周几的方法分析
Jun 27 Javascript
Vue.js中对css的操作(修改)具体方式详解
Oct 30 Javascript
Vue拖拽组件列表实现动态页面配置功能
Jun 17 Javascript
微信小程序中的上拉、下拉菜单功能
Mar 13 Javascript
解决vue自定义组件@click点击失效问题
Apr 30 Vue.js
js中scrollHeight,scrollWidth,scrollLeft,scrolltop等差别介绍
May 16 #Javascript
JS字符串累加Array不一定比字符串累加快(根据电脑配置)
May 14 #Javascript
JQuery 返回布尔值Is()条件判断方法代码
May 14 #Javascript
JQuery选择器特辑 详细小结
May 14 #Javascript
IE6背景图片不缓存问题解决方案及图片使用策略多个方法小结
May 14 #Javascript
js split 的用法和定义 js split分割字符串成数组的实例代码
May 13 #Javascript
jQuery循环滚动展示代码 可应用到文字和图片上
May 11 #Javascript
You might like
php中获取关键词及所属来源搜索引擎名称的代码
2011/02/15 PHP
php获取通过http协议post提交过来xml数据及解析xml
2012/12/16 PHP
php动态变量定义及使用
2015/06/10 PHP
PhpStorm 如何优雅的调试Hyperf的方法步骤
2019/11/24 PHP
js日期时间补零的小例子
2013/03/05 Javascript
拖动table标题实现改变td的大小(css+js代码)
2013/04/16 Javascript
比较新旧两个数组值得增加和删除的JS代码
2013/10/30 Javascript
JS 屏蔽按键效果与改变按键效果的示例代码
2013/12/24 Javascript
div失去焦点事件实现思路
2014/04/22 Javascript
Google Maps API地图应用示例分享
2014/10/23 Javascript
js实现的倒计时按钮实例
2015/06/24 Javascript
jQuery鼠标事件汇总
2015/08/30 Javascript
浅析创建javascript对象的方法
2016/05/13 Javascript
Angular 4依赖注入学习教程之简介(一)
2017/06/04 Javascript
javascript基于定时器实现进度条功能实例
2017/10/13 Javascript
解决Vue打包之后文件路径出错的问题
2018/03/06 Javascript
vue简单练习 桌面时钟的实现代码实例
2019/09/19 Javascript
原生js实现二级联动菜单
2019/11/27 Javascript
Js图片点击切换轮播实现代码
2020/07/27 Javascript
vue-admin-template配置快捷导航的代码(标签导航栏)
2020/09/04 Javascript
[28:48]《真视界》- 2017年国际邀请赛
2017/09/27 DOTA
Linux(Redhat)安装python3.6虚拟环境(推荐)
2018/05/05 Python
python实现多层感知器
2019/01/18 Python
Python I/O与进程的详细讲解
2019/03/08 Python
Python从入门到精通之环境搭建教程图解
2019/09/26 Python
Python 装饰器@,对函数进行功能扩展操作示例【开闭原则】
2019/10/17 Python
基于python实现蓝牙通信代码实例
2019/11/19 Python
python中reload重载实例用法
2020/12/15 Python
CSS3 制作旋转的大风车(充满童年回忆)
2013/01/30 HTML / CSS
详解如何使用CSS3中的结构伪类选择器和伪元素选择器
2020/01/06 HTML / CSS
优秀管理者获奖感言
2014/02/17 职场文书
党的群众路线教育实践活动批评与自我批评发言稿
2014/10/16 职场文书
人事专员岗位职责
2015/02/03 职场文书
廉洁自律心得体会2016
2016/01/13 职场文书
修改并编译golang源码的操作步骤
2021/07/25 Golang
Windows环境下实现批量执行Sql文件
2021/10/05 SQL Server