这是我参与「第五届青训营 」伴学笔记创作活动的第 12 天
单线程的JavaScript
进程 & 线程
-
js 是单线程的,一个任务完成后才执行另一个任务。
-
将线程比作服务员,将任务比作客户。多线程可以理解为一个服务员服务一个客户,则多个服务员服务多个客户。单线程可以理解为一个服务员服务多个客户。
-
进程(厂房):是并发执行的程序在执行过程中分配和管理资源的基本单位(程序的运行环境),是一个动态概念,竞争计算机系统资源的基本单位。
线程(工人):是进程的一个执行单元,是进程内科调度实体(实际进行运算的实体)。
-
主线程:浏览器用来处理用户事件、渲染和绘制显示以及运行组成典型网页或应用程序的大部分代码的线程。
-
现代 JavaScript 提供了创建额外线程的方式,每个线程独立执行,同时可能相互通信。这是使用例如 web workers 等技术实现的,这些技术可以用来衍生出一个在自己的线程中与主线程同时运行的子程序。
-
可以创建一种称为 service worker 的特殊类型的 worker,可以在即使用户当前不使用该网站的情况下在网站背后运行(在用户许可的情况下)。这用于创建在用户与网站交互不活跃的情况下当发生事情时能够通知用户的网站。
异步 & 同步
-
同步
同步代码立即放入 JS 引擎( JS 主线程)执行,并原地等待结果。
同步代码直接放入执行栈中。
浏览器会等待代码的解析和工作,在上一行完成后才会执行下一行(自上而下逐行执行)。
同步任务的执行会出现阻塞的情况,一行代码执行得慢会影响整个程序的执行。
解决同步带来的问题:java、python 通过多线程的方式解决;js 通过异步编程的方式来解决。
-
异步
异步代码先放入宿主环境(浏览器 / Node),不必原地等待结果。
异步代码等待时机成熟送入任务队列排队。
程序可以在执行一个可能长期运行的任务的同时,继续对其他事件做出反应而不必等待任务完成。
异步任务不会出现阻塞情况,但是无法通过 return 来设置返回值。
解决异步带来的问题:通过回调函数来返回结果,但会造成回调地狱。
-
同步任务执行完毕后再执行异步任务。执行栈执行完毕后,会去看任务队列是否有异步任务,若有就送到执行栈执行,执行栈反复查看执行的这个过程称为事件循环(Event Loop)。
宏任务 & 微任务
-
任务队列
为了更合理的处理异步任务,将任务队列分为宏任务队列(Task Queue)和微任务队列(Microtask Queue)。
微任务队列是专门用来放置由 Promise 产生的回调函数的(then、catch、finally),相对的,setTimeout 这些方法则将函数放入到了“宏任务队列”。
代码执行时,宏任务进入到宏任务队列,微任务进入到微任务队列。
异步任务可分为宏任务与微任务:
-
宏任务
- 计时器(
setTimeout、setInterval) ajax- 读取文件
- 计时器(
-
微任务
promise.then -
执行顺序
- 同步任务(调用栈)
process.nextTick(tick 队列)- 微任务队列
- 宏任务队列
setImmediate