回顾用法
let promise = new Promise((resolve, reject) => {
resolve('成功')
resolve('reject')
})
promise.then(value => {}, reason => {})
复制代码
Promise
就是一个类 在执行这个类的时候,需要传递一个执行器进去 执行器会立即执行Promise
有三种状态 分别为成功fulfilled
、 失败rejected
、 等待pending
。
-
一旦状态确定就不可更改
-
pending -> fulfilled
-
pending -> rejected
- resolve 和 rejected 函数是用来更改状态的
- resolve : fulfilled
- reject : rejected
-
then方法内部做的事情就判断状态 如果状态是成功 调用成功的回调函数 如果状态是失败 调用失败回调函数 then方法是被定义在原型对象中的
-
then成功回调有一个参数 表示成功之后的值 then失败回调有一个参数 表示失败后的原因
核心逻辑
定义状态枚举
- 把三个状态定义为枚举。 便于以后的非字符串输入引起错误
代码如下
const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";
复制代码
定义一个类
- 在回顾用法中知道,new promise 过程中会传入
代码如下
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject);
}
}
复制代码
状态更改
- 状态只允许更改一次。,要做非等待状态的判断
- 修改对应的状态
代码如下
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject);
}
status = PENDING;
resolve = () => {
// 状态只允许更改一次。
if (this.status !== PENDING) return;
// 将状态更改为成功
this.status = RESOLVED;
};
reject = () => {
if (this.status !== PENDING) return;
// 将状态更改为失败
this.status = REJECTED;
};
}
复制代码
then
- 会有成功 、 失败的回调
- 回调会有原因, 因此在改变状态的时候需要保存原因,在回调的时候返回
代码如下
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject);
}
status = PENDING;
value = undefined
reason = undefined
resolve = value => {
if (this.status !== PENDING) return;
this.status = RESOLVED;
// 1 保存成功原因
this.value = value
};
reject = reason => {
if (this.status !== PENDING) return;
this.status = REJECTED;
// 1 保存失败原因
this.reason = reason
};
then(successCallback, failCallback) {
// 2 判断状态
if(this.status === RESOLVED) {
successCallback(this.value)
} else if(this.status === REJECTED){
failCallback(this.reason)
}
}
}
复制代码
异步逻辑
eg: 异步回调。
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("成功");
reject('失败')
}, 20000)
});
promise.then(
(value) => {
console.log("----value", value);
},
(reason) => {
console.log("----reason", reason);
}
);
复制代码
此时按照目前的逻辑,是不会执行 successCallback
或 failCallback
。
改造:
then
中判断是否是等待状态
,如果是,保存 成功和失败 的callback- 在
resolve
、reject
中判断 这个回调是否存在,存在并把对应参数带回去调用。
代码如下
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject);
}
status = PENDING;
value = undefined;
reason = undefined;
// 1 定义两个callback变量
successCallback = undefined;
failCallback = undefined;
resolve = (value) => {
if (this.status !== PENDING) return;
this.status = RESOLVED;
this.value = value;
// 2 如果有callback则调用,并把对应参数带过去
this.successCallback && this.successCallback(this.value)
};
reject = (reason) => {
if (this.status !== PENDING) return;
this.status = REJECTED;
this.reason = reason;
// 2 如果有callback则调用,并把对应参数带过去
this.failCallback && this.failCallback(this.reason)
};
then(successCallback, failCallback) {
if (this.status === RESOLVED) {
successCallback(this.value);
} else if (this.status === REJECTED) {
failCallback(this.reason);
} else {
// 3 如果还是等待状态,保存callback
this.successCallback = successCallback;
this.failCallback = failCallback;
}
}
}
复制代码
then 方法多次调用添加多个处理函数
同一个promise对象下面的then方法是可以被调用多次的。
eg:
let promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve("成功");
reject("失败");
}, 2000);
// resolve("成功");
// reject("失败");
});
promise.then(
(value) => {
console.log("----value", value);
},
(reason) => {
console.log("----reason", reason);
}
);
promise.then((value) => {
console.log(1, value);
});
promise.then((value) => {
console.log(2, value);
});
promise.then((value) => {
console.log(3, value);
});
复制代码
那么在此时,目前的代码只会保存最后一次的 callback
, 因此我们需要
- 将
callback
改造成数组
代码如下
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject);
}
status = PENDING;
value = undefined;
reason = undefined;
// 1 变成数组
successCallback = [];
failCallback = []
resolve = (value) => {
if (this.status !== PENDING) return;
this.status = RESOLVED;
this.value = value;
// 2 while 判断长度,shift 不断推出第一个元素,将this.value传进去
while(this.successCallback.length) this.successCallback.shift()(this.value)
};
reject = (reason) => {
if (this.status !== PENDING) return;
this.status = REJECTED;
this.reason = reason;
// 2 while 判断长度,shift 不断推出第一个元素,将this.value传进去
while(this.failCallback.length) this.failCallback.shift()(this.reason)
};
then(successCallback, failCallback) {
if (this.status === RESOLVED) {
successCallback(this.value);
} else if (this.status === REJECTED) {
failCallback(this.reason);
} else {
// 3 变成push
this.successCallback.push(successCallback);
this.failCallback.push(failCallback);
}
}
}
复制代码
链式调用
then方法是可以被链式调用的, 后面then方法的回调函数拿到值的是上一个then方法的回调函数的返回值
普通值
let promise = new Promise((resolve, reject) => {
resolve("成功");
});
promise.then((value) => {
console.log(1, value);
return 100
}).then(value => {
console.log(value);
})
复制代码
输出结果如下
因此我们需要
-
返回新的 promise
-
successCallback 返回的东西也需要带给下一个 .then
-
以前then 需要立即执行,放哪? -> 放入 new Promise 中,立即执行
代码如下
then(successCallback, failCallback) {
// 定义为一个新的Promise
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === RESOLVED) {
// 将当前successCallback return 的值返回
let x = successCallback(this.value);
resolve(x)
} else if (this.status === REJECTED) {
failCallback(this.reason);
} else {
this.successCallback.push(successCallback);
this.failCallback.push(failCallback);
}
});
// 将新的Promise返回,以完成链式调用
return promise2;
}
复制代码
callback 返回的又是一个Promise
特俗的, 如果返回的又是一个Promise, 那么我们需要判断,Promise的状态是成功 的还是失败的,如果是成功,则调用resolve
, 如果是 失败,则要 reject
。
需要处理逻辑的如下
-
判断 x 的值是普通值还是promise对象
-
如果是普通值 直接调用resolve
-
如果是promise对象 查看promsie对象返回的结果
-
再根据promise对象返回的结果 决定调用resolve 还是调用reject
我们定义一个新方法resolvePromise
(不是类中的方法,定义在类之外),便于统一调用。 传递的参数分别是 callback的值
,resolve
, reject
function resolvePromise (x, resolve, reject) {
//判断 x 的值是否 promise 对象
if (x instanceof MyPromise) {
x.then(resolve, reject);
} else {
// 普通值
resolve(x);
}
}
复制代码
then 中修改如下
then(successCallback, failCallback) {
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === RESOLVED) {
let x = successCallback(this.value);
// 调用resolvePromise
resolvePromise(x, resolve, reject)
} else if (this.status === REJECTED) {
failCallback(this.reason);
} else {
this.successCallback.push(successCallback);
this.failCallback.push(failCallback);
}
});
return promise2;
}
复制代码
特殊循环调用
在特殊情况下,可以让return的promise 为自身,这就会导致循环调用。
eg:
let promise = new Promise((resolve, reject) => {
resolve("成功");
});
let promise2 = promise
.then((value) => {
console.log(1, value);
return promise2;
})
复制代码
结果如下
因此我们需要判断 return 的内容是否为 自身。
修改如下
class MyPromise {
....
then(successCallback, failCallback) {
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === RESOLVED) {
let x = successCallback(this.value);
// 将promise2 自身传进去做判断
resolvePromise(promise2, x, resolve, reject)
} else if (this.status === REJECTED) {
failCallback(this.reason);
} else {
this.successCallback.push(successCallback);
this.failCallback.push(failCallback);
}
});
return promise2;
}
}
function resolvePromise (promise2, x, resolve, reject) {
// 加上判断是否为自身, 如果是reject一个错误。
if(promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if (x instanceof MyPromise) {
x.then(resolve, reject);
} else {
resolve(x);
}
}
复制代码
但这由有一个新的问题,在resolvePromise
传值的时候,promise
是还没有拿到的。 我们需要怎么做呢
- 处理成异步
因此我们只要加个settime即可。
class MyPromise {
。。。
then(successCallback, failCallback) {
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === RESOLVED) {
// 添加setTimeout, 使其异步化
setTimeout(() => {
let x = successCallback(this.value);
resolvePromise(promise2, x, resolve, reject);
}, 0);
} else if (this.status === REJECTED) {
failCallback(this.reason);
} else {
this.successCallback.push(successCallback);
this.failCallback.push(failCallback);
}
});
return promise2;
}
}
复制代码
捕获错误
截至至目前,我们都在处理正常的情况,我们需要添加相应的错误兼容,已保证代码的正常执行。
- 添加try catch
代码如下
class MyPromise {
constructor(executor) {
// 添加try catch
try {
executor(this.resolve, this.reject);
} catch (error) {
// 将错误reject 出去
this.reject(error)
}
}
....
then(successCallback, failCallback) {
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === RESOLVED) {
setTimeout(() => {
// 添加try catch
try {
let x = successCallback(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
}, 0);
} else if (this.status === REJECTED) {
failCallback(this.reason);
} else {
this.successCallback.push(successCallback);
this.failCallback.push(failCallback);
}
});
return promise2;
}
}
复制代码
补充其他状态的处理
目前,我们只是处理的resolve
的状态,我们继续添加reject 状态的代码
class MyPromise {
...
then(successCallback, failCallback) {
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === RESOLVED) {
setTimeout(() => {
try {
let x = successCallback(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
}, 0);
} else if (this.status === REJECTED) {
setTimeout(() => {
// 添加 try catch
try {
let x = failCallback(this.reason)
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
}, 0);
} else {
this.successCallback.push(successCallback);
this.failCallback.push(failCallback);
}
});
return promise2;
}
}
复制代码
异步处理
结合前面成功 和 失败的 处理, 我们还需要对异步的回调函数处理
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject);
} catch (error) {
this.reject(error)
}
}
status = PENDING;
value = undefined;
reason = undefined;
successCallback = [];
failCallback = [];
resolve = (value) => {
if (this.status !== PENDING) return;
this.status = RESOLVED;
this.value = value;
// 不再需要传值
// while (this.successCallback.length) this.successCallback.shift()(this.value);
while (this.successCallback.length) this.successCallback.shift()();
};
reject = (reason) => {
if (this.status !== PENDING) return;
this.status = REJECTED;
this.reason = reason;
// 不再需要传值
// while (this.failCallback.length) this.failCallback.shift()(this.reason);
while (this.failCallback.length) this.failCallback.shift()();
};
then(successCallback, failCallback) {
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === RESOLVED) {
setTimeout(() => {
try {
let x = successCallback(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
}, 0);
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = failCallback(this.reason)
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
}, 0);
} else {
this.successCallback.push(() => {
// 将成功的函数copy一份放在此
setTimeout(() => {
try {
let x = successCallback(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
}, 0);
});
this.failCallback.push(() => {
// 将失败的函数copy一份放在此
setTimeout(() => {
try {
let x = failCallback(this.reason)
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
}, 0);
});
}
});
return promise2;
}
}
复制代码
将 then 方法的参数变成可选参数
我们先来看一段代码
let promise = new Promise((resolve, reject) => {
resolve("成功");
// reject("失败");
});
promise
.then()
.then()
.then((value) => {
console.log(value);
});
复制代码
再 then
中,我们可以选择不传递参数,在最后有参数的地方,拿到一层层传递下来的参数。
实际上,上面的代码 等同于 下面的代码
promise
.then(value => value)
.then(value => value)
.then((value) => {
console.log(value);
});
复制代码
因此
-
判断是否有callback, 有则用,没有则补充
class MyPromise {
…
then(successCallback, failCallback) {
// 添加可选参数
successCallback = successCallback || (value => value);
// 失败的回调需加 throw
failCallback = failCallback || (reason => { throw reason });let promise2 = new MyPromise((resolve, reject) => { ... } return promise2; 复制代码
}
}
静态方法
all
Promise 允许我们将多个promise 执行完后一次性返回, 这就是 all 方法。注意的是,这是个静态方法。以下代码是例子。 特殊的,有一个返回的是 reject
, 则其他都不会返回
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("成功 p1");
}, 2000)
});
let p2 = new Promise((resolve, reject) => {
resolve("成功 p2");
});
let p = Promise.all(['a1', 'a2', p1, p2, 'c1'])
p.then(res => console.log(res))
复制代码
由以上代码可以得知,
all
传递的是个数组- 传递元素可以是非promise实例
实现代码
class MyPromise {
...
// 定义静态方法all
static all(arr) {
// 定义一个数组保存结果
let result = [];
// 保存一个index 和 数组长度判断是否执行
let index = 0;
return new MyPromise((resolve, reject) => {
function addData(key, value) {
// 保存结果值
result[key] = value;
// 每次+1
index++;
// 判断是否执行
if (index === arr.length) {
resolve(result);
}
}
for (let idx = 0; idx < arr.length; idx++) {
const current = arr[idx];
// 判断是否是MyPromise 实例下的
if (current instanceof MyPromise) {
// 将then 中的结果放入 结果数组
current.then(
(value) => addData(idx, value),
(reason) => reject(reason)
);
} else {
// 如果不是直接add进结果数组
addData(idx, current);
}
}
});
}
}
复制代码
resolve
resolve 可以将传进来的参数变成一个promise. 让后续也可以链式调用。 例子如下
function p1() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("成功 p1");
}, 2000);
});
}
Promise.resolve(10).then((res) => console.log(res));
Promise.resolve(p1()).then((res) => console.log(res));
复制代码
log如下
其实很简单。
-
判断是否是
Promise
实例,如果是直接 返回 -
不是
resolve
出去class MyPromise {
…
// 定义静态方法resolve
static resolve (value) {
// 如果是Promise实例,直接返回
if (value instanceof MyPromise) return value;
// 不是则resolve 出去
return new MyPromise(resolve => resolve(value));
}
}
finally
我们知道 finally
, 无论如何都可以调用 。我们先来复习看下例子是如何用的
let p1 = new Promise((resolve, reject) => {
console.log('.....');
resolve("成功 p1");
});
p1.then((res) => console.log(res)).finally(() => {
console.log("----1");
});
p1.finally(() => {
console.log("----2");
}).then((res) => console.log(res))
复制代码
log 如下
我们可以发现
-
finally 可以放在如何位置 按顺序执行
-
finally 放前面 后面接 then 是可以拿到 返回的值
-
需要注意的是,这里有微任务宏任务的概念。 then 后面接 finally 或者 finally 后面接then 都是第二次微任务。
-
需要考虑finally 在前面,返回的value 是异步的情况。
代码如下
class MyPromise {
...
finally(callback) {
// 因为可以链式调用,我们需要返回一个promise, 直接调用.then 方法既可。
return this.then(value => {
// 如果 return 的是个promise 需要等待执行完再return
return MyPromise.resolve(callback()).then(() => value)
}, reason => {
return MyPromise.resolve(callback()).then(() => { throw reason })
})
}
}
复制代码
catch
话不多说,先看例子
let p1 = new Promise((resolve, reject) => {
reject('失败回调')
});
p1.then((res) => console.log(res))
.catch(err => {
console.log(err);
})
复制代码
log 如下;
我们可以发现
-
then
不传递 失败回调时,是可以在 catch 中捕获到的。
其实实现很简单,只需要将callback
放入 then(undefind, callback )
既可
代码实现如下
class MyPromise {
...
catch (failCallback) {
return this.then(undefined, failCallback)
}
}
复制代码
结束
自此,已完成全部逻辑。下面是代码总览
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
constructor (executor) {
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e);
}
}
// promsie 状态
status = PENDING;
// 成功之后的值
value = undefined;
// 失败后的原因
reason = undefined;
// 成功回调
successCallback = [];
// 失败回调
failCallback = [];
resolve = value => {
// 如果状态不是等待 阻止程序向下执行
if (this.status !== PENDING) return;
// 将状态更改为成功
this.status = FULFILLED;
// 保存成功之后的值
this.value = value;
// 判断成功回调是否存在 如果存在 调用
while(this.successCallback.length) this.successCallback.shift()()
}
reject = reason => {
// 如果状态不是等待 阻止程序向下执行
if (this.status !== PENDING) return;
// 将状态更改为失败
this.status = REJECTED;
// 保存失败后的原因
this.reason = reason;
// 判断失败回调是否存在 如果存在 调用
while(this.failCallback.length) this.failCallback.shift()()
}
then (successCallback, failCallback) {
// 添加可选参数
successCallback = successCallback || (value => value);
// 失败的回调需加 throw
failCallback = failCallback || (reason => { throw reason });
let promsie2 = new MyPromise((resolve, reject) => {
// 判断状态
if (this.status === FULFILLED) {
setTimeout(() => {
// 添加容错
try {
let x = successCallback(this.value);
resolvePromise(promsie2, x, resolve, reject)
}catch (e) {
reject(e);
}
}, 0)
}else if (this.status === REJECTED) {
setTimeout(() => {
// 添加容错
try {
let x = failCallback(this.reason);
resolvePromise(promsie2, x, resolve, reject)
}catch (e) {
reject(e);
}
}, 0)
} else {
// 等待
// 将成功回调和失败回调存储起来
this.successCallback.push(() => {
setTimeout(() => {
try {
let x = successCallback(this.value);
resolvePromise(promsie2, x, resolve, reject)
}catch (e) {
reject(e);
}
}, 0)
});
this.failCallback.push(() => {
setTimeout(() => {
try {
let x = failCallback(this.reason);
resolvePromise(promsie2, x, resolve, reject)
}catch (e) {
reject(e);
}
}, 0)
});
}
});
return promsie2;
}
finally(callback) {
// 因为可以链式调用,我们需要返回一个promise, 直接调用.then 方法既可。
return this.then(value => {
// 如果 return 的是个promise 需要等待执行完再return
return MyPromise.resolve(callback()).then(() => value)
}, reason => {
return MyPromise.resolve(callback()).then(() => { throw reason })
})
}
catch (failCallback) {
return this.then(undefined, failCallback)
}
// 定义静态方法all
static all(arr) {
// 定义一个数组保存结果
let result = [];
// 保存一个index 和 数组长度判断是否执行
let index = 0;
return new MyPromise((resolve, reject) => {
function addData(key, value) {
// 保存结果值
result[key] = value;
// 每次+1
index++;
// 判断是否执行
if (index === arr.length) {
resolve(result);
}
}
for (let idx = 0; idx < arr.length; idx++) {
const current = arr[idx];
// 判断是否是MyPromise 实例下的
if (current instanceof MyPromise) {
// 将then 中的结果放入 结果数组
current.then(
(value) => addData(idx, value),
(reason) => reject(reason)
);
} else {
// 如果不是直接add进结果数组
addData(idx, current);
}
}
});
}
// 定义静态方法resolve
static resolve (value) {
// 如果是Promise实例,直接返回
if (value instanceof MyPromise) return value;
// 不是则resolve 出去
return new MyPromise(resolve => resolve(value));
}
}
// 判断 x 的值是普通值还是promise对象
// 如果是普通值 直接调用resolve
// 如果是promise对象 查看promsie对象返回的结果
// 再根据promise对象返回的结果 决定调用resolve 还是调用reject
function resolvePromise (promsie2, x, resolve, reject) {
if (promsie2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if (x instanceof MyPromise) {
// promise 对象
// x.then(value => resolve(value), reason => reject(reason));
x.then(resolve, reject);
} else {
// 普通值
resolve(x);
}
}
复制代码