# Promise
# 异步编程的问题: 代码逻辑不连续
循环系统和消息队列的操作,页面的一大特点:异步回调。 Web 页面的单线程架构决定了异步回调,而异步回调影响了我们编码的方式。
回调会导致代码的逻辑不连贯、不线性,非常不符合人的直觉。
封装异步,让处理流程变的线性。关注输入和输出,而不关注中间内容。
# 控制倒转
先指定回调函数,然后才写逻辑。 我们应该先指定逻辑,后写入回调。
# 回调地狱
- 第一个是嵌套调用。依赖关系。
- 第二个是任务的不确定性,执行每个任务都有两种可能的结果,需要对每个任务的执行结果做两次判断。增加了代码的混乱程度。
# 需要解决任务
- 消灭嵌套
- 合并多个任务的错误处理。
# Promise如何解决嵌套
- 返回一个 promise 对象。
- 传入一个 executor 函数,业务流程都在 executor 中执行。
- 如果 executor 的业务成功了,会调用 resolve,失败了调用 reject。
- executor 调用 resolve ,会触发 promise.then 设置的回调函数.
Promise 实现了回调函数的延时绑定。先创建 Promise 对象,通过 Promise 的 executor 来执行业务逻辑。创建好 Promise 对象之后,使用 then 来设置回调函数。
需要将回调函数 onResolve 的返回值穿透到最外层。这样就可以摆脱嵌套循环了。
# Promise如何解决错误处理
最后一个对象来捕获所有的异常,因为 Promise 对象的错误具有冒泡性质,向后传递,直到被 onReject 函数 或者 cache 语句捕获为止。就不需要对每个 promise 单独捕获异常了。
# Promise与微任务
Promise 的构造函数调用executor函数,在 executor 函数中执行 resolve,由于 Promise 采用了回调函数延迟绑定技术,所以在 resolve 函数的时候,回调函数还没有绑定,只能拖迟回调函数的执行。Promise 将改造成了微任务,可以让 onResolved 延迟被调用,又提高了代码的执行效率。
# Promise 概念
new Promise(function () {
})
当传递给 new Promise 的函数被称为 executor, new Promise 被创建,executor 会被自动运行。它会提供两个参数 resolve、reject。
当 executor 获取到了结果,无论是什么时候获取到了,它都应该执行这两个回调函数。
- resolve 成功的回调
- reject 失败的回调
new Promise 构造器返回的 promise 对象具有以下的内部属性。
- 状态最初为 pending, 然后 resolve 被改变为 fulfilled. 在 reject 变为 rejected
- result 最初为 undefined, 然后 resolve(value) 改为 value, 或者在 reject(error) 变为 error.
注意: 只能改变一次,改变之后就不能够改变了。
状态都是内部的,但是我们可以使用 then/catch/finally.
# promise 特点
- 对象的状态不受外界的影响。promise 对象代表一个异步操作。有三种状态。pending、fulfilled、rejected。 只有异步操作的结果,可以决定当前是哪一种状态,任何其他的操作都无法改变这个状态。承若。
- 一旦状态发送变化,任何时候都能得到这个结果。promise 对象的改变,只有两种:pending到成功,pending变为rejected。这时候就会变为已定型的。如果已经变化,对 promise 添加回调函数,就会立即得到这个结果。
# promise 缺点
- 无法取消 promise,一旦新建它就会之际执行,promise本身是同步的立即执行函数。无法中途取消。
- 如果不设置回调函数,promise内部抛出的错误,无法反映到外部。
- 当处于pending状态时,无法得知具体到哪一个阶段。
# 实现 Promise
- Promise 的基本状态, status 状态。 data 保存结果。callbacks 来存放回调。
function Promise(executor) {
this.status = 'pending';
this.data = null;
this.callbacks = [];
executor();
}
- resolve, reject 函数. 注意:promise 的状态只能改变一次。
function Promise(executor) {
const self = this;
this.status = 'pending';
this.data = null;
this.callbacks = [];
function resolve(value) {
if (self.status !== 'pending') return;
self.status = 'resolved';
self.data = value;
}
function reject(reason) {
if (self.status !== 'pending') return;
self.status = 'rejected';
self.data = reason;
}
executor(resolve, reject);
}
- throw xxx 状态也会变为失败。
function Promise(executor) {
const self = this;
this.status = 'pending';
this.data = null;
this.callbacks = [];
function resolve(value) {
if (self.status !== 'pending') return;
self.status = 'resolved';
self.data = value;
}
function reject(reason) {
if (self.status !== 'pending') return;
self.status = 'rejected';
self.data = reason;
}
try {
executor(resolve, reject); // 接收到 throw 之后
} catch (error) {
reject(error);
}
}
- then
Promise.prototype.then = function (onResolved, onRejected) {
const self = this;
if (self.status === 'pending') {
self.callbacks.push({
onResolved,
onRejected
})
} else if (self.status === 'resolved') {
setTimeout(() => {
onResolved(self.data);
});
} else if (self.status === 'rejected') {
setTimeout(() => {
onRejected(self.data);
})
}
}
then 返回 promise then 返回一个 promise, 链式调用 then,下一次的 then 回调用来接收上一次的 then 返回的 promise 的结果。
返回的 promise 成功, 那么下一次的 then 的结果就是成功。
返回的 promise 失败,下一次的 then 的结果就是失败。
如果 返回的结果是 promise, 那么这个 promise 的结果就是当前 promise 结果。
Promise.prototype.then = function (onResolved, onRejected) {
const self = this;
return new Promise((resolve, reject) => {
if (self.status === 'pending') {
self.callbacks.push({
onResolved,
onRejected
})
} else if (self.status === 'resolved') {
setTimeout(() => {
try {
const result = onResolved(self.data);
if (result instanceof Promise) {
result.then(
value => resolve(value),
reason => reject(reason)
)
} else {
resolve(result);
}
} catch (error) {
reject(error);
}
});
} else if (self.status === 'rejected') {
setTimeout(() => {
onRejected(self.data);
})
}
})
}
- then 返回 promise (2)
Promise.prototype.then = function (onResolved, onRejected) {
const self = this;
return new Promise((resolve, reject) => {
function handler(callback) {
try {
const result = callback(self.data);
if (result instanceof Promise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (error) {
reject(error);
}
}
if (self.status === PENDING) {
self.callbacks.push({
onResolved() {
handler(onResolved)
},
onRejected() {
handler(onRejected)
}
})
} else if (self.status === RESOLVED) {
setTimeout(() => {
handler(onResolved);
});
} else if (self.status === REJECTED) {
setTimeout(() => {
handler(onRejected);
});
}
})
}
- 异常穿透
Promise.prototype.then = function (onResolved, onRejected) {
onResolved = typeof onResolved === 'function' ? onResolved : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}; // 异常穿透的关键
}
- catch
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected);
}
← 宏任务/微任务 async await →