问题一: 如何做到状态变化后执行后续的then中的代码的?
promise构造函数中传入异步代码块:
new promise((res) =>{resolve(res)}).then(value => {console.info(value)})
new Promise()本身是同步的,后面跟的then也是同步的。但是new promise传入的箭头函数中的代码可能是异步的,这就是说有可能then已经执行了,但是new promise中传入的箭头函数没有执行完成,有没有发现,这有点违反我们的直觉, 然而事实却是这样的:首先根据事件循环原理(eventloop)同步执行的代码肯定优先一步到底执行完毕,异步代码稍后执行,所以then并不会等待前面new Promise构造函数中传入的异步箭头函数,then中传入的函数会根据当前Promise的状态【包含三种:pending(进行中)、fulfilled(已成功)和rejected(已失败)】来分别执行不同的操作,首先如果是pending状态的话,then中的函数会直接放入到预备数组中进行缓存(不会执行),当new promise中传入的异步函数执行完成后并调用了resolve()或者reject()方法之后
Promise的状态随之改为了fulfilled或者rejected,与此同时,之前存入对应的预备数组中的函数会被取出进行执行。补充一点,then中可传入两个函数,分别为resolve调用之后对应的回调函数和reject调用之后对应的回调。如果当前的Promise的状态为pending,then中的resolve回调函数和reject回调分别放入两个预备数组中,后面会根据promise构造函数中传入的异步代码块包含resolve方法或者是reject方法来判断是取哪个预备数组中的函数来执行。
Promise构造函数中如果resolve()存在于同步代码块中,那么Promise的状态在执行then之前就会是fulfilled
promise的class类
// promise 原理代码
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
// 接收执行器:也就是说在new MyPromise((resolve, reject)=>{resolve("成功")})的时候,传匿名函数
// executor会马上进行同步执行,而匿名函数中又传入了resolve,并且在匿名函数中进行了传参执行
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e);
}
}
status = PENDING; // promise的状态
value = undefined; // 成功之后的值
reason = undefined; // 失败之后的值
successCallback = []; // 成功回调
failCallback = []; // 失败回调
// resolve和reject为什么要用箭头函数?
// 如果直接调用的话,普通函数this指向的是window或者undefined
// 用箭头函数就可以让this指向当前实例对象
resolve = value => {
// 如果状态不是等待 组织程序向下执行
if (this.status !== PENDING) return
// 将状态更改为成功
this.status = FULFILLED;
// 保存成功之后的值
this.value = value;
// 判断成功回调是否存在 如果存在 调用
//this.successCallback && this.successCallback(this.value)
while (this.successCallback.length) this.successCallback.shift()()
}
reject = reason => {
// 如果状态不是等待 组织程序向下执行
if (this.status !== PENDING) return
// 将状态更改为失败
this.status = REJECTED;
// 保存失败后的原因
this.reason = reason;
// 判断失败回调是否存在 如果存在 调用
// this.failCallback && this.failCallback(this.reason)
while (this.failCallback.length) this.failCallback.shift()();
}
then (successCallback, failCallback) {
successCallback = successCallback ? successCallback : value => value;
failCallback = failCallback ? failCallback : reason => {
throw reason
};
// then链式调用参数变为可选参数 例:promise.then().then().then((value)=>{console.log(value)}) // value;
//这里new MyPromise传入的匿名function是会执行的,构造函数里面会将传入的function直接执行了
let promise2 = new MyPromise((resolve, reject) => {
// 传递一个执行器 立马执行
// 判断状态
if (this.status === FULFILLED) {
setTimeout(() => { // 将下面的代码变成异步代码
try {
let x = successCallback(this.value)
// 判断 x 的值是普通值还是promise对象
// 如果是普通值 直接调用resolve
// 如果是promise对象 查看promise对象返回的结果
// 再根据promise对象返回的结果 界定调用resolve 还是reject
resolvePromise(x, resolve, reject);
} catch (e) { // 处理异常状态
reject(e)
}
}, 0)
} else if (this.status === REJECTED) {
setTimeout(() => { // 将下面的代码变成异步代码
try {
let x = failCallback(this.reason)
resolvePromise(x, resolve, reject);
} catch (e) { // 处理异常状态
reject(e)
}
}, 0)
} else {
// 当前状态是等待
// 将成功回调和失败回调存储起来 - 多个then方法调用
this.successCallback.push(() => {
setTimeout(() => { // 将下面的代码变成异步代码
try {
let x = successCallback(this.value);
resolvePromise(x, resolve, reject);
} catch (e) { // 处理异常状态
reject(e)
}
}, 0)
});
this.failCallback.push(() => {
setTimeout(() => { // 将下面的代码变成异步代码
try {
let x = failCallback(this.reason);
resolvePromise(x, resolve, reject);
} catch (e) { // 处理异常状态
reject(e)
}
}, 0)
});
}
});
return promise2;
}
finally (callback) {
/**
- 无论当前最终状态是成功还是失败,finally都会执行
- 我们可以在finally方法之后调用then方法拿到结果
- 这个函数是在原型对象上用的
* **/
return this.then(value => {
return MyPromise.resolve(callback()).then(() => value)
}, reason => {
return MyPromise.resolve(callback()).then(() => {
throw reason
})
})
}
catch (failCallback) {
/**
- catch方法是为了捕获promise对象的所有错误回调的
- 直接调用then方法,然后成功的地方传递undefined,错误的地方传递reason
- catch方法是作用在原型对象上的方法
* **/
return this.then(undefined, failCallback);
}
static all (array) {
/**
* 分析一下:
- all方法接收一个数组,数组中可以是普通值也可以是promise对象
- 数组中值得顺序一定是我们得到的结果的顺序
- promise返回值也是一个promise对象,可以调用then方法
- 如果数组中所有值是成功的,那么then里面就是成功回调,如果有一个值是失败的,那么then里面就是失败的
- 使用all方法是用类直接调用,那么all一定是一个静态方法
**/
let result = [];
let index = 0;
return new MyPromise((resolve, reject) => {
function addData (key, value) {
// 保存每个传入参数执行完毕,并存储返回值
result[key] = value;
index++;
if (index === array.length) {
resolve(result)
}
}
for (let i = 0; i < array.length; i++) {
let current = array[i];
if (current instanceof MyPromise) {
// promise对象
current.then(value => addData(i, value), reason => reject(reason))
} else {
// 普通值
addData(i, array[i])
}
}
})
}
static resolve (value) {
/**
resolve方法的作用是将给定的值转换为promise对象 resolve的返回值的promise对象
如果参数就是一个promise对象,直接返回,如果是一个值,那么需要生成一个promise对象,把值进行返回
是Promise类的一个静态方法
* **/
if (value instanceof MyPromise) return value;
return new MyPromise(resolve => resolve(value))
}
}
function resolvePromise (x, resolve, reject) {
if (x instanceof MyPromise) {
// promise 对象
// x.then( value => resolve(value),reason => reject(reason))
x.then(resolve, reject) // 简化
} else {
// 普通值
resolve(x)
}
}
module.exports = MyPromise;
测试类:
import {MyPromise} from "./MyPromise"
// new的时候传入的箭头函数会直接同步执行
let promise = new MyPromise((resolve,reject)=>{
// setTimeout(()=>{ // 异步操作
// resolve('成功')
// },2000)
resolve('成功')
})
let p1 = promise.then(value =>{
console.log(value)
return p1
})
// 测试 then方法可以多次调用
// then 方法的链式调用 1.实现链式调用 2.将一个返回值作为第二个then的参数
promise.then(value => {
console.log(value);
return p1
},reason => {
console.log(reason)
}).then(value => {
console.log(value)
})
// 打印结果-> 成功 成功