介绍
- 异步调用必须要通过回调函数来返回数据,当我们进行一些复杂调用时, 会出现“回调地狱”
- promise出现的原因是为了解决异步函数调用的问题, 防止代码可读写性太差
- promise就是一个用来存储数据的容器,它和普通对象的区别就是它可以存储异步调用的结果
方法详情
-
Promise构造函数的回调函数,它会在创建Promise时调用,调用时会有两个参数传递进去,resolve和reject, resolve在执行正常时存储数据, reject在执行错误时存储数据
-
读取数据采用then,then需要两个回调函数作为参数,回调函数用来获取promise中的数据,通过resolve存储的数据会调用第一个函数返回, 可以在第一个函数中编写处理数据的代码,通过reject存储的数据或出现异常时, 会调用第二个函数返回, 可以在第二个函数中编写处理异常的代码
-
Promise中维护了两个隐藏属性
PromiseResult - 用来存储数据 PromiseState - 记录Promise的状态(三种状态) pending (进行中) fulfilled(完成) 通过resolve存储数据时 rejected(拒绝,出错了) 出错了或通过reject存储数据时 - state只能修改一次,修改以后永远不会在变 流程: 当Promise创建时,PromiseState初始值为pending, 当通过resolve存储数据时 PromiseState 变为fulfilled(完成) PromiseResult变为存储的数据 当通过reject存储数据或出错时 PromiseState 变为rejected(拒绝,出错了) PromiseResult变为存储的数据 或 异常对象 当我们通过then读取数据时,相当于为Promise设置了回调函数, 如果PromiseState变为fulfilled,则调用then的第一个回调函数来返回数据 如果PromiseState变为rejected,则调用then的第二个回调函数来返回数据 -
then 和 catch 和 finally
then()和catch()都会返回一个新的promise, promise会存储回调函数的返回值 finally的返回值, 不会存储到新的promise中 catch() 用法和then类似,但是只需要一个回调函数作为参数 catch()中的回调函数只会在Promise被拒绝时才调用 catch() 相当于 then(null, reason => {}) catch() 就是一个专门处理Promise异常的方法 finally() - 无论是正常存储数据还是出现异常了,finally总会执行 - 但是finally的回调函数中不会接收到数据 - finally()通常用来编写一些无论成功与否都要执行代码
方法注意
- promise的链式调用
const promise = new Promise((resolve,reject) => {
resolve('哈哈果1')
})
promise.then(result => console.log('第一个then'))
.catch(err => console.log('第一个catch'))
.then(result => console.log(result,'result'))
对于Promise进行链式调用时,后边的方法(then和catch)读取的是上一步的执行结果,如果上一步的执行结果不是当前想要的,则跳过当前方法
Promise.all
Promoise.all([...]) 同时返回多个Promise的执行结果,其中一个有报错就返回错误
Promise.allSettled()
Promise.allSettled([...])同时返回多个Promise的执行结果(无论失败与否)
返回 {status: 'fulfilled', value: '123'} {status: 'rejected', reason: '123'}
Promise.race()
Promise.race([...])返回执行最快的, 不考虑对错
实现一个Promise
/**
* Promise方法的核心在于解决异步,承诺存值
* 只存一次, 不会丢, 同时then实现promise的链式调用
* then返回的是什么: 返回的是promise中存的值
* queueMicrotask(() => {}) 创建微任务队列
* 私有方法和私有属性外边实例不可访问加#表示私有
*
* 类中方法: 如果是普通函数形式是放在了函数的原型中 [只有一次]
* 如果是箭头函数形式是放在了对象中 [这种情况稍微浪费一点内存]
* - MyPromiseStatus记录Promise的状态(三种状态)
* pending (进行中)
* fulfilled(完成) 通过resolve存储数据时
* rejected(拒绝,出错了) 出错了或通过reject存储数据时
* 状态一旦改变就不会再被修改,所以使用状态来判断是否赋值
*
*/
const MyPromiseStatus = {
PENDING_STATUS: 0,
FULFILLED_STATUS: 1,
REJECTED_STATUS: 2,
};
class MyPromise {
#result = null; //用来存储值
#status = MyPromiseStatus.PENDING_STATUS;
#onFulfilledCallbacks = []; //用来执行成功的回调函数 []为了实现then的多次调用
#onRejectedCallbacks = []; //用来执行回调函数
constructor(executor) {
executor(this.#resolve, this.#reject);
}
// resolve 和 reject 是内部方法, 不允许外边修改
#resolve = (value) => {
if (this.#status !== MyPromiseStatus.PENDING_STATUS) return;
this.#result = value;
this.#status = MyPromiseStatus.FULFILLED_STATUS;
queueMicrotask(() => {
this.#onFulfilledCallbacks.forEach((cb) => {
cb(this.#result);
});
});
};
#reject = (value) => {
if (this.#status !== MyPromiseStatus.PENDING_STATUS) return;
this.#result = value;
this.#status = MyPromiseStatus.REJECTED_STATUS;
queueMicrotask(() => {
this.#onRejectedCallbacks.forEach((cb) => {
cb();
});
});
};
// 存值完成, 定义取值方法
then(onFulfilled, onRejected) {
/**
* 谁将成为then返回的新Promise中的数据
* then中回调函数的返回值,会成为新的Promise中的返回值
*/
// 函数可以不传
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (value) => value;
onRejected =
typeof onRejected === "function"
? onRejected
: (reason) => {
return reason;
};
return new MyPromise((resolve, reject) => {
if (this.#status === MyPromiseStatus.FULFILLED_STATUS) {
//成功
queueMicrotask(() => {
resolve(onFulfilled(this.#result));
});
} else if (this.#status === MyPromiseStatus.REJECTED_STATUS) {
//失败
queueMicrotask(() => {
reject(onRejected(this.#result));
});
} else {
// 进行中 --- 如果是异步的时候就要在resolve和reject调用方法
this.#onFulfilledCallbacks.push(() => {
resolve(onFulfilled(this.#result));
});
this.#onRejectedCallbacks.push(() => {
reject(onRejected(this.#result));
});
}
});
}
catch(onRejected) {
return this.then(null, onRejected);
}
}
export default MyPromise;