「这是我参与2022首次更文挑战的第9天,活动详情查看:2022首次更文挑战」。
Promise
- Promise 有三个状态, pending 等待态, reject 失败态, resolve 成功态
- new Promise 时需要传递一个 executor 执行器,执行器会立即执行
- 执行器中传递两个参数 resolve 成功函数,它调用的时候可以传递一个值,值可以是任何值. reject 失败函数,它调用时也可以传递一个值,值可以是任何值
- 从初始等待态 pending 只可以向失败态 reject 或者成功态 resolve 转变且不能再更改
- Promise 的每个实例都拥有一个 then 方法,这个方法传递两个参数,一个是成功的回调,另一个是失败的回调
- 如果调用 then 时,发现已经成功,会让这个成功函数执行并且把成功的内容当做参数传递到 then 方法的成功回调中,反之就是失败回调中
- Promise 中可以同一个实例多次调用 then 方法多次,如果状态是 pending 需要将函数存放起来,等状态确定后,在以此将对应函数执行(发布订阅)
- 如果执行时出现异常,Promise 状态就会从 pending 变更为失败态 reject
let p = new Promise((resolve, reject) => {
resolve(1);
})
let p2 = new Promise((resolve, reject) => {
reject(2);
})
p.then((value) => {
console.log(value); // 1
}, (reason) => {
console.log('err', reason);
});
p.then((value) => {
console.log(value); // 1
}, (reason) => {
console.log('err', reason);
});
p2.then((value) => {
console.log(value)
}, (reason) => {
console.log('err', reason); // 2
});
链式调用
- 每次 Promise 执行 then 后都会返回一个新的 Promise
- 如果 then 中返回的是一个结果,会把这个结果传递到下一次 then 中的成功回调
- 如果 then 中出现异常,会走下一个 then 的失败回调并错误传递到失败回调中
- catch 会捕获到没有捕获的异常
如果 then 方法返回的是一个 Promise 那么会等待这个 Promise 执行完决定返回的是成功态还是失败态 为什么要返回一个新的 Promise 而不是 this 是因为 Promise 的状态一但确定后就不能更改
let p = new Promise((resolve, reject) => {
resolve(1);
})
p.then(data => {
console.log(data); // 1
throw new Error('啥也不是');
}).then(null, (err) => {
console.log(err); // Error: 啥也不是
})
Promise 实现
function MyPromise(executor) {
let self = this;
self.status = 'pending'; // 初始状态
self.value = undefined; // 成功回调传递值
self.reason = undefined; // 失败回调传递值
self.onResolved = []; // 成功事件池
self.onRejected = []; // 失败事件池
function resolve(value) {
// 成功状态函数
if (self.status === 'pending') {
self.value = value;
self.status = 'resolved';
self.onResolved.forEach(fn => fn());
}
};
function reject(reason) {
// 失败状态函数
if (self.status === 'pending') {
self.reason = reason;
self.status = 'rejected';
self.onRejected.forEach(fn => fn());
}
};
try {
executor(resolve, reject);
} catch (e) {
// catch 会捕获到没有捕获的异常 一层语法糖
reject(e);
}
}
// 解析函数 判断then 链式调用之后的是否都是Promise
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('循环引用'));
}
// 这个方法是处理所有 Promise 的实现
let called; // 用来防止多次调用
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then;
if (typeof then === 'function') {
// 让返回的这个 x 也就是返回的 Promise 执行
// 用它的状态让promise2 成功或者失败
then.call(x, (y) => {
if (called) return;
called = true;
// 递归解析 如果resolve 是一个 Promise 就要不停的让resolve的结果进行处理
resolvePromise(promise2, y, resolve, reject);
}, (e) => {
if (called) return;
called = true;
reject(e)
});
} else {
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
reject(e);
}
} else {
// x就是一个普通值 (就用这个值让返回的promise成功即可)
resolve(x);
}
}
MyPromise.prototype.then = function (onfulfilled, onRejected) {
// 判断onfulfilled是否是函数 不是返回一个函数 因为是成功的回到要保持他的存在意义
onfulfilled = typeof onfulfilled === 'function' ? onfulfilled : val => val;
// 判断onRejected是否是函数 不是直接返回报错信息
console.log(typeof onRejected);
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
let self = this;
// 这里需要判断 onfulfilled与onfulfilled执行结果和 promise2 的关系
let promise2;
promise2 = new MyPromise((resolve, reject) => {
if (self.status === 'resolved') {
setTimeout(() => {
try {
let x = onfulfilled(self.value); // 将resolve传递的参数在then的成功回调函数中
resolvePromise(promise2, x, resolve, reject); // 解析x 和 promise2的关系
} catch (e) {
reject(e);
}
}, 0)
};
if (self.status === 'rejected') {
setTimeout(() => {
try {
let x = onRejected(self.reason); // 将reject传递的参数在then的失败回调函数中
resolvePromise(promise2, x, resolve, reject); // 解析x 和 promise2的关系
} catch (e) {
reject(e);
}
}, 0)
};
if (self.status === 'pending') {
// 将 pending 状态 先放进 成功状态池中
self.onResolved.push(function () {
setTimeout(() => {
try {
let x = onfulfilled(self.value);
resolvePromise(promise2, x, resolve, reject); // 解析x 和 promise2的关系
} catch (e) { reject(e); }
}, 0)
});
self.onRejected.push(function () {
setTimeout(() => {
try {
let x = onRejected(self.reason);
resolvePromise(promise2, x, resolve, reject); // 解析x 和 promise2的关系
} catch (e) {
reject(e);
}
}, 0)
})
}
})
return promise2
}
let a = new MyPromise((resolve, reject) => {
// resolve('MyPromise 成功了吗');
reject('MyPromise 失败了吗')
});
a.then((value) => {
console.log(value);
}, (e) => {
console.log(e);
})