js的异步编程

126 阅读4分钟

前置知识

JS语言的执行环境是"单线程", 也就是我们写的所有js代码都是在一个线程(主线程)上执行

理解单线程:

就是指一次只能完成一件任务。 如果有多个任务,就必须排队,前一个任务完成,再执行后面一个任务,以此类推

js执行任务的2种模式

同步(Synchronous)

  -   后一个任务等待前一个任务结束,然后再执行,
  -   程序的执行顺序与任务的排列顺序是一致的、同步的

异步(Asynchronous)

  -   每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,
  -   后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。

为什么需要异步JS?

浏览器端:

 -   耗时很长的操作都应该异步执行,避免浏览器失去响应
 -   给时机让浏览器能去更新界面, 响应用户操作
 Node端:
 -   "异步模式"是唯一的模式,执行环境是单线程的
 -   处理请求的回调函数/数据库操作/文件读写操作都必须是异步处理, 否则处理多个请求时很快就会失去响应

JS常用的异步编码方式

  • 回调函数
  • 事件机制
  • 消息订阅与发布 / 全局事件总线
  • Promise
  • async & await

回调函数

1.异步编程最基本的方法,所有模式都是在此基础上进行封装而来
2.回调函数的执行方式:
(1)异步执行
(2)同步执行
3.异步回调的缺点:
(1)不利于代码的阅读和维护
(2)容易出现回调地狱的问题

事件机制

1.事件驱动模式:
(1)任务执行不取决于代码定义的顺序,而取决于某个事件是否发生
(2)事件监听函数定义时不会执行,只有当事件发生时才会执行
2.分类:
(1)原生DOM事件
(2)自定义事件 3.操作:
(1)在某个元素或者组件上绑定特有监听事件
(2)在某个元素或者组件上分发事件

消息订阅和发布与全局事件总线

  1. 消息订阅/发布:

订阅全局消息

发布全局消息

  1. 全局事件总线:

绑定事件监听

分发事件

  1. 特点: 分发事件后, 所有同名的事件监听回调都会调用

Promise

  • 实现异步编程新的通用解决方案
  • 相对于纯回调的优势
  • 指定异步回调函数的方式更灵活(可以在启动异步任务后,甚至可以在任务完成后)
  • 通过then的链式调用解决回调地狱的问题
  • 不足: 还需要指定回调函数

async/await

  • 基于promise的语法糖, 简化了promise对象的使用(不再使用回调函数编码)
  • 以同步编码方式实现的异步流程
  • 是js异步编程的终极解决方案(基本上可以这样说)

JS事件循环机制

  • s是单线程运行的
  • js的回调函数可以异步执行, 也可以同步执行
  • js通过event-loop机制实现了js的单线程异步执行
  • JS引擎解析执行js代码总是在主线程执行(WebWorks除外)
  • 浏览器有在分线程执行的对应管理模块(浏览器是多线程执行的)
  • 定时器
  • DOM事件监听
  • ajax请求
  • Promise
  • MutationObserver
  • JS引擎有专门的回调队列, 缓存待执行的回调函数
  • 宏队列
  • 微队列

Promise深入理解

  • 如何改变promise的状态?
  • 一个promise指定多个成功/失败回调函数, 都会调用吗?
  • promise.then()返回的新promise的结果状态由什么决定?
  • 返回一个非promise值 resolved
  • 抛出异常 rejected
    • 返回一个promise
    • 成功了 resolved
    • 失败了 rejected
    • pending pending
  • 改变promise状态和指定回调函数谁先谁后?
  • promise如何串连多个操作任务?
  • promise异常传(穿)透?
  • 中断promise链

自定义Promise

  • 定义整体结构
  • Promise构造函数的实现
  • promise.then()/catch()的实现
  • Promise.resolve()/reject()的实现
  • Promise.all/race()的实现
  • Promise.resolveDelay()/rejectDelay()的实现
  • ES6 class版本