1. 队列
- 先进先出的数据结构
- js中没有队列,但是可以使用array来实现队列
- 入队
push() - 出队
shift()
- 入队
const queue = [];
//入队
queue.push(1); // [1]
queue.push(2); // [1, 2]
// 出队
const item1 = queue.shift(); // 1
const item2 = queue.shift(); // 2
2. 什么场景用队列
- 需要
先进先出的的场景 - 比如:食堂排队打饭、JS异步中的任务队列、计算最近请求次数
2.1 场景一:食堂排队打饭
- 食堂只留一个窗口,学生排队打饭似春运
- 先进先出,保证有序
2.3 场景二:JS异步中的任务队列
- JS 是单线程,无法同时处理异步中的并发任务
- 使用任务队列先后处理异步任务
2.3 场景三:计算最近请求次数
- 有新请求就入队,3000ms 前发出的就请求出队
- 队列的长度就是最近请求的次数
3. LeetCode:933. 最近的请求次数
3.1 解题思路
- 越早发的的请求越早不在最近3000ms内的请求里;
- 满足先进先出,考虑用队列;
3.2 解题步骤
- 有新请求就入队,300ms前发出的请求出队
- 队列的长度就是最近的请求次数
var RecentCounter = function () {
this.q = [];
};
/**
* @param {number} t
* @return {number}
*/
RecentCounter.prototype.ping = function (t) {
this.q.push(t)
while (this.q[0] < t - 3000) {
this.q.shift()
}
return this.q.length;
};
/**
* Your RecentCounter object will be instantiated and called as such:
* var obj = new RecentCounter()
* var param_1 = obj.ping(t)
*/
- 本题结果:时间复杂度 O(n)、空间复杂度 O(n)
4. 前端与队列:JS异步中的任务队列
维基百科的定义是:“事件循环是一个程序结构,用于等待和发送消息和事件(a programming construct that waits for and dispatches events or messages in a program)”。
4.1 异步面试题
setTimeout(()=>console.log(1), 0);
console.log(2);
- 输出结果
- 原理
- 先有一个主事件放到任务队列中,然后JS引擎会拿到 主事件 去执行
- 执行setTimeout 发现是一异步任务,就交给web API去执行,web API 在0ms 就执行完了,
- 接着把执行完的回掉函数
console.log(1)放人任务中, - 但是发现还有一个任务队列
console.log(2)没有执行完 - 所以先打印
2再打印1
4.2 事件循环与任务队列
4.3 主线程和任务队列
JavaScript 运行时,除了一个正在运行的主线程,引擎还提供一个任务队列(task queue),里面是各种需要当前程序处理的异步任务。(实际上,根据异步任务的类型,存在多个任务队列。为了方便理解,这里假设只存在一个队列。)
首先,主线程会去执行所有的同步任务。等到同步任务全部执行完,就会去看任务队列里面的异步任务。
如果满足条件,那么异步任务就重新进入主线程开始执行,这时它就变成同步任务了。等到执行完,下一个异步任务再进入主线程开始执行。一旦任务队列清空,程序就结束执行。
4.3 异步任务的写法通常是回调函数
一旦异步任务重新进入主线程,就会执行对应的回调函数。如果一个异步任务没有回调函数,就不会进入任务队列,也就是说,不会重新进入主线程,因为没有用回调函数指定下一步的操作。
4.5 事件循环
JavaScript 引擎怎么知道异步任务有没有结果,能不能进入主线程呢?答案就是引擎在不停地检查,一遍又一遍,只要同步任务执行完了,引擎就会去检查那些挂起来的异步任务,是不是可以进入主线程了。这种循环检查的机制,就叫做事件循环(Event Loop)。
5 队列总结
-
队列是一个先进先出的数据结构
-
js中没有队列,但是可以使用array来实现队列
- 入队
push() - 出队
shift() - 获取队头元素
queue[0]
- 入队
-
树 和 图的数据结构时也会使用到队列进行广度和深度优先遍历