前端异步编程
异步处理概念
异步处理是指在不等待某个操作的情况下,可以继续执行其他操作。异步处理可以提高程序的运行效率,减少等待时间,提高用户体验。
异步处理的实现方式
异步处理的实现方式有以下几种:
- 回调函数
javascript
function fetchData(callback) {
// 异步操作
setTimeout(() => {
const data = 'Hello World'
callback(data)
}, 1000)
}
fetchData((data) => {
console.log(data)
})
- Promise
javascript
function fetchData() {
return new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
const data = 'Hello World'
resolve(data)
}, 1000)
})
}
fetchData().then(data => {
console.log(data)
})
- async/await
javascript
async function fetchData() {
// 异步操作
const data = await new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Hello World')
}, 1000)
})
return data
}
fetchData().then(data => {
console.log(data)
})
异步处理常见场景与处理策略
- 网络请求
- 定时任务
- 事件绑定
- 大量数据处理 Web Worker
处理策略
- 回调函数
- Promise
- async/await
- 发布/订阅模式
- Generator 函数
- promise.all
- 预加载资源
- 事件监听
手写简版 Promise
Promise规范
- 初始状态为 pending
- 执行了 resolve Promise状态为 fulfilled
- 执行了 reject Promise状态为 rejected
- Promise状态不可逆
- Promise中有throw error会被捕获,并转换为reject状态
- then接受两个回调,一个是成功的回调,一个是失败的回调,只有当Promise状态为fulfilled时才会执行成功的回调,只有当Promise状态为rejected时才会执行失败的回调
- 存在定时器,需要等定时器结束之后才会执行then的回调
- 链式调用,then返回的Promise可以继续调用then。下一次的then的回调函数接收上一次的回调函数的返回值。
- all
- 接收一个数组,数组中的元素都是Promise对象。
- 返回一个新的Promise对象,只有当所有Promise对象都执行完毕后才会执行成功的回调。
- 如果有一个失败,就返回失败的结果
- race
- any
- allSettled
实现MyPromise
javascript
class MyPromise {
constructor(executor) {
// 初始化值
this.initValue()
this.initBind(this.resolve, this.reject)
// 执行executor函数
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
initValue() {
this.PromiseState = 'pending' // 初始状态为pending
this.PromiseResult = null // 初始结果为null
// 初始化任务队列
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []
}
initBind() {
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
resolve(value) {
if (this.PromiseState !== 'pending') return // 如果状态不是pending,则直接返回
this.PromiseState = 'fulfilled' // 状态变为fulfilled
this.PromiseResult = value // 结果变为value
while (this.onFulfilledCallbacks.length) {
this.onFulfilledCallbacks.shift()(this.PromiseResult)
}
}
reject(value) {
if (this.PromiseState !== 'pending') return // 如果状态不是pending,则直接返回
this.PromiseState = 'rejected' // 状态变为rejected
this.PromiseResult = value // 结果变为value
while (this.onRejectedCallbacks.length) {
this.onRejectedCallbacks.shift()(this.PromiseResult)
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => value
onRejected = typeof onRejected === 'function' ? onRejected : (value) => value
const thenPromise = new MyPromise((resolve, reject) => {
const resolvePromise = cb => {
setTimeout(() => {
try {
const result = cb(this.PromiseResult)
if (result === thenPromise && result) {
throw new Error('不能返回本身')
}
if (result instanceof MyPromise) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch (e) {
reject(e)
throw new Error(e)
}
})
}
if (this.PromiseState === 'fulfilled') {
resolvePromise(onFulfilled)
} else if (this.PromiseState === 'rejected') {
resolvePromise(onRejected)
} else if (this.PromiseState === 'pending') {
this.onFulfilledCallbacks.push(onFulfilled.bind(this))
this.onRejectedCallbacks.push(onRejected.bind(this))
}
})
return thenPromise
}
static all(promises) {
const result = []
let count = 0
return new MyPromise((resolve, reject) => {
const addData = (value, index) => {
result[index] = value
count++
if (count === promises.length) {
resolve(result)
}
}
promises.forEach((promise, index) => {
if (promise instanceof MyPromise) {
promise.then(value => {
addData(value, index)
}, error => reject(error))
} else {
addData(promise, index)
}
})
})
}
static allSettled(promises) {
return new MyPromise((resolve, reject) => {
const result = []
let count = 0
const addData = (status, value, index) => {
result[index] = {
status,
value
}
count++
if (count === promises.length) {
resolve(result)
}
}
promises.forEach((promise, index) => {
if (promise instanceof MyPromise) {
promise.then(value => {
addData('fulfilled', value, index)
}, (error) => {
addData('rejected', error, index)
})
} else {
addData('fulfilled', promise, index)
}
})
})
}
}