回顾用法
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);
}
}
状态更改
状态只允许更改一次。,要做非等待状态的判断
修改对应的状态 ```javascript 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; }; }
<a name="IQyoh"></a>
### then
- 会有成功 、 失败的回调
- 回调会有原因, 因此在改变状态的时候需要保存原因,在回调的时候返回
```javascript
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: ```javascript 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` 改造成数组
```javascript
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 方法的参数变成可选参数
我们先来看一段代码 ```javascript let promise = new Promise((resolve, reject) => { resolve(“成功”); // reject(“失败”); });
promise .then() .then() .then((value) => { console.log(value); });
再 `then` 中,我们可以选择不传递参数,在最后有参数的地方,拿到一层层传递下来的参数。<br />实际上,上面的代码 等同于 下面的代码
```javascript
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
, 则其他都不会返回 ```javascript 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实例
实现代码
```javascript
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);
}
}