《浏览器工作原理与实践》读书笔记(3)
浏览器中的页面循环系统
1.要想在线程运行过程中,能接收并执行新的任务,就需要采用事件循环机制。示例如下:
//GetInput
//等待用户从键盘输入一个数字,并返回该输入的数字
int GetInput(){
int input_number = 0;
cout<<"请输入一个数:";
cin>>input_number;
return input_number;
}
//主线程(Main Thread)
void MainThread(){
for(;;){
int first_num = GetInput();
int second_num = GetInput();
result_num = first_num + second_num;
print("最终计算的值为:%d",result_num);
}
}
2.为了能够接收其它线程(比如资源加载、交互事件、渲染事件、文件读写等)发送的消息,就在上面的事件循环机制上面加上消息队列。消息队列是一种数据结构,用来存放要执行的任务。
3.如何退出事件循环呢?很简单,加一个退出标记,每次事件循环的时候判断这个标记,如果有的话就退出循环。
4.为了保证任务的实时性(快速执行,不被消息队列中的任务延误)和效率(不影响当前正在执行的消息队列中的任务),我们把消息队列中的每个任务都加入一个微任务队列,而消息队列中的每个任务被称为宏任务。
5.其实除了有消息队列之外,chrome 还维护了一个延迟队列,用来存放 settimeout 的任务,执行完消息队列中的每个任务之后,就回去判断延迟队列中的任务该不该执行。(所以只有消息队列中的当前正在执行的任务会影响 settimeout 的延迟时间)
6.对于 settimeout 有以下几点需要注意:
1.如果 setTimeout 存在嵌套调用,那么系统会设置最短时间间隔为 4 毫秒
2.未激活的页面,setTimeout 执行最小间隔是 1000 毫秒
3.延时执行时间有最大值
4.使用 setTimeout 设置的回调函数中的 this 不符合直觉
7.使用 xhr 发送 http 请求的 demo:
function GetWebData(URL){
/**
* 1:新建XMLHttpRequest请求对象
*/
let xhr = new XMLHttpRequest()
/**
* 2:注册相关事件回调处理函数
*/
xhr.onreadystatechange = function () {
switch(xhr.readyState){
case 0: //请求未初始化
console.log("请求未初始化")
break;
case 1://OPENED
console.log("OPENED")
break;
case 2://HEADERS_RECEIVED
console.log("HEADERS_RECEIVED")
break;
case 3://LOADING
console.log("LOADING")
break;
case 4://DONE
if(this.status == 200||this.status == 304){
console.log(this.responseText);
}
console.log("DONE")
break;
}
}
xhr.ontimeout = function(e) { console.log('ontimeout') }
xhr.onerror = function(e) { console.log('onerror') }
/**
* 3:打开请求
*/
xhr.open('Get', URL, true);//创建一个Get请求,采用异步
/**
* 4:配置参数
*/
xhr.timeout = 3000 //设置xhr请求的超时时间
xhr.responseType = "text" //设置响应返回的数据格式
xhr.setRequestHeader("X_TEST","time.geekbang")
/**
* 5:发送请求
*/
xhr.send();
}
8.https 混合内容问题:当我们在 https 网站加载 http 的资源,都属于混合内容。如果这些内容不是 xhr 加载而是图片 src,视频 src等方式加载的话,浏览器会显示警告;但是如果这些内容是 xhr 加载的话,浏览器会阻挡这些请求。
9.产生微任务一般有两种方式:使用 MutationObserver 监控某个DOM节点;使用 promise。
10.MutationObserver 使用异步 + 微任务的模式:使用异步解决了同步操作的性能问题;使用微任务解决了实时性的问题。
11.promise 主要是通过下面2点来解决嵌套回调问题的:1.回调函数的延时绑定。(先创建 promise 对象,然后使用executor执行业务逻辑,最后使用then来绑定回调函数)2.将回调函数的返回值穿透到最外层。
12.promise 的好处:1.消灭了嵌套回调。2.更好的信任度,回调函数只会执行一次。3.更好的流程处理。4.更好的错误处理。(可以通过监听 unhandledRejection 来捕获未处理的 promise 错误)
13.生成器是一个带星号的函数,而且是可以暂停执行和恢复执行的。执行生成器代码的函数叫做执行器。(参考著名的 co 框架)
14.协程是比线程更轻量级的存在,它完全受程序所控制,不被操作系统内核管理,也不会像线程切换那样消耗资源。