说明
图解 Google V8 学习笔记
什么是回调函数?
只有当某个函数被作为参数,传递给另外一个函数,或者传递给宿主环境,然后该函数在函数内部或者在宿主环境中被调用,才称为回调函数。
回调函数有两种不同的形式:
- 同步回调:函数在执行函数内部被执行的;
- 异步回调:函数在执行函数外部被执行的。
UI 线程的宏观架构
注意:在浏览器的页面里面是UI线程,node中就是它的主线程。
什么是 UI 线程?
所谓 UI 线程,是指运行窗口的线程,当你运行一个窗口时,无论该页面是 Windows 上的窗口系统,还是 Android 或者 iOS 上的窗口系统,它们都需要处理各种事件,诸如有触发绘制页面的事件,有鼠标点击、拖拽、放大缩小的事件,有资源下载、文件读写的事件,等等。
通用的 UI 线程的结构,有消息队列,通过鼠标、键盘、触控板等产生的消息都会被添加进消息队列,主线程会循环地从消息队列中取出消息并执行。
异步回调函数的调用时机
异步回调有两种不同的类型,其典型代表是 setTimeout 和 XMLHttpRequest。
setTimeout
例子:比如在页面主线程中正在执行 A 任务,在执行 A 任务的过程中调用 setTimeout(foo, 3000)
function foo() { alert("Hello"); } setTimeout(foo, 3000)
示意图:
在执行 setTimeout 函数的过程中,宿主就会将 foo 函数封装成一个事件,并添加到消息队列中,然后 setTimeout 函数执行结束。主线程会不间断地从消息队列中取出新的任务,执行新的任务,等到时机合适,便取出 setTimeout 设置的 foo 函数的回调的任务,然后就可以直接执行 foo 函数的调用。
定时器有单独的队列,每次执行新的宏任务时,主线程会先在这两个队列中查找即将要执行的事件,然后执行。
xmlHttpRequest
XMLHttpRequest 是用来下载网络资源的,而下载任务会消耗比较久,如果在 UI 线程上执行,会阻塞 UI 线程,拖慢 UI 界面的交互和绘制的效果。所以当主线程从消息队列中取出来了这类下载任务之后,会将其分配给网络线程。
示意图:
XMLHttpRequest 所触发的回调流程:
UI 线程会从消息队列中取出一个任务,并分析该任务。
分析过程中发现该任务是一个下载请求,那么主线程就会将该任务交给网络线程去执行。
网络线程接到请求之后,便会和服务器端建立连接,并发出下载请求;
网络线程不断地收到服务器端传过来的数据;
网络线程每次接收到数据时,都会将设置的回调函数和返回的数据信息,如大小、返回了多少字节、返回的数据在内存中存放的位置等信息封装成一个新的事件,并将该事件放到消息队列中 ;
UI 线程继续循环地读取消息队列中的事件,如果是下载状态的事件,那么 UI 线程会执行回调函数,程序员便可以在回调函数内部编写更新下载进度的状态的代码;
直到最后接收到下载结束事件,UI 线程会显示该页面下载完成。
网络线程在执行下载的过程中,会将一些中间信息和回调函数封装成新的消息,并将其添加进消息队列中,然后主线程从消息队列中取出回调事件,并执行回调函数。