核心逻辑,后面的 then 执不执行取决于第一个 new promise的回调函数的 resolve 回调函数的执不执行。
基础逻辑
1、promise 构造函数接收一个回调函数,该函数会在 new Promise 时候执行。
2、promise 构造函数里会创建两个函数,第一个函数会使该 promise 对象的状态变成 resolve,另一个函数会使该 promise 对象的状态变成 reject。
3、promise 构造函数里会把这两个函数作为回调函数的参数,这样回调函数可以改变 promise 实例的状态 。
1、then 方法接收两个回调函数,这里把第一个回调函数命名为 onResolved,第二个回调函数命名为 onReject,这是因为第一个回调在 promise 实例状态变为 resolved 时调用,第二个回调在 promise 实例状态变为 reject 时调用。
2、then 方法如果返回一个新的 promise 对象,则该 then 方法后面的 then 方法的回调函数必须等待该 then 方法返回的 promise 对象的状态变为 resolved 或 reject 后才会执行。
版本一,使用 setInterval 进行监听状态的改变
<!DOCTYPE html>
<html lang="zn-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
<script>
class Promise {
constructor(callback) {
this.status = "pending";
this.value = "";
this.reason = "";
const resolve = (value) => {
this.value = value;
this.status = 'resolve';
}
const reject = (value) => {
this.reason = value;
this.status = 'reject';
}
try {
typeof callback === "function" && callback(resolve);
} catch (error) {
reject(error);
}
}
}
// 监听 promise 对象
function then(target, resolveCallback, rejectCallback) {
if (target.status === 'pending') {
const newPromise = new Promise();
const id1 = setInterval(() => {
if (target.status === 'resolve') {
if (typeof resolveCallback === 'function') {
const res = resolveCallback(target.value);
if (res instanceof Promise) {
// console.log(res);
const id2 = setInterval(() => {
if (res.status === 'resolve') {
newPromise.value = res.value;
newPromise.status = 'resolve';
clearInterval(id2);
}
}, 1);
} else {
newPromise.value = res;
newPromise.status = 'resolve';
}
}
clearInterval(id1);
}
}, 1);
return newPromise;
}
}
const p1 = new Promise((resolve) => {
console.log('已经执行 1');
setTimeout(() => {
resolve('我是 p1 的 resolve 值');
}, 1000);
});
const p2 = then(p1, (res) => {
// console.log('已经执行 2');
console.log('p1 的 resolve 值:' + res);
return new Promise((resolve) => {
setTimeout(() => {
resolve('我是 p2 的 resolve 值');
}, 2000);
});
});
const p3 = then(p2, (res) => {
// console.log('已经执行 3');
console.log('p2 的 resolve 值:' + res);
});
const p5 = then(p3, (res) => {
console.log('已经执行 5');
return new Promise(() => {
setTimeout(() => {
console.log('我是 p5 new Promise 的 resolve 回调函数');
}, 3000);
});
});
</script>
</html>
版本二,使用 Promise 监听状态的改变
<!DOCTYPE html>
<html lang="zn-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
<script>
class Promise {
constructor(callback) {
this.status = "pending";
this.value = "";
this.reason = "";
const resolve = (value) => {
this.value = value;
this.status = 'resolve';
}
const reject = (value) => {
this.reason = value;
this.status = 'reject';
}
try {
typeof callback === "function" && callback(resolve);
} catch (error) {
reject(error);
}
}
}
// 监听 promise 对象
function then(target, resolveCallback, rejectCallback) {
if (target.status === 'pending') {
const newPromise = new Promise();
// 把对 target 的操作改成对 proxy 的操作
// 即把 status 存储在 proxy 上
const proxy = { status: 'pending' };
Object.defineProperty(target, 'status', {
get() {
return proxy.status;
},
set(newValue) {
proxy.status = newValue;
if (target.status === 'resolve') {
if (typeof resolveCallback === 'function') {
const res = resolveCallback(target.value);
// 如果函数返回值是一个 Promise 对象
if (res instanceof Promise) {
// 把对 Promise 对象的操作改成对 proxy 的操作
// 即把 status 存储在 proxy 上
const proxy = { status: 'pending' };
Object.defineProperty(res, 'status', {
get() {
return proxy.status;
},
set(newValue) {
proxy.status = newValue;
if (res.status === 'resolve') {
newPromise.value = res.value;
newPromise.status = 'resolve';
}
}
});
} else {
newPromise.value = res;
newPromise.status = 'resolve';
}
}
}
}
});
return newPromise;
}
}
const p1 = new Promise((resolve) => {
console.log('已经执行 1');
setTimeout(() => {
resolve('我是 p1 的 resolve 值');
}, 1000);
});
console.log('我是同步函数');
const p2 = then(p1, (res) => {
// console.log('已经执行 2');
console.log('p1 的 resolve 值:' + res);
return new Promise((resolve) => {
setTimeout(() => {
resolve('我是 p2 的 resolve 值');
}, 2000);
});
});
const p3 = then(p2, (res) => {
// console.log('已经执行 3');
console.log('p2 的 resolve 值:' + res);
});
const p5 = then(p3, (res) => {
console.log('已经执行 5');
return new Promise((resolve) => {
setTimeout(() => {
console.log('我是 p5 new Promise 的 resolve 回调函数');
resolve('我是 p5 的 resolve 值');
}, 3000);
});
});
</script>
</html>
版本二加强,把 then 函数整合成 Promise 对象的方法
<!DOCTYPE html>
<html lang="zn-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
<script>
class Promise {
constructor(callback) {
this.status = "pending";
this.value = "";
this.reason = "";
const resolve = (value) => {
this.value = value;
this.status = 'resolve';
}
const reject = (value) => {
this.reason = value;
this.status = 'reject';
}
try {
typeof callback === "function" && callback(resolve);
} catch (error) {
reject(error);
}
}
then(resolveCallback) {
if (this.status === 'pending') {
const newPromise = new Promise;
// 把对 target 的操作改成对 proxy 的操作
// 即把 status 存储在 proxy 上
const proxy = { status: 'pending' };
Object.defineProperty(this, 'status', {
get() {
return proxy.status;
},
set(newValue) {
proxy.status = newValue;
if (this.status === 'resolve') {
if (typeof resolveCallback === 'function') {
const res = resolveCallback(this.value);
// 如果函数返回值是一个 Promise 对象
if (res instanceof Promise) {
// 把对 Promise 对象的操作改成对 proxy 的操作
// 即把 status 存储在 proxy 上
const proxy = { status: 'pending' };
Object.defineProperty(res, 'status', {
get() {
return proxy.status;
},
set(newValue) {
proxy.status = newValue;
if (res.status === 'resolve') {
newPromise.value = res.value;
newPromise.status = 'resolve';
}
}
});
} else {
newPromise.value = res;
newPromise.status = 'resolve';
}
}
}
}
});
return newPromise;
}
}
}
const p1 = new Promise((resolve) => {
console.log('我是 new Promise 的回调函数');
setTimeout(() => {
resolve('我是 new Promise 的 resolve 值');
}, 1000);
});
console.log('我是同步函数');
p1.then((res) => {
// console.log('已经执行 2');
console.log('new Promise 的 resolve 值:' + res);
return new Promise((resolve) => {
setTimeout(() => {
resolve('我是第一个 then 的 resolve 值');
}, 1000);
});
}).then((res) => {
// console.log('已经执行 3');
console.log('第一个 then 的 resolve 值:' + res);
// console.log('我是 p3 的 resolve');
}).then((res) => {
// console.log('已经执行 5');
return new Promise((resolve) => {
setTimeout(() => {
console.log('我是第三个 then 的 new Promise 的 resolve 回调');
resolve('我是 p5 的 resolve 值');
}, 1000);
});
});
</script>
</html>
版本二再加强,把 resolve 函数、reject 函数、 then 回调函数放进微任务队列执行(使用 queueMicrotask 函数)
<!DOCTYPE html>
<html lang="zn-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
<script>
class Promise {
constructor(callback) {
this.status = "pending";
this.value = "";
this.reason = "";
const resolve = (value) => {
queueMicrotask(() => {
this.value = value;
this.status = 'resolve';
});
}
const reject = (value) => {
queueMicrotask(() => {
this.reason = value;
this.status = 'reject';
});
}
try {
typeof callback === "function" && callback(resolve);
} catch (error) {
reject(error);
}
}
then(resolveCallback) {
if (this.status === 'pending') {
const newPromise = new Promise;
// 把对 target 的操作改成对 proxy 的操作
// 即把 status 存储在 proxy 上
const proxy = { status: 'pending' };
Object.defineProperty(this, 'status', {
get() {
return proxy.status;
},
set(newValue) {
proxy.status = newValue;
if (this.status === 'resolve') {
if (typeof resolveCallback === 'function') {
queueMicrotask(() => {
const res = resolveCallback(this.value);
// 如果函数返回值是一个 Promise 对象
if (res instanceof Promise) {
// 把对 Promise 对象的操作改成对 proxy 的操作
// 即把 status 存储在 proxy 上
const proxy = { status: 'pending' };
Object.defineProperty(res, 'status', {
get() {
return proxy.status;
},
set(newValue) {
proxy.status = newValue;
if (res.status === 'resolve') {
newPromise.value = res.value;
newPromise.status = 'resolve';
}
}
});
} else {
newPromise.value = res;
newPromise.status = 'resolve';
}
});
}
}
}
});
return newPromise;
}
}
}
const p1 = new Promise((resolve) => {
console.log('我是 new Promise 的回调函数');
setTimeout(() => {
resolve('我是 new Promise 的 resolve 值');
}, 1000);
});
console.log('我是同步函数');
p1.then((res) => {
// console.log('已经执行 2');
console.log('new Promise 的 resolve 值:' + res);
return new Promise((resolve) => {
setTimeout(() => {
resolve('我是第一个 then 的 resolve 值');
}, 1000);
});
}).then((res) => {
// console.log('已经执行 3');
console.log('第一个 then 的 resolve 值:' + res);
// console.log('我是 p3 的 resolve');
}).then((res) => {
// console.log('已经执行 5');
return new Promise((resolve) => {
setTimeout(() => {
console.log('我是第三个 then 的 new Promise 的 resolve 回调');
resolve('我是 p5 的 resolve 值');
}, 1000);
});
});
</script>
</html>
错误版本
代码逻辑
then 返回一个新的 promise 对象(命名为 promise a),新的 promise 对象的构造函数里判断旧的 promise 对象的状态,如果旧 promise 对象的状态是等待(padding)状态,则把以下两个操作 push 进旧 promise 对象的 onResolved 回调队列
1、执行 then 的 onResolved 回调
2、执行新的 promise 对象构造函数的 resolve 回调函数,使新的 promise 对象的状态变为 resolve。
这样旧的 promise 对象只要执行了 resolve,新的 promise 对象的状态也会变为 resolve。
错误原因
忽略了 then 的 onResolved 回调函数里有可能返回一个 新的 promise 对象。
then 的 onResolved 回调函数里有可能返回一个 新的 promise 对象(命名为 promise b),该 promise b 的回调函数有可能是异步函数,必须等待该 promise b 的回调函数有了执行结果(即 promise b 的构造函数的回调函数里执行了 resolve 回调或是 reject 回调,即 promise b 的状态变为 resolve 或 reject )后才可以执行 promise a 的构造函数的 resolve 回调(即 promise a 的状态取决于 promise b )。
错误导致的后果
错误导致的后果就是该 then 方法后面跟着的 then 方法的回调函数没有等待该 then 方法回调函数里的 promise b 状态变为 resolve 或 reject 就立刻执行了。
<!DOCTYPE html>
<html lang="zn-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
<script>
class MyPromise {
// 构造函数的参数是一个回调函数
constructor(callback) {
this.status = "pending";
this.value = "";
this.reason = "";
// 存储成功状态的回调函数
this.onResolvedCallbacks = [];
// 存储失败状态的回调函数
this.onRejectedCallbacks = [];
// 定义 resolve 函数
// 每个 promise 对象的构造函数里都定义了一个 resolve 函数
// 该 resolve 函数可以修改该 promise 对象的状态为 resolve
const resolve = (value) => {
if (this.status == "pending") {
// 修改实例状态
this.status = "resolved";
this.value = value;
// console.log('执行 ResolvedCallback');
this.onResolvedCallbacks.forEach(fn => fn());
}
}
// 定义 reject 函数
// 每个 promise 对象的构造函数里都定义了一个 reject 函数
// reject 函数可以修改该 promise 对象的状态为 reject
const reject = (reason) => {
if (this.status == "pending") {
// 修改实例状态
this.status = "rejected";
this.reason = reason;;
// 执行
this.onRejectedCallbacks.forEach(fn => fn());
}
}
try {
// 把定义好的 resolve 函数和 reject 函数传进外部传入的回调函数
// 执行外部传入的回调函数
// 这样外部传入的回调函数就可以改变该 promise 实例的 status、value 或 reason
callback(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onResolved, onRejected) {
onResolved = typeof onResolved === "function" ? onResolved : (value) => value;
onRejected = typeof onRejected === "function" ? onRejected : (reason) => { throw reason };
// 创建一个新的 promise 对象 promise2
// 回调函数用的是箭头函数,所以回调函数里的 this 是 then 里的 this,即旧的 promise 对象
const promise2 = new MyPromise((resolve, reject) => {
// 如果旧的 promise 对象的状态等于 resolved
if (this.status == "resolved") {
try {
// 执行 then 方法的 onResolved 回调函数,参数是旧的 promise 对象的值(value 属性)
const res = onResolved(this.value);
// 执行 new MyPromise 回调函数里的 resolve 回调从而修改新 promise 实例的状态(status 属性)和值(value 属性)
resolve(res);
} catch (error) {
reject(error);
}
}
// 如果旧的 promise 对象的状态等于 rejected
if (this.status == "rejected") {
try {
// 执行 then 方法的 onRejected 回调函数,参数是旧的 promise 对象的 reason 属性
const x = onRejected(this.reason);
// 执行 promise2 回调函数里的 resolve 回调从而修改 promise2 实例的 status 属性和 value 属性
resolve(x);
} catch (error) {
reject(error);
}
}
// 如果旧的 promise 对象的状态等于 pending
if (this.status == "pending") {
// 往旧 promise 对象的 onResolvedCallbacks 数组添加箭头函数
// 因为用的是箭头函数,所以箭头函数里的 this 值的是旧的 promise 对象
this.onResolvedCallbacks.push(() => {
// 如果旧 promise 对象的 status 变为 resolved
if (this.status == "resolved") {
try {
// 执行 then 方法的 onResolved 回调函数 参数是旧 promise 对象的 value
const res = onResolved(this.value);
// 执行 new MyPromise 回调函数里的 resolve 回调从而修改新 promise 对象的 status 属性和 value 属性
// 参数是 then 方法的 onResolved 回调函数的返回值
resolve(res);
} catch (error) {
reject(error);
}
}
});
// 往 promise2 的 onRejectedCallbacks 数组添加匿名函数
// 因为用的是箭头函数,所以箭头函数里的 this 值的是旧的 promise 对象
this.onRejectedCallbacks.push(() => {
// 如果旧的 promise 对象的 status 变为 rejected
if (this.status == "rejected") {
try {
// 执行 then 方法的 onRejected 回调函数 参数是旧 promise 对象的 reason
const res = onRejected(this.reason);
// 执行 new MyPromise 回调函数里的 reject 回调从而修改 promise2 对象的 status 属性和 value 属性
// 参数是 then 方法的 onRejected 回调函数的返回值
resolve(res);
} catch (error) {
reject(error);
}
}
});
} else {
console.log('清空回调数组');
// 执行完所有回调函数之后,清空回调数组
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
}
});
// 返回 promise2
return promise2
}
catch(onRejected) {
return this.then(null, onRejected);
}
}
const p1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
console.log(1);
resolve('我是 p1 resolve 的成功');
}, 1000);
});
p1.then((res) => {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
console.log(2);
resolve('我是 p1 resolve 的成功 2');
}, 1000);
});
}).then((res) => {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
console.log(3);
resolve('我是 p1 resolve 的成功 3');
}, 1000);
});
});
// p1.then(1).then(value => {
// console.log('1');
// }).then(value => {
// console.log('2');
// return new MyPromise((resolve, reject) => {
// setTimeout(() => {
// resolve('第二次处理结果');
// }, 1000);
// });
// }).then(value => {
// //console.log(value);
// console.log(value);
// throw new Error('抛出异常');
// }).catch(error => {
// console.log(error);
// });
</script>
</html>