Promise特点
- then的返回值
const promise = new Promise((resolve, reject) => {
resolve("success");
});
// 普通值会转为Promise对象
promise.then((res) => {
return "haha"; // Promise.resolve('hahaha')
});
// 返回Promise
promise.then((res) => {
return new Promise((resolve, reject) => {
resolve("success");
});
});
// 返回thenable对象
promise.then((res) => {
return {
then(resolve, reject) {
resolve("tianzhen");
},
};
});
- then和catch都会返回一个新的Promise
promise理解
- 异步编程的一种解决方案,
- JS原生对象
- 解决了以前回调地狱
- 改善了异步编程的困境
- 回调函数和事件更强大
三种状态
pending
fulfilled
rejected
pending->fulfilled/rejected一旦转换无法更改
异常处理
.then((success, error))
, 弊端:只能捕获Promise主体异常,如果success里出现异常则无法捕获try...catch
, 弊端:只能捕获同步代码异常.catch()
,推荐使用catch
捕获
链式调用
.then().then().catch()
每次调用都会返回一个新的Promise实例对象,所以可以.then()
实例API(原型)
then
catch
finally
静态方法
resolve
reject
all([])
所有promise
都fulfilled
race([])
任一fulfilled、rejected
any([])
第一个fulfilled
,es12/es2021: 拿到第一个resolve
allSettled
都有结果(无论是resolve,reject
)any
第一个resolve
其他
resolve()
参数
- 参数是普通类型,返回值将自动转为
promise
- 参数是
promise
,状态由promise
的resolve、reject
决定 - 参数是
thenable
对象,也会执行then
方法
基础实现
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class myPromise {
constructor(executor) {
this.status = "pending"; // 保存当前处于哪一状态
this.reason = undefined; // 保存reject结果
this.value = undefined; // 保存resolve结果
const resolve = (value) => {
console.log(value);
this.value = value;
};
const reject = (reason) => {
console.log(reason);
this.reason = reason;
};
executor(resolve, reject);
}
}
const p = new myPromise((resolve, reject) => {
resolve("success");
reject("fail");
throw new Error("error");
});
问题:
- resolve和reject都执行了
- 最终status: rejected
- 无法捕获主体异常
添加状态不可逆
const resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED;
console.log(value);
this.value = value;
}
};
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED;
console.log(reason);
this.reason = reason;
}
};
捕获主体异常
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
实现then
then(onFulfilled, onRejected) {
if(this.status === FULFILLED) {
onFulfilled(this.value)
}
if(this.status === REJECTED) {
onFulfilled(this.reason)
}
}
// 测试
p.then(res => {
console.log(res) // success
})
问题:
- 无法处理主体异步问题
const p = new myPromise((resolve, reject) => {
setTimeout(() => {
resolve("timeout");
}, 1000);
});
p.then((res) => {
console.log("res", res); // 这里不会执行
});
解决异步问题
因为执行then的时候status的状态还是pending,所以就没办法执行onFulfilled, 可以先将then的回调先保存起来,在resolve或reject时再调用
constructor(executor) {
this.fulfilledCallbacks = [] // then 可以多次调用,使用数组保存
this.rejectedCallbacks = []
}
then(onFulfilled, onRejected) {
if(this.status === PENDING) {
onFulfilled && this.fulfilledCallbacks.push(onFulfilled)
onRejected && this.rejectedCallbacks.push(onRejected)
}
}
const resolve = (value) => {
this.fulfilledCallbacks.forEach(cb => {
cb(this.value)
})
}
const reject = (reason) => {
this.fulfilledCallbacks.forEach(cb => {
cb(this.reason)
})
}
- 完整代码
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class myPromise {
constructor(executor) {
this.status = "pending"; // 保存当前处于哪一状态
this.reason = undefined; // 保存reject结果
this.value = undefined; // 保存resolve结果
this.fulfilledCallbacks = [];
this.rejectedCallbacks = [];
const resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED;
// console.log(value)
this.value = value;
this.fulfilledCallbacks.forEach((cb) => {
cb(this.value);
});
}
};
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED;
// console.log(reason)
this.reason = reason;
this.rejectedCallbacks.forEach((cb) => {
cb(this.reason);
});
}
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value);
}
if (this.status === REJECTED) {
onFulfilled(this.reason);
}
if (this.status === PENDING) {
onFulfilled && this.fulfilledCallbacks.push(onFulfilled);
onRejected && this.rejectedCallbacks.push(onRejected);
}
}
}
const p = new myPromise((resolve, reject) => {
// resolve('success')
// reject('fail')
// throw new Error('eeeeee')
setTimeout(() => {
resolve("timeout");
}, 1000);
});
p.then((res) => {
console.log("res1==========================", res);
});
p.then((res) => {
console.log("res2==========================", res);
});
实现链式调用
返回一个新的promise实例
then(onFulfilled, onRejected) {
const thenPromise = new myPromise((resolve, reject) => {
if(this.status === FULFILLED) {
try {
const value = onFulfilled(this.value)
resolve(value)
} catch (error) {
reject(error)
}
}
if(this.status === REJECTED) {
try {
const value = onRejected(this.reason)
resolve(value)
} catch (error) {
reject(error)
}
}
if(this.status === PENDING) {
onFulfilled && this.fulfilledCallbacks.push(() => {
try {
const value = onFulfilled(this.value)
resolve(value)
} catch (error) {
reject(error)
}
})
onRejected && this.rejectedCallbacks.push(() => {
try {
const value = onRejected(this.reason)
resolve(value)
} catch (error) {
reject(value)
}
})
}
})
return thenPromise
}
- 注意
之前的
onFulfilled && this.fulfilledCallbacks.push(onFulfilled)
要改成下面这样
onFulfilled &&
this.fulfilledCallbacks.push(() => {
try {
const value = onFulfilled(this.value);
resolve(value);
} catch (error) {
reject(error);
}
});
因为之前是直接push了onFulfilled,无法拿到onFulfilled的结果
添加catch
catch可以看做是then只传了第二个参数
catch(onRejected) {
this.then(undefined, onRejected)
}
- 完整代码
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
// 统一处理异常
const catchFn = (fn, value, resolve, reject) => {
try {
const result = fn(value);
resolve(result);
} catch (error) {
reject(error);
}
};
class myPromise {
constructor(executor) {
this.status = "pending"; // 保存当前处于哪一状态
this.value = undefined; // 保存resolve结果
this.reason = undefined; // 保存reject结果
this.fulfilledCallbacks = [];
this.rejectedCallbacks = [];
const resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED;
// console.log(value)
this.value = value;
while (this.fulfilledCallbacks.length) {
this.fulfilledCallbacks.shift()(this.value);
}
}
};
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED;
// console.log(reason)
this.reason = reason;
while (this.rejectedCallbacks.length) {
this.rejectedCallbacks.shift()(this.reason);
}
}
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
onRejected =
typeof onRejected === "function"
? onRejected
: (reason) => {
throw reason;
};
const thenPromise = new myPromise((resolve, reject) => {
if (this.status === FULFILLED) {
catchFn(onFulfilled, this.value, resolve, reject);
}
if (this.status === REJECTED) {
catchFn(onRejected, this.reason, resolve, reject);
}
if (this.status === PENDING) {
onFulfilled &&
this.fulfilledCallbacks.push(() => {
catchFn(onFulfilled, this.value, resolve, reject);
});
onRejected &&
this.rejectedCallbacks.push(() => {
catchFn(onRejected, this.reason, resolve, reject);
});
}
});
return thenPromise;
}
catch(onRejected) {
this.then(undefined, onRejected);
}
}
真题
返回非promise对象
返回非
promise
对象都会转为promise
(function () {
Promise.resolve()
.then(() => {
return new Error("error");
})
.then((res) => {
console.log("then: ", res);
})
.catch((err) => {
console.log("catch: ", err);
});
// then: Error: error
})();
- 尽管是抛出了异常,其实 return new Error(‘error’) === Promise.resolve(new Error(‘error’))
值穿透
Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log);
then
catch
的参数期望是函数,传入非函数会发生值穿透- 第一个
then
和第二个then
的参数都不是函数,所以发生了值穿透,1
直接进入了最后一个then