JS版数据结构之 栈与队列、异步线程、任务队列

一、栈

1.定义

栈:一种受限制的线性表,遵循后近先出(Last In First Out)

2.实现

class Stack {
    
    
  constructor() {
    
    
    this.items = []
  }

  // 选择一个元素到栈顶
  push(ele) {
    
    
    this.items.push(ele)
  }

  // 出栈
  pop() {
    
    
    this.items.pop()
  }

  // 返回栈顶元素
  peek() {
    
    
    return this.items[this.items.length - 1]
  }

  // 判断是否为空栈
  isEmpty() {
    
    
    return this.items.length === 0
  }

  // 获取栈中元素的个数
  size() {
    
    
    return this.items.length
  }

  // 清空栈
  clear() {
    
    
    // this.items.length = 0
    // this.items = []
    this.items.splice(0, this.items.length)
  }
}

const stack = new Stack()

stack.push(1)
stack.push(2)
stack.push(3)
stack.push(4)

console.log(stack)
console.log(stack.peek())
console.log(stack.isEmpty())

stack.pop()
console.log(stack)

stack.clear()
console.log(stack)

3.扩展

(1)清空数组的三种方法

1.a.length = 0
2.a = []
3.a.splice(0,a.length)

4.栈的应用

(1)十进制转二进制

// 十进制转二进制
const binary = number => {
    
    
  let stack = new Stack()
  let remainder = 0
  let top = ''

  while (number > 0) {
    
    
    // 除以二,取余数
    remainder = number % 2
    stack.push(remainder)
    // 向下取整
    number = Math.floor(number / 2)
  }

  // 不为空的时候
  while (!stack.isEmpty()) {
    
    
    // 取栈顶
    top += stack.pop()
  }
  return top
}

console.log(binary(100))	//1100100

二、队列

1.定义

队列:一种受限制的线性表,遵循先近先出(First In First Out)

2.实现

class Queue {
    
    
  constructor() {
    
    
    this.items = []
  }

  // 入队
  enqueue(ele) {
    
    
    this.items.push(ele)
  }

  // 出队
  dequeue() {
    
    
    this.items.shift()
  }

  // 查看队首元素
  front() {
    
    
    return this.items[0]
  }

  // 查看队尾元素
  real() {
    
    
    return this.items[this.items.length - 1]
  }

  // 查看队列是否为空
  isEmpty() {
    
    
    return this.items.length === 0
  }

  // 长度
  size() {
    
    
    return this.items.length
  }

  // 清空
  clear() {
    
    
    this.items = []
  }
}

三、异步线程与同步线程

1.原理

  1. JS时单线程语言,浏览器只会分配一个主线程给JS,用来执行任务(函数),一次只能执行一个任务。
  2. 主线程里维护着一个“任务队列”,这个任务保存着异步的代码。
  3. 所有代码都在主线程执行,形成一个执行线。
  4. 只要有了异步代码,就会在“任务队列”里面放置一个事件。
  5. 一旦执行线所有的同步任务执行完毕以后,系统就会去读取“任务队列”,将对应的异步任务放入执行线,执行异步任务。

主线程不断重复以上步骤

事件循环(Event Loop):主线程执行完毕以后,从事件队列中读取任务队列的过程。
例子:

console.log(1)

setTimeout(() => {
    
    
  console.log(2)
}, 50)

setTimeout(() => {
    
    
  console.log(3)
}, 0)

console.log(4)
// 结果:1 4 3 2 

2.异步代码:定时器、ajax、事件

3.执行顺序:

  1. 最先执行的是:同步代码,执行完毕后立即出栈,让出主线程,此时主线程处理空闲状态
  2. 主线程读取任务列表为队列,触发条件相同时,遵循先进先出;触发条件不同时,执行先到达触发条件的代码。
  3. 定时器的时间为0秒代表同步代码一执行完毕,就立即执行该定时器的内容。

四、宏任务队列,微任务队列

/**
 * 1.同步代码
 * 2.new Promise 的时候,excutor函数是立即执行的,说明Promise本来就是同步的
 * 3.基于then或者catch存放的方法是异步的
 */
new Promise((resolve, reject) => {
    
    
  // excutor
  console.log(1)
  resolve()
}).then(() => {
    
    
  console.log(2)
})

console.log(3)
// 1 3 2

任务队列:存在两个队列,一个是宏任务队列,一个是微任务队列
主线程:同步任务>微任务>宏任务
宏任务队列:I/O、定时器、事件绑定、ajax…
微任务队列:Promise.then catch finally、process.nextTick、async、await

猜你喜欢

转载自blog.csdn.net/ladream/article/details/119801896