说到客户端的JavaScript,很容易联想到服务器端的JavaScript,服务器的JavaScript最常见最火的也就是node了,还有一个Rhino也是服务器端的JavaScript
今天主要聊聊客户端的JavaScript,也叫做web浏览器中的JavaScript,Window对象是所有客户端JavaScript特性和API的主要接入点
客户端的this与node的this
Window是客户端JavaScript下特有的对象,简单举几个例子聊聊this
然而这时浏览器端的JavaScript,node中不存在window,之前我在对象详解中聊过,JavaScript在浏览器中运行时会生成一系列的全局对象、属性、函数,node不存在window如果运行打印window是会报错的
node中的this
https://www.cnblogs.com/pssp/p/5321506.html
这篇文章可以参考,针对node基础的小伙伴,无基础可以跳过
Web浏览器中的Web页面
一些静态信息的页面,我们称之为文档(document)(由于加入了JavaScript,静态信息看上去会动来动去,但信息本身是静态的),相对于文档来说,其他的Web页面则感觉看上去更像是应用,类似数据交互,数据存储,看起来更像是图形化,而非文本化
Window对象是所有客户端JavaScript特性和API的主要接入点,它表示Web浏览器的一个窗口或窗体,使用window标识符来引用它,Window下所有的属性方法都可以打印window查看,比如常见的location属性,定时器方法,主要提点比较常用原生操作的到的属性
事件处理程序
事件处理程序可以让JavaScript代码修改窗口、文档、和组成文档的元素的行为。事件处理程序的属性名是以单词‘on’开始的,比如说:
elemnet.onclick=function(){this.innerHTML = new Date().toString()}
Window对象中onload处理程序是最重要的事件处理程序之一。当显示窗口中的文档内容稳定并可以操作时会触发它, 更多事件后续简单提点(内容太多,也不知道自己可以写多少)
Web应用里的JavaScript
JavaScript程序可以Document对象和它包含的Element对象遍历管理文档内容,比如说它可以通过操作css样式和类,修改文档内容的呈现,并且可以通过注册适当的事件处理程序来定义文档元素的行为。内容、呈现和行为的组合,叫做动态HTML或DHTML
JavaScript在web文档中的作用更多的是增强用户体验,使信息获取和传递更加容易,用户的体验不应依赖于JavaScript,不要因为你的‘秀’而成为了一个bug web程序员
在HTML中的JavaScript
最常见的就是内联,我们把JavaScript代码放置在<srcipt></script>标签中
其次放置在由<script>标签的src属性指定的外部文件中(使用src的优点可以百度一下,一些面试会提及)
放置在HTML事件处理程序中
放在一个URL里,这个URL使用特殊的“JavaScript:”协议
如果是XHTML(了解一下)
<script <![CDATA[
//JavaScript代码
]]></script>
HTML中的事件处理,我们有时候偷懒的效果就可以使用下方的操作
<button onclick="alert(1)">GET</button>
URL中的JavaScript了解一下(英语应该是有毛病的,请不要学)
<a href="javascript:new Date().toLocaleTimeString()">What is a time</a>
defer async
当JavaScript第一次添加到Web浏览器时,还没有API可以用来遍历文档的结构和内容,JavaScript唯一可以影响文档内容的方法就是快速生成内容,使用docum.write()方法,大家初学js的时候有没有写过这样的代码,我是敲了好几遍,我再来敲一下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>Table of Function</h1>
</body>
<script>
function factorial(n){
if(n<=1){
return n
}else{
return n*factorial(n-1) //n的阶乘
}
}
document.write('<table>')
document.write("<tr><th>n</th><th>n!</th></tr>")
for(var i=1;i<=10;i++){
document.write("<tr><td>"+i+"</td><td>"+factorial(i)+"</td></tr>")
}
document.write("</table>")
document.write( new Date())
</script>
</html>
document.write()方法是其中一个由Netscape 2浏览器实现非常早起的脚本化API(脚本化后期提),它曾在DOM 之前就被很好的引入了,也曾是在文档中显示计算后的文本唯一的方法。简单一点总结就是,只有在解析文档时才能使用write()方法输出到HTML到当前文档中,如果将它放在函数定义或者事件程序调用,它就会擦除该文档所有内容,先于DOM树构建完成之前执行(可以这么理解)
<h1 onclick='write()'>Table of Function</h1>
</body>
<script>
function write(){
document.write('<h1>666</h1>') //不管里面写什么,点击将清空所有内容
}
</script>
当HTML解析器遇到script元素时,默认先执行脚本(圈起来),然后再恢复文档的解析和渲染。这对于内联的JavaScript没有什么问题,但如果脚本源代码是由一个src指定的外部文件,这意味着脚本后面的文档部分在下载和执行脚本之前,都不会出现在浏览器中(src与url的区别小伙伴可百度一下),这里是指文档的文本内容已经截入,但没有浏览器引擎解析成DOM树,DOM树的生成是受JavaScript代码执行影响的,JavaScript会“阻塞”页面UI的渲染。
简单演示一下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h2>666</h2>
<script>
while(true){
}
</script>
<h1>666</h1>
</body>
</html>
在前面提过,DOM树的生成是受JavaScript代码执行影响的,我在上方定义了一个死循环,此时内容已经截入,但DOM树未解析成,因此我们看不到浏览器中有内容
Script标签有两个属性,defer 和 async,两个属性都是不允许操作write()方法,也不能说不允许,可以说不执行,必须配合src使用,也就是说必须是引入外部脚本文件的时候使用,两者都存在以async效果为先。两个属性相当于告知了浏览器链接进来的脚本不会使用document.write()方法,也不会生成文档内容,因此浏览器在下载脚本时继续解析和渲染文档,区别在于async是异步操作。此处就不测试引入的document.write(),加defer 与async都是不予执行的
简单做个比较,其实用的也不多,想深入可以再百度一下
在外部编写一个js文件
while(true){
}
在HTML中引入
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h2>666</h2>
<script defer src="./test.js">
</script>
<h1>666</h1>
</body>
</html>
DOM树还是无法解析
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h2>666</h2>
<script async src="./test.js">
//此处换属性了
</script>
<h1>666</h1>
</body>
</html>
此时DOM树已经解析完成,浏览器有元素
今天内容差不多到这,很多东西也没有整理,比如说浏览器的同源策略,兼容与互用,安全与可访问 ,浏览器的测试原生AJAX,接下去想到啥写啥(^ _ ^)
简单介绍一下浏览器解析代码的流程,如有错请指出
区分进程和线程
最常见进程就是我们的任务管理器吧,打开任务管理器就能看到一系列的进程,而且可以看到每个进程的内存资源信息以及cpu占有率
进程是cpu资源分配的最小单位(是能拥有资源和独立运行的最小单位)
线程是cpu调度的最小单位(线程是建立在进程的基础上的一次程序运行单位,一个进程中可以有多个线程)
浏览器是多进程的
浏览器是多进程的
浏览器之所以能够运行,是因为系统给它的进程分配了资源(cpu、内存)
简单点理解,每打开一个Tab页,就相当于创建了一个独立的浏览器进程。
重点是浏览器内核(渲染进程)
可以这样理解,页面的渲染,JS的执行,事件的循环,都在这个进程内进行。接下来重点分析这个进程(不提其他的,怕多说多错,自己了解的也不是很透彻)
1.GUI渲染线程
负责渲染浏览器界面,解析HTML,CSS,构建DOM树
注意,GUI渲染线程与JS引擎线程是互斥的,当JS引擎执行时GUI线程会被挂起(相当于被冻结了),GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。如果JS引擎出问题(比如死循环,报错)导致DOM无法继续渲染
2.JS引擎线程
也称为JS内核,负责处理Javascript脚本程序。(例如V8引擎)
JS引擎线程负责解析Javascript脚本,运行代码。
JS引擎一直等待着任务队列中任务的到来,然后加以处理,一个Tab页(renderer进程)中无论什么时候都只有一个JS线程在运行JS程序
同样注意,GUI渲染线程与JS引擎线程是互斥的,所以如果JS执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞。
JS阻塞页面加载
从上述的互斥关系,可以推导出,JS如果执行时间过长就会阻塞页面。
譬如,假设JS引擎正在进行巨量的计算,此时就算GUI有更新,也会被保存到队列中,等待JS引擎空闲后执行。
然后,由于巨量计算,所以JS引擎很可能很久很久后才能空闲,自然会感觉到巨卡无比。
所以,要尽量避免JS执行时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。
浏览器器内核拿到内容后,渲染大概可以划分成以下几个步骤:
解析html建立dom树
解析css构建render树(将CSS代码解析成树形的数据结构,然后结合DOM合并成render树)
布局render树,负责各元素尺寸、位置的计算
绘制render树(paint),绘制页面像素信息
浏览器会将各层的信息发送给GPU,GPU会将各层合成(composite),显示在屏幕上。
所有详细步骤都已经略去,渲染完毕后就是load事件了,之后就是自己的JS逻辑处理了
网友评论