Promise
• #js
Promise出现解决了什么问题
- Promise通过链式调用和统一错误处理机制,解决了异步编程中的回调嵌套、错误分散和流程控制难题,使代码更易维护。
// Before: 回调嵌套
getData1(function(data1) {
getData2(data1, function(data2) {
getData3(data2, function(data3) {
// 业务逻辑...
}, handleError)
}, handleError)
}, handleError)
// After: Promise链式调用
getData1()
.then(data1 => getData2(data1))
.then(data2 => getData3(data2))
.then(data3 => { /* 业务逻辑 */ })
.catch(handleError)
◭ 回调地狱
// Before: 分散的错误处理
function handleError(err) {
console.log('Error:', err)
}
ajaxCall1(function(result1) {
if (result1.error) handleError(result1.error)
else {
ajaxCall2(function(result2) {
if (result2.error) handleError(result2.error)
// ...
})
}
})
// After: 统一错误捕获
ajaxCall1()
.then(result1 => ajaxCall2(result1))
.then(result2 => { /* ... */ })
.catch(err => {
console.log('统一错误处理:', err)
})
◭ 错误处理分散
// Before: 手动维护异步状态
let count = 0
const results = []
function checkAllDone() {
if (++count === 3) {
// 全部完成处理
}
}
ajaxCall1(function(res) {
results[0] = res
checkAllDone()
})
ajaxCall2(function(res) {
results[1] = res
checkAllDone()
})
ajaxCall3(function(res) {
results[2] = res
checkAllDone()
})
// After: Promise.all 统一管理
Promise.all([ajaxCall1(), ajaxCall2(), ajaxCall3()])
.then(results => {
// 全部完成处理
})
◭ 异步流程控制
Promise的基本使用
Promise是一个类
入参为函数(称为executor,立即执行)
resolve 成功时回调
reject 失败时回调
◭ Promise的基本使用
Promise的三种状态
- pending
- fulfilled
- rejected
◭ Promise的三种状态
Promise的对象方法
- then
- catch
- finally 最终状态不论是fulfilled还是rejected,都会执行finally
可以被多次调用,Promise状态由回调函数的返回值决定
Promise的类方法
- resolve
- reject
- all 有一个Promise状态为rejected就会中断,根据数组的顺序了不按照时间返回结果
- allSettled 返回所有的状态和结果
- race 最快的
- any 等到一个fulfilled结果
◭ Promise的类方法
手写Promise
主线程
│
├─ 创建Promise实例
│ ├─ 执行constructor
│ │ ├─ 初始化状态为pending
│ │ ├─ 定义resolve/reject方法
│ │ ├─ 立即执行executor函数 ← 关键修正点
│ │ │ ├─ 用户代码中调用resolve()
│ │ │ │ ├─ 修改状态为fulfilled
│ │ │ │ └─ 将回调加入微任务队列
│ │ └─ constructor执行完毕
│ └─ 返回实例
│
├─ 调用then()方法
│ └─ 注册onFulfilled回调
│
└─ 主线程执行完毕
│
└─ 执行微任务队列
└─ 调用已注册的onFulfilled回调
Promise的结构设计
Promise类包含一个State和Result
// 定义resolve,reject函数
// 执行传入的executor函数,并传入resolve和reject作为参数
// 执行 executor 函数:
// 调用resolve,reject函数
// 构造函数执行完毕,afe1实例创建完成
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
class Afe1Promise {
constructor(executor){
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED
this.value = value
console.log("resolve被调用")
}
}
const reject = (reason) => {
if(this.status === PROMISE_STATUS_PENDING){
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
console.log('reject被调用');
}
}
executor(resolve,reject) // <- 这里把两个函数传给用户代码
}
}
const afe1 = new Afe1Promise((resolve,reject) => {
console.log('executor立刻执行');
resolve('调用构造函数里面的resolve函数');
reject('调用构造函数里面的reject函数')
})
◭ Promise的结构设计
Promise-then方法实现
then方法设计
实例调用then方法将传入的onFulfilled和onRejected回调函数直接赋值给了this.onFulfilled和this.onRejected,给实例属性添加了两个函数(主任务)
在构造函数中,当Promise状态改变时,会调用这些存储的回调函数(微任务)
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
class Afe1Promise {
constructor(executor){
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED
queueMicrotask(() => {
this.value = value
this.onFulfilled(this.value)
})
}
}
const reject = (value) => {
if(this.status === PROMISE_STATUS_PENDING){
this.status = PROMISE_STATUS_REJECTED
queueMicrotask(() => {
this.reason = value
this.onRejected(this.reason)
})
}
}
executor(resolve,reject) // <- 这里把两个函数传给用户代码
}
then(onFulfilled,onRejected){
this.onFulfilled = onFulfilled
this.onRejected = onRejected
}
}
const afe1 = new Afe1Promise((resolve,reject) => {
console.log('executor立刻执行');
resolve('调用构造函数里面的resolve函数');
})
afe1.then((res) => {
console.log('then回调函数执行了');
console.log(res);
})
◭ then方法设计
then方法设计优化一
实现多次then调用,确保status状态只能改变一次
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
class Afe1Promise {
constructor(executor){
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledFns = []
this.onRejectedFns = []
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_FULFILLED
this.value = value
this.onFulfilledFns.forEach((fn) => {
fn(this.value)
})
})
}
}
const reject = (reason) => {
if(this.status === PROMISE_STATUS_PENDING){
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
this.onRejectedFns.forEach((fn) => {
fn(this.reason)
})
})
}
}
executor(resolve,reject) // <- 这里把两个函数传给用户代码
}
then(onFulfilled,onRejected){
if(this.status === PROMISE_STATUS_FULFILLED && onFulfilled){
onFulfilled(this.value)
}
if(this.status === PROMISE_STATUS_REJECTED && onRejected){
onRejected(this.reason)
}
if(this.status === PROMISE_STATUS_PENDING){
this.onFulfilledFns.push(onFulfilled)
this.onRejectedFns.push(onRejected)
}
}
}
const afe1 = new Afe1Promise((resolve,reject) => {
console.log('executor立刻执行');
resolve('调用构造函数里面的resolve函数');
})
afe1.then((res) => {
console.log('then回调函数执行了1');
console.log(res);
})
afe1.then((res) => {
console.log('then回调函数执行了2');
console.log(res);
})
// 在确定Promise状态之后, 再次调用then
setTimeout(() => {
afe1.then(res => {
console.log("res3:", res)
}, err => {
console.log("err3:", err)
})
}, 1000)
◭ then方法设计优化一
then方法设计优化二
实现then的链式调用(之前是调用then方法传入的函数,现在调用的是包装的函数)
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
class Afe1Promise {
constructor(executor){
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledFns = []
this.onRejectedFns = []
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_FULFILLED
this.value = value
this.onFulfilledFns.forEach((fn) => {
fn(this.value)
})
})
}
}
const reject = (reason) => {
if(this.status === PROMISE_STATUS_PENDING){
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
this.onRejectedFns.forEach((fn) => {
fn(this.reason)
})
})
}
}
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
then(onFulfilled,onRejected){
return new Afe1Promise((resolve,reject) => {
if(this.status === PROMISE_STATUS_FULFILLED && onFulfilled){
try {
const value = onFulfilled(this.value)
resolve(value)
} catch(err) {
reject(err)
}
}
if(this.status === PROMISE_STATUS_REJECTED && onRejected){
try {
const reason = onRejected(this.reason)
resolve(reason)
} catch(err) {
reject(err)
}
}
if(this.status === PROMISE_STATUS_PENDING){
this.onFulfilledFns.push(() => {
try {
const value = onFulfilled(this.value)
resolve(value)
} catch(err) {
reject(err)
}
})
this.onRejectedFns.push(() => {
try {
const reason = onRejected(this.reason)
resolve(reason)
} catch(err) {
reject(err)
}
})
}
})
}
}
const afe1 = new Afe1Promise((resolve,reject) => {
console.log('executor立刻执行');
resolve('调用构造函数里面的resolve函数');
})
afe1.then((res) => {
console.log('then回调函数执行了1');
console.log(res);
})
afe1.then((res) => {
console.log('then回调函数执行了2');
console.log(res);
})
// 在确定Promise状态之后, 再次调用then
setTimeout(() => {
afe1.then(res => {
console.log("res3:", res)
}, err => {
console.log("err3:", err)
})
}, 1000)
// 调用then方法多次调用
afe1.then(res => {
console.log("res1:", res)
return "aaaa"
// throw new Error("err message")
}, err => {
console.log("err1:", err)
return "bbbbb"
// throw new Error("err message")
}).then(res => {
console.log("res2:", res)
}, err => {
console.log("err2:", err)
})
◭ then方法设计优化二