是什么:promise 是一个构造函数,本质上是,js对象,用来生成promise实例。
解决什么问题:promise 是用来解决回调地狱的
promise的三个状态:有三种状态pending、fulfilled、reject
promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject,他们是两个函数,由js引擎提供,不用自己部署
resolve 函数的作用是,将promise对象的状态从pending变为fulfillied,在异步操作成功时调用,并将一步操作的结果,作为参数传递出去
reject函数的作用,是将Promise对象的状态从pending变成reject,在异步操作失败时调用,并将一步操作报出的错误,作为参数传递出去
promise 实例生成以后,可以用then方法分别指定fulfillied状态和rejected状态的回调函数
promise 方法
实现一个promise,从精简版,一步步实现
class MyPromise {
/**
* 手动实现一个promise,包括resolve和reject方法,then方法和reject方法
* @param {*} executor promise实例化时会传入一个回调,内部立即调用executor
*/
constructor(executor) {
this.state = "pending";
this.value = null;
this.reason = null;
this.onFulfilledCb = [];
this.onRejectCb = [];
const resolve = () => {};
const reject = () => {};
executor(resolve, reject);
}
then() {}
catch() {}
}
完善初始化数据 resolve和reject方法
class MyPromise {
constructor(executor) {
this.state = "pending";
this.value = null;
this.reason = null;
// 用于存储then方法中,成功和失败的回调
this.onFulfilledCb = [];
this.onRejectCb = [];
// 以下两个函数用于在成功或失败时,更新状态和值(原因),并调用所有注册的回调函数
const resolve = (value) => {
if (this.state === "pending") {
this.state = "fulfilled";
this.value = value;
this.onFulfilledCb.forEach((cb) => {
cb(this.value);
});
}
};
const reject = (reason) => {
if (this.state === "pending") {
this.state = "reject";
this.reason = reason;
this.onRejectCb((cb) => {
cb(this.reason);
});
}
};
executor(resolve, reject);
}
then() {}
catch() {}
}
promise.then()方法
class MyPromise2 {
constructor(executor) {
this.state = "pending"; // fulfilled reject
this.value = null; // 成功的值
this.reason = null; // 失败的值
this.onFulfilledCb = [];
this.onRejectCb = [];
const resolve = (value) => {
if (this.state === "pending") {
this.state = "fulfilled";
this.value = value;
this.onFulfilledCb.forEach((cb) => {
cb(this.value);
});
}
};
const reject = (reason) => {
if (this.state === "pending") {
this.state = "reject";
this.reason = reason;
this.onRejectCb((cb) => {
cb(this.reason);
});
}
};
executor(resolve, reject);
}
/*`promise`调用`then`方法时,当前的`promise`并没有成功,一直处于`pending`状态,
* 所以如果当调用 `then`方法时,当前状态是`pending`,需要`先将成功和失败的回调分别存放起来`,
* 在`executor()`的异步任务被执行时,`触发resolve或reject,依次调用成功或失败的回调`
*/
// then 方法分别指定fulfilled和rejected状态的回调函数
then(onFulfilled, onReject) {
// 同步
if (this.state === "fulfilled") {
onFulfilled(this.value);
}
if (this.state === "reject") {
onReject(this.reason);
}
// 异步订阅
if (this.state === "pending") {
this.onFulfilledCb.push(() => {
onFulfilled(this.value);
});
this.onRejectCb.push(() => {
onReject(this.reason);
});
}
}
catch() {}
}
promise.then() 方法链式调用
promise接收两个参数,onFulfilled和onReject
在方法内部如果promise成功或者失败,会立即调用对应的回调函数;
如果是pending,将回调函数添加到回调数组中,并返回一个promise,该对象会在原Promise成功或失败时调用对应的回调函数。
class MyPromise {
constructor(executor) {
this.state = "pending";
this.value = null;
this.reason = null;
this.onFulfilledCb = [];
this.onRejectCb = [];
const resolve = (value) => {
if (this.state === "pending") {
this.state = "fulfilled";
this.value = value;
this.onFulfilledCb.forEach((cb) => {
cb(this.value);
});
}
};
const reject = (reason) => {
if (this.state === "pending") {
this.state = "reject";
this.reason = reason;
this.onRejectCb((cb) => {
cb(this.reason);
});
}
};
executor(resolve, reject);
}
/**
* 返回一个promise对象,支持链式调用
* 接收两个可选回调函数,如果成功或失败调用对应的回调函数
* @param {*} onFulfilled
* @param {*} onRejected
* 返回Promise,增加setTimeout延迟代码块执行,不然取不到promise2值会报错
*/
then(onFulfilled, onReject) {
let promise2 = new Promise((resolve, reject) => {
// 如果promise成功或者失败,会立即调用对应的回调函数
// 如果是pending,将回调函数添加到回调数组中,并返回一个promise,该对象会在原Promise成功或失败时调用对应的回调函数。
if (this.state === "fulFilled") {
// 增加setTimeout的原因: 把当前任务放到下一个宏任务里执行。
// 利用eventLoop 宏任务,让代码块延迟执行,等new完Promise2 ,不然isPromise(Promise2,x,resolve, reject )中取不到Promise2会报错
// 因为处理异步可能会有问题
setTimeout(() => {
try {
let result = onFulfilled(this.value);
this.isPromise(promise2, result, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
} else if (this.state === "reject") {
setTimeout(() => {
try {
let result = onReject(this.value);
this.isPromise(promise2, result, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
} else {
this.onFulfilledCb.push(() => {
// 为代码简洁可读,暂时没有写try catch
setTimeout(() => {
const result = onFulfilled(this.value);
this.isPromise(promise2, result, resolve, reject);
}, 0);
});
this.onRejectCb.push(() => {
// 为代码简洁可读,暂时没有写try catch
setTimeout(() => {
const result = onReject(this.reason);
this.isPromise(promise2, result, resolve, reject);
}, 0);
});
}
});
return promise2;
}
/**
promise链式调用。在内部调用then方法时,返回一个新的promise,并让这个新的promise接管了它下一个then方法
* 前一个回调函数,有可能返回的还是一个Promise对象(即有异步操作),
* 这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用
x跟promise2不能只一个东西
* @param {*} promise
* @param {*} x
* @param {*} resolve
* @param {*} reject
* @returns
*/
function resolvePromise(promise, x, resolve, reject) {
// 防止内部的循环引用
if (promise === x) {
return reject(new TypeError("Chaining cycle detected for promise"));
}
// 解析x,判断他是一个promise
if (x instanceof MyPromise) {
x.then(resolve, reject);
} else {
resolve(x);
}
}
catch() {}
}
promise.all()
Promise.all 方法用于将多个Promise实例,包装成一个新的Promise实例
Promise.all 方法接受一个数组作为参数,p1、p2、p3都是Promise实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转换为Promise实例,再进行一步处理
promise.all状态由P1、P2、P3 决定的,分为两种情况
- 只有
p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。 - 只要
p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数
const p = Promise.all([]);
/**
* 返回一个promise对象,让外部可以调用then方法获取结果
* 主要逻辑遍历arr, 添加结果到数组中
* @param {*} arr
* @returns
*/
Promise.all = function (arr) {
let resultList = []; // 保存所有结果的数组
let index = 0; // 用于记录操作到第几个项,操作完返回数据
return new Promise((resolve, reject) => {
// 1、主要函数逻辑
for (let i = 0; i < arr.length; i++) {
// 2、判断当前项,是否为promise,如果是,则调用它的then方法获取返回结果
if (arr[i] instanceof Promise2) {
arr[i].then(
(value) => {
addData(i, value);
},
(reason) => {
reject(reason);
}
);
} else {
// 3、如果是普通对象的话,直接返回结果
addData(i, arr[i]);
}
}
function addData(key, value) {
resultList[key] = value;
index++;
if (index === arr.length) {
resolve(resultList);
}
}
});
};
promise.resolve 和 promise.reject
// promise.resolve 将现有对象转换为promise对象
Promise.resolve = function (value) {
if (value instanceof Promise) {
return value;
}
return new Promise((resolve) => {
resolve(value);
});
};
// promise.reject 返回一个新的promise实例,该实例的状态为rejected
Promise.reject = function (reason) {
return new Promise(_, (reject) => reject(reason));
};
Promise.prototype.finally
finally用于不管promise对象最后状态如何,都会执行的操作
调用当前promise的then方法返回一个新的promise对象
调用promise中的resolve方法进行返回
promise.finally(()=>{})
等同于
promise.then((result)=>{return result},(error)=>{ throw error})
Promise.prototype.finally = function (callback) {
return this.then(
(value) => {
this.resolve(callback()).then(() => value);
},
(reason) => {
this.resolve(callback()).then(() => reason);
}
);
};
Promise.prototype.catch
Promise.prototype.catch()方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数
Promise.prototype.catch = function (onReject) {
return this.then(null, onReject);
};
promise.race
Promise.race = function (arr) {
return new Promise((resolve, reject) => {
for (let i = 0; i < arr.length; i++) {
const cur = arr[i];
Promise.resolve(cur).then(resolve, reject);
}
});
};