一、队列
队列(queue):它是一种一种运算受限的线性表,FIFO(先进先出)
栈:后进先出
受限之处:它只允许表的前端(front)进行删除操作,在表的后端(rear)进行插入操作
面对无法同时处理多个请求的场景,我们通常就会使用队列,先进先出。
一个一个的解决问题,保证有序
队列的基本操作:
- enqueue(element):向队列尾部添加一个(或多个)新的项
- dequeue():移除队列的第一(即排在队列最前面的)项,并返回被移除的元素
- front():返回队列中第一个元素——最先被添加,也将是最先被移除的元素。队列不做任何变动(不移除元素,只返回元素信息——与Stack类的peek方法非常类似)
- isEmpty():如果队列中不包含任何元素,返回true,否则返回false
- size():返回队列包含的元素个数,与数组的length属性类似
class Queue{
constructor(){
this.items = [];
}
// 入队操作
enqueue(elem){
this.items.push(ele);
}
// 出队操作
dequeue(){
return this.item.shift();
}
// 查看队首元素
front(){
return this.items[0];
}
// 查看队尾
rear(){
return this.items[this.items.length-1];
}
// 查看队列是否为空
isEmpty(){
return this.items.length === 0;
}
// 返回队列包含的元素个数
size(){
return this.items.length;
}
// 清空队列
clear(){
this.items=[];
}
}
const queue = new Queue();
二、JS异步队列
javascript:单线程,同一个时间只能执行一个任务,前一个任务结束了以后,才能执行下一个任务。
线程是最小的执行单元,进程是最小的资源管理单元(线程是从属于进程)
JS的主要作用:完成与用户交互,以及DOM操作。避免复杂性,从一开始,JS就是单线程。
H5 ,web worker 标准,它是允许JS 创建多个线程,但是,子线程是完全受主线程控制的,而且子线程是不可以操作DOM的。
IO的时候,(输入输出的时候),主线程不去管IO,挂起处于等待中的任务,先运行排在后面的任务,等待IO设备返回了结果,再回过头,把挂起等待的任务继续执行下去。于是所有的任务分为同步任务和异步任务。同步会阻塞后面的代码,异步任务在主线程一有空,就立即执行,不是等待0秒。
- 同步任务:在主线程上排队执行的任务,只有前一个任务执行完毕以后,才能够去执行下一个任务。
- 异步任务:不进入主线程,而是进入“任务队列”,只有“任务队列”通知主线程,某个异步任务可以执行了,这个任务才会进入主线程执行。
最先执行的是:同步代码,执行完毕以后,立即出栈,让出主线程
同步代码执行完毕,立即出栈,此时主线程是出于:空闲状态
主线程去读取任务队列,队列遵循的原则是先进先出,但是,有个条件:触发条件相等,会遵循先进先出,如果触发条件不相同,则优先执行到达触发条件的代码,主线程一有空就立即执行
主线程里边维护着一个任务队列,这个任务保存的是:异步的代码
JS是单线程语言,浏览器只会分配一个主线程给JS,用来执行任务(函数)
但是一次只能执行一个任务。
console.log(1);
setTimeout(()=>{
console.log(2);
},50);
setTimeout(()=>{
console.log(3);
},0);
console.log(4);
// 1432
// 定时器、ajax、事件 (异步的)
执行栈进行如下:
- 所有的同步任务都是在主线程上执行,形成一个执行栈
- 主线程之外,还存在一个任务队列,只要存在异步任务,就会在任务队列里放置一个事件
- 一旦执行栈里边同步任务代码执行完毕,主线程就会去读取“任务队列”,看任务队列有哪些对应的异步任务,结束等待状态,进入执行栈,开始执行
主线程不断重复上面3个步骤
主线程执行完毕以后,从事件队列中去读取任务队列的过程,我们称之为事件循环(Event Loop)
任务队列
任务队列:存在着两个队列,一个是宏任务队列,一个是微任务队列
主线程:同步任务->微任务->宏任务
I/O,定时器、事件绑定、ajax ...存在于宏任务队列里的
Promise.then catch finally process.nextTick 都是存在微任务队列