前言
💯 知其然,更知其所以然,举一反三,融会贯通
JavaScript脚本是在主线程中执行的,由于是单线程会造成阻塞,所以代码中很多工作都是通过异步的方式来实现的,在开发过程中我们接触到与异步编程的方案哪些呢?下面具体来梳理一下
异步方案的实现原理会涉及到JS的核心事件循环机制,这里就不阐述了!
首先通过一张图,大致了解一下异步编程的发展历程,大致可以分为三个阶段
-
第一阶段Callback: ES5中的方案
-
第二阶段Promoise和generator:ES6中的方案
-
第三阶段Async/await:ES7中的方案
同步和异步
在真正去了解异步编程之前,还是有必要了解一下同步和异步的概念,因为在JS引擎中执行代码就分为这两种模式,它们是相互协作的
【同步】:在js中执行一个函数或方法后,会一直等待引擎返回值或者消息,这时程序会处于阻塞状态,后续的代码不会执行,直到函数执行完毕返回值后才会继续执行其他命令。
【异步】:在js中执行一个函数或方法后,不会阻塞性的等待结果的返回,而是向JS引擎或浏览器委托一个异步的过程(比如回调函),当系统接收到返回的结果时,系统会自动触发委托的异步过程,从而达到异步非阻塞的目的。
接下来具体看看异步的实现方案
Callback
回调函数简单来说是把一个函数作为参数传递给另一个函数,等待被调用,是异步中最常见和简单的一种实现方式,如下几种都是利用回调函数来实现的
定时器
最常用的定时器setTimeout和setInterval
function myFun(callback) {
setTimeout(() => {
const result = '我是返回的结果'
callback && callback(result)
}, 2000)
}
myFun((data) => {
console.log(data)
})
上面的例子中把(data) => {console.log(data)}当做参数传递给myFun,当异步的任务有了结果之后,会触发回调函数把结果返回,此过程并不会影响主线程的代码执行
异步请求
ajax是前端开发过程中必不可少的一项技术,用来请求服务器端的数据,由于请求的过程和结果是不可预期的,所以必须使用异步的方式得到响应结果,它的实现如下
function request(callback) {
const xhr = new XMLHttpRequest()
xhr.open('get', 'http://xxx.com', true)
xhr.onreadystatechange = () => {
if(xhr.readystate ==4 && xhr.status === 200) {
callback && callback(xhr.responseText)
}
}
xml.send()
}
request((data) => {
console.log(data)
})
事件监听
js中的有自带的添加绑定事件方法以及自定义事件类: addEventLinstener 和 CustomEvent
例如给网页dom元素绑定事件, 利用回调函数进行监听
const myDom = document.getElementById("myDiv")
myDiv.addEventLinstener('click', (e) => {
console.log(e)
}, false)
通过自定义事件, 回调函数监听
const sendEvent = new CustomEvent('sendMsg',{title: 'hello'})
document.addEventLinstener('sendMsg', (data) => {
console.log(data.title)
})
document.dispatchEvent(sendEvent)
Promise
Promise是ES6中新增的功能,主要是提供一种标准化的异步方案,来解决异步回调函数的一些困境,它主要是使用链式操作来替代回调函数
new Promise((resolve, reject)=> {
setTimeout(() => {
resolve('success')
}, 2000)
}).then(data => {
console.log(data)
}).catch(err => {
console.log(err)
})
Generator
Generator(生成器)是ES6中的关键字,简单来说Generator是一个带*星号的函数(并不是真正的函数),它通过yield关键字来暂停或者执行函数
function* myFun() {
let a = yield 1
let b = yield 2
return 3
}
const g = myFun()
console.log(g.next()) // { value: 1, done: false}
console.log(g.next()) // { value: 2, done: false}
console.log(g.next()) // { value: 3, done: true}
console.log(g.next()) // { value: undefined, done: true}
Async/await
Async是ES7版本中新增的功能,很多人以为是ES6中的,可以说是异步编程的终极解决方案,它基于Promise和Generator进行了深层的封装,提供出async/await语法糖,让异步过程的写法完全同步化,代码更加精细和简练
写法是函数通过async声明,函数内部使用await,通常情况下await后面跟着一个方法,而方法是返回一个Promise对象
const requsetData = () => {
return new Promise((resolve, reject)=> {
setTimeout(() => {
resolve('success')
}, 2000)
})
}
cosnt getData = async () => {
const data = await requestData()
console.log(data)
}
getData()