Promise
Promise对象代表一个一步操作,共有三种功能状态:
- pending进行中;
- fulfilled已成功;
- rejected已失败;
pending为默认状态,执行的结果只能是fulfilled和rejected,并且状态是不可逆的。
Promise只以第一次为准,第一成功就永久为fulfilled,第一次失败就永久为rejected;
Promise中有throw的话,就等于是执行了reject();
resolve可以把状态改为fulfilled,reject或者throw可以把状态修改为rejected;
处于pending状态的Promise,then函数不会被调用;
实例化Promise对象时候必须传递一个函数,这个函数包含两个参数:resolve、reject;
代码如下
// Promise 有三种状态
class MyPromise {
// pending/fulfilled/rejected, 初始是pending,只能变为fulfilled或者rejected并且不可逆
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(func) {
// Promise的结果
this.result = null;
// Promise的状态
this.status = MyPromise.PENDING;
// 异步处理的回调函数
this.fulfilledCallBack = [];
this.rejectedCallBack = [];
try {
// 防止this丢失
func(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error);
}
}
// 成功的回调
resolve(result) {
if (this.status === MyPromise.PENDING) {
this.status = MyPromise.FULFILLED;
this.result = result;
// 把存的异步回调拿出来执行
this.fulfilledCallBack.forEach((cb) => cb(result));
}
}
// 失败的回调
reject(reason) {
// 同上
if (this.status === MyPromise.PENDING) {
this.status = MyPromise.FULFILLED;
this.result = reason;
this.rejectedCallBack.forEach((cb) => cb(reason));
}
}
// then 方法,接受两个回调函数
then(onFulfilled, onRejected) {
// 判断是否是函数
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (value) => value;
onRejected =
typeof onRejected === "function"
? onRejected
: (reason) => {
throw reason;
};
// 成功就执行成功的,失败就执行失败的,还是pending就先收集起来
if (this.status === MyPromise.PENDING) {
this.fulfilledCallBack.push(() => {
setTimeout(() => {
onFulfilled(this.result);
});
});
this.rejectedCallBack.push(() => {
setTimeout(() => {
onRejected(this.result);
});
});
}
if (this.status === MyPromise.FULFILLED) {
// 回调函数是异步执行的
setTimeout(() => {
onFulfilled(this.result);
});
}
if (this.status === MyPromise.REJECTED) {
// 回调函数是异步执行的
setTimeout(() => {
onRejected(this.result);
});
}
}
}
// 测试代码
/** 测试代码start **/
console.log(1);
let promise1 = new MyPromise((resolve, reject) => {
console.log(2);
setTimeout(() => {
console.log("A", promise1.status);
resolve("这次一定");
console.log("B", promise1.status);
console.log(4);
});
});
promise1.then(
(result) => {
console.log("C", promise1.status);
console.log("fulfilled:", result);
},
(reason) => {
console.log("D", promise1.status);
console.log("rejected:", reason);
}
);
/** 测试代码stop **/
then链式调用
then方法需要返回一个新的promise对象才能支持链式调用;
根据第一个promise处理的结果来处理下一个promise的操作;
第一个promise的处理结果有三种情况:
- 是一个普通值;
- 还是一个promise对象;
- 是一个对象或者方法,有可能是一个thenable对象;
如果是一个普通值,就直接resolve;
如果是一个promise对象,就调用对应的then方法继续处理;
如果是一个对象或者方法,就判断是否是一个thenable对象,thenable对象需要特殊处理,需要添加一个开关判断是否正在执行,因为then方法有可能被调用多次,如果是一个普通对象或者函数,直接resolve;
代码如下
// 手写promise then函数的调用
class MyPromise {
// pending/fulfilled/rejected, 初始是pending,只能变为fulfilled或者rejected并且不可逆
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(func) {
// Promise的结果
this.result = null;
// Promise的状态
this.status = MyPromise.PENDING;
// 异步处理的回调函数
this.fulfilledCallBack = [];
this.rejectedCallBack = [];
try {
// 防止this丢失
func(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error);
}
}
// 成功的回调
resolve(result) {
if (this.status === MyPromise.PENDING) {
this.status = MyPromise.FULFILLED;
this.result = result;
// 把存的异步回调拿出来执行
this.fulfilledCallBack.forEach((cb) => cb(result));
}
}
// 失败的回调
reject(reason) {
// 同上
if (this.status === MyPromise.PENDING) {
this.status = MyPromise.FULFILLED;
this.result = reason;
this.rejectedCallBack.forEach((cb) => cb(reason));
}
}
then(onFulfilled, onRejected) {
// 链式调用需要返回一个行的promise
const promise2 = new MyPromise((resolve, reject) => {
if (this.status === MyPromise.PENDING) {
this.fulfilledCallBack.push(() => {
setTimeout(() => {
try {
if (typeof onFulfilled !== "function") {
resolve(this.result);
} else {
let x = onFulfilled(this.result);
resolvePromise(promise2, x, resolve, reject);
}
} catch (error) {
reject(error);
}
});
});
this.rejectedCallBack.push(() => {
setTimeout(() => {
try {
if (typeof onRejected === "function") {
reject(this.result);
} else {
let x = onRejected(this.result);
resolvePromise(promise2, x, resolve, reject);
}
} catch (error) {
reject(error);
}
});
});
}
// 成功和失败的时候都需要处理 promise
if (this.status === MyPromise.FULFILLED) {
setTimeout(() => {
// 获取处理的返回值
// 如果获取失败,直接就拒绝掉
try {
// 判读但onFullfilled是否是一个函数,不是函数直接返回结果
if (typeof onFulfilled !== "function") {
resolve(this.result);
} else {
let x = onFulfilled(this.result);
resolvePromise(promise2, x, resolve, reject);
}
} catch (error) {
reject(error);
}
});
}
if (this.status === MyPromise.REJECTED) {
setTimeout(() => {
try {
// 判断是否是函数
if (typeof onRejected === "function") {
let x = onRejected(this.result);
resolvePromise(promise2, x, resolve, reject);
} else {
reject(this.result);
}
} catch (error) {
reject(error);
}
});
}
});
return promise2;
}
}
/**
* 在新的promise中处理resolve和reject
* @param {*} promise2 返回新的promise对象
* @param {*} x promise1处理的结果
* @param {*} resolve 新的promise的resolve方法
* @param {*} reject 新的promise的reject方法
*
*/
function resolvePromise(promise2, x, resolve, reject) {
// 如果返回的promise和当前的promise相同,就报错
if (promise2 === x) {
return reject(new TypeError("循环引用了 "));
}
// 处理不同值
// 1.是一个promise
// 2.是一个对象或者函数,有thenable方法则执行then,否则直接resolve
// 3.一个普通值
if (x instanceof promise2) {
// 是一个promise的实例,执行then 方法
x.then((y) => {
resolvePromise(promise2, y, resolve, reject),
(reason) => {
reject(reason);
};
});
} else if (x !== null && (typeof x === "object" || typeof x === "function")) {
let then;
try {
then = x.then;
} catch (error) {
reject(error);
}
if (typeof then === "function") {
let called = false;
try {
then.call(x, (y) => {
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
}),
(r) => {
if (called) return;
called = true;
reject(r);
};
} catch (error) {
if (called) return;
called = true;
reject(error);
}
} else {
resolve(x);
}
} else {
// 普通值直接返回
return resolve(x);
}
}
// 测试代码
/** 测试代码start **/
console.log(1);
let promise1 = new MyPromise((resolve, reject) => {
console.log(2);
setTimeout(() => {
console.log("A", promise1.status);
resolve("这次一定");
console.log("B", promise1.status);
console.log(4);
});
});
promise1.then(
(result) => {
console.log("C", promise1.status);
console.log("fulfilled:", result);
},
(reason) => {
console.log("D", promise1.status);
console.log("rejected:", reason);
}
);
/** 测试代码stop **/
其他方法
resolve
resolve方法是将一个值编程一个promise对象。
传入的值有这三种判断:
- 如果是一个promise对象直接返回;
- 如果是一个thenable对象,就是带有then方法的对象,会跟随这个thenable对象的then方法返回一个新的promise;
- 否则就返回一个新的promise并且resolve这个值
代码如下
MyPromise.resolve = function (value) {
//1.是一个promise直接返回
if (value instanceof MyPromise) {
return value;
}
// 是一个thenable。跟随这个thenable
if (typeof value === "object" && value !== null && "then" in value) {
return new MyPromise((resolve, reject) => {
value.then(resolve, reject);
});
}
// 如果只是普通值,直接reso
return new MyPromise((resolve, reject) => {
resolve(value);
});
};
reject
reject 方法是返回一个带有拒绝原因的对象;
原理就是返回一个新的promise然后执行reject方法,把传入原因reject出去;
代码如下
MyPromise.reject = function (reason){
return new MyPromise((resolve,reject)=>{
reject(reason);
})
};
catch
catch 方法其实就是 .then(undefined,onRejected)的简写;
代码如下
catch(onRejected){
return this.then(undefined,onRejected);
}
finally
finally方法,不管promise的状态如何,都会执行内部其实就是执行then方法,并把传入的参数作为then方法的入参;
代码如下
finally(callback){
return this.then(callback,callback);
}
all
all 方法接受一个promise数组,如果数组中包含普通值,不会做处理原封不动的返回;
all 方法会等待所有任务完成,或者遇到第一个失败的任务就返回,并且返回一个新的promise实例,存放所有成功结果的数组,失败则抛出第一个失败的原因;
代码如下
// 接受一个promise数组
static all(promises) {
// 返回一个新的promise实例
return new MyPromise((resolve, reject) => {
if (Array.isArray(promises)) {
// 存放所有的成功的结果
const result = [];
// 计数器
let count = 0;
// 如果传入的是空数组
if (promises.length === 0) {
// 直接把原内容返回
resolve(promises);
}
promises.forEach((item, index) => {
MyPromise.resolve(item).then(
(value) => {
count++;
result[index] = value;
count === promises.length && resolve(result);
},
(reason) => {
// 如果第一个就报错,直接结束
reject(reason);
}
);
});
} else {
throw new TypeError("传入的参数必须是一个数组");
}
});
}
allSettled
allSettled方法接受一个promise数组,返回一个新的promise对象,会处理每一个promise,给出一个数组对象,每个对象表示对应的promise结果;
allSettled适合用于有多个不相互依赖的异步任务中,或者你想要知道每一个promise的结果,而all 更适合彼此有相互依赖或者其中一个失败就立即结束的情况;
对于每个结果对象,都有一个status字符串,如果成功就是fulfilled,对应的值是value,如果失败就是rejected,对应的值是reason;
代码如下
static allSettled(promises) {
return new MyPromise((resolve, reject) => {
// 判断promises是否是一个数组
if (Array.isArray(promises)) {
const result = [];
let count = 0;
if (promises.length === 0) {
resolve(promises);
}
promises.forEach((item, index) => {
MyPromise.resolve(item).then(
(value) => {
count++;
result[index] = {
status: MyPromise.FULFILLED,
value,
};
count === promises.length && resolve(result);
},
(reason) => {
count++;
result[index] = {
status: MyPromise.REJECTED,
value: reason,
};
count === promises.length && resolve(result);
}
);
});
} else {
throw new TypeError("传入的参数必须是一个数组");
}
});
}
any
any和all是相反的;
any接受一个promise数组,只要其中有一个promise成功,就返回那个成功promise;
如果都失败了,就返回一个失败promise;
如果参数是一个空数组,返回一个失败的promise;
如果参数中不包含promise,将这些数据转换成一个promise然后返回一个成功promise;
代码如下
static any(promises) {
// 返回一个新的promise
return new MyPromise((resolve, reject) => {
// 判断是否是一个数组
if (Array.isArray(promises)) {
// 收集错误
const errors = [];
// 计数器
let count = 0;
// 如果传入的是空数组
if (promises.length === 0) {
// 直接把原内容返回
reject(new Error("promises为空"));
}
promises.forEach((item, index) => {
// 把非promise转成promise
MyPromise.resolve(item).then(
(value) => {
// 有一个成功直接resolve
resolve(value);
},
(error) => {
count++;
errors[index] = error;
count === promises.length && reject(new Error(errors));
}
);
});
} else {
reject(new TypeError("传入的参数必须是一个数组"));
}
});
}
race
返回第一个执行成功的promise;
也就是接受第一个promise数组,返回第一个成功的promise;
如果是一个空数组,返回一个永远等待的promise;
代码如下
static race(promises) {
return new MyPromise((resolve, reject) => {
if (Array.isArray(promises)) {
if (promises.length > 0) {
promises.forEach((item) => {
// 第一个处理完成的返回
MyPromise.resolve(item).then(resolve, reject);
});
}
} else {
reject(new TypeError("promises必须是一个数组"));
}
});
}