1 实现自己定义的 Promise 类 并且绑定 this
class Yu {
static PENDING = "pending";
static FUIFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.state = YU.PENDING;
this.value = null;
executor(this.resolve, this.reject);
}
resolve(value) {}
reject(reason) {}
}
let p = new Yu((resolve, reject) => {
resolve(1);
});
console.log(p);
不绑定 this 的时候 会报错, 因为 es6 class 默认开启严格模式,想要不报错就使用 bind 绑定 this 即可
executor(this.resolve.bind(this), this.reject.bind(this));
但是 resolve reject 同步同时调用的情况会后面的把前面的状态覆盖,我们期望的是状态从 pending 变成 rejected 或者 pending 变成 fulfilled 以后就不要再变了。 下面通过状态保护来解决
2 状态保护以及 executor 的异常捕获的处理
状态保护很简单,就是 resolve reject 里面加判断即可 判断当前状态是 pending 再做里面的处理
resolve(value) {
if (this.state === Yu.PENDING) {
this.state = Yu.FUIFILLED;
this.value = value;
}
}
reject(reason) {
if (this.state === Yu.PENDING) {
this.state = Yu.REJECTED;
this.value = reason;
}
}
当我们这样使用的时候 ,有可能有这样的情况
new Yu((resolve, reject) => {
//使用一个错误的变量
console.log(bbb);
//或者主动抛出一个错误
throw 2222;
//
});
我们都需要对 executor 进行错误处理, 内部使用 try catch 处理,再内部修改 catch 里面的状态
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (e) {
this.reject(e);
}
这样就可以了
3 then 的基础 pending fulfilled rejected 的处理
- Promises/A+ 规范写明,必须提供一个then方法, 该 方法接收两个参数,onFulfilled 和onRejected,
then(onFulfilled, onRejected)
,第一个参数是成功的回调,第二个参数是失败的回调 - 两个参数都是可选的 , 意思
.then()
的时候要做then值穿透的处理,其实就是返回当前Promise实例的里面的value - 当onFulfilled是函数的时候, 必须且只能在当前状态是fulfilled的情况才可以调用,之前不行,也不可以调用多次,
- 当onFulfilled是函数的时候,必须且只能在当前状态是rejected的情况才可以调用,之前不行,也不可以调用多次,
- then可以在同一个promise实例上调用多次
- then 必须返回新的Promise实例
promise2 = promise1.then(onFulfilled, onRejected)
then 是原型上的方法 接收两个回调函数作为参数。
then(onFulfilled, onRejected) {
//先让传进来的第一个函数执行 ,并且将实例上的value传递给当前函数
onFulfilled(this.value);
}
调用下看一下效果,当调用 resolve('success') 内部将 succss 保存在实例的 value 属性上并且改变当前的状态为成功状态(fulfilled), 并且在调用 then 的时候,执行传递进来的 onFulfilled 方法的时候,将 this.value 也就是 success 传递给 onFulfilled,这样就可以再调用的时候 ,输出形参 value,也就是实参,success 了。
let p = new Yu((resolve, reject) => {
resolve("success");
}).then(val => {
console.log(val); //success
});
但是当我们注释掉 resolve 的时候 ,不应该有输出, 但是现在还是有输出,所有我们不能上来就在 then 的里面执行这个成功的方法,而是应该在一定的情况下执行,什么情况呢? 就是当前状态为 fulfilled 的请求,同理, 其他两种情况也类似, 代码修改为:
then(onFulfilled, onRejected) {
//1 两个参数的校验 todo
//2 执行两个传进来的函数 什么时候执行 什么时候不执行?
this.state === Yu.FUIFILLED && onFulfilled(this.value);
this.state === Yu.REJECTED && onRejected(this.value);
if (this.state === Yu.PENDING) {
//因为不知道什么时候成功或者失败,所以要暂时将函数保存
}
//3 返回一个新的Promise实例 为什么需要返回新的实例? 因为可以支持链式调用then 就是递归 函数每次调用自己 那我可以直接返回this 下次使用then的时候通过查找原型链上的then方法
//也可以实现链式调用呀? 那为什么不用直接返回this的方法 而是 使用重新new 一个构造函数 得到一个新的实例的方法呢? 因为需要传递上次的状态
//而且返回的不能和上一个实例相同 如果相同应该给一个报错的提示
}
调用的时候 ,注意 then 方法接受两个回调函数作为参数 第一个是成功的函数 第二个是失败的函数。 里面的参数是当前实例上的 value, 如果没传的第一个或者第二个参数的时候,不要报错,这时候就要我们在 then 里面做参数的处理
then(onFulfilled, onRejected) {
//1 两个参数的校验
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : () => {};
onRejected = typeof onRejected === "function" ? onRejected : () => {};
//2 执行两个传进来的函数 是对应的状态的时候 才执行
this.state === Yu.FUIFILLED && onFulfilled(this.value);
this.state === Yu.REJECTED && onRejected(this.value);
if (this.state === Yu.PENDING) {
//因为不知道什么时候成功或者失败,所以要暂时将函数保存
}
}
错误处理的时候, 也要把异常捕获。 所以还要完善一下错误处理的函数 里面自己抛出异常
//1 两个参数的校验
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : () => {};
onRejected =
typeof onRejected === "function"
? onRejected
: err => {
throw err;
};
调用的结果可以是这样
let p = new Yu((resolve, reject) => {
resolve("success");
}).then(
val => {
console.log(val);
}
//不传第二个参数 也不会报错, 因为then内部做了处理
// reason => {
// console.log(reason);
// }
);
也可以是这样调用
let p = new Yu((resolve, reject) => {
reject("失败");
}).then(
//第一个参数不是函数 也不会报错, 因为then内部做了处理
null,
reason => {
console.log(reason);
}
);
还有个问题是 如果 then 里面 onFulfilled 和 onRejected 里面也有错误,也需要在内部做 try catch 的处理
//2 执行两个传进来的函数 是对应的状态的时候 才执行
if (this.state === Yu.FUIFILLED) {
try {
onFulfilled(this.value);
} catch (e) {
onRejected(this.value);
}
}
if (this.state === Yu.REJECTED) {
try {
onRejected(this.value);
} catch (e) {
onRejected(this.value);
}
}
另一个细节是, new Promise 里面的 resovle 是同步执行还是异步执行的? 我们可以看一下,正常的 promsie 的输出顺序
let p2 = new Promise((resolve, reject) => {
console.log(1111);
resolve("成功");
console.log(2222);
}).then(val => console.log(val));
所以我们要把 resolve reject 变成异步的 ,可以用 setTimeout 模拟一下
const fakeMicroTask = (cb, timer = 1000) => setTimeout(cb, timer);
//2 执行两个传进来的函数 是对应的状态的时候 才执行
if (this.state === Yu.FUIFILLED) {
fakeMicroTask(() => {
try {
onFulfilled(this.value);
} catch (e) {
onRejected(this.value);
}
});
}
if (this.state === Yu.REJECTED) {
fakeMicroTask(() => {
try {
onRejected(this.value);
} catch (e) {
onRejected(this.value);
}
});
}
如果 new Promise 里面 异步调用 resolve 或者 reject 的时候, 我们看看正常的 promise 的执行顺序:
let p2 = new Promise((resolve, reject) => {
console.log(1111);
setTimeout(() => {
resolve("成功");
}, 1000);
console.log(2222);
}).then(val => console.log(val));
console.log("first");
//输出顺序
//1111
//2222
//first
//一秒后 输出 成功
所以我们要对异步调用 resolve 的情况做处理, 这时候就是对 pending 状态做处理 ,因为一开始状态就是 pending ,要等一秒后才会改变状态
const fakeMicroTask = (cb, timer = 1000) => setTimeout(cb, timer);
class Yu {
static PENDING = "pending";
static FUIFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.state = Yu.PENDING;
this.value = null;
this.callbacks = [];
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (e) {
this.reject(e);
}
}
resolve(value) {
if (this.state === Yu.PENDING) {
this.state = Yu.FUIFILLED;
this.value = value;
this.callbacks.forEach(cbObj => {
cbObj.onFulfilled(value);
});
}
}
reject(reason) {
if (this.state === Yu.PENDING) {
this.state = Yu.REJECTED;
this.value = reason;
this.callbacks.forEach(cbObj => {
cbObj.onRejected(reason);
});
}
}
then(onFulfilled, onRejected) {
//1 两个参数的校验
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : () => {};
onRejected =
typeof onRejected === "function"
? onRejected
: err => {
throw err;
};
//2 执行两个传进来的函数 是对应的状态的时候 才执行
if (this.state === Yu.FUIFILLED) {
fakeMicroTask(() => {
try {
onFulfilled(this.value);
} catch (e) {
onRejected(this.value);
}
});
}
if (this.state === Yu.REJECTED) {
fakeMicroTask(() => {
try {
onRejected(this.value);
} catch (e) {
onRejected(this.value);
}
});
}
if (this.state === Yu.PENDING) {
//因为不知道什么时候成功或者失败,所以要暂时将函数保存
this.callbacks.push({
onFulfilled,
onRejected
});
}
}
}
pending 状态异常处理
//没有加错误处理的情况
if (this.state === Yu.PENDING) {
//因为不知道什么时候成功或者失败,所以要暂时将函数保存
this.callbacks.push({
onFulfilled,
onRejected
});
}
//对pending 状态加了错误处理的情况
if (this.state === Yu.PENDING) {
//因为不知道什么时候成功或者失败,所以要暂时将函数保存
this.callbacks.push({
onFulfilled: value => {
try {
onFulfilled(value);
} catch (err) {
onRejected(err);
}
},
onRejected: reason => {
try {
onRejected(value);
} catch (err) {
onRejected(err);
}
}
});
}
下面的输出顺序是? :
let p = new Yu((resolve, reject) => {
setTimeout(() => {
resolve("success");
console.log(111);
});
}).then(value => console.log(value), reason => console.log(reason));
console.log("first");
1 first 2 success 3 111
但是 正常 promise 输出的顺序是
1 first 2 111 3 success
所以我们要做一下改造: 改成异步即可
resolve(value) {
if (this.state === Yu.PENDING) {
this.state = Yu.FUIFILLED;
this.value = value;
fakeMicroTask(() => {
this.callbacks.forEach(cbObj => {
cbObj.onFulfilled(value);
});
});
}
}
reject(reason) {
if (this.state === Yu.PENDING) {
this.state = Yu.REJECTED;
this.value = reason;
fakeMicroTask(() => {
this.callbacks.forEach(cbObj => {
cbObj.onRejected(reason);
});
});
}
}
4 then 支持链式调用
先调用 一下
let p = new Yu((resolve, reject) => {
setTimeout(() => {
resolve("success");
console.log(111);
});
console.log(2222);
})
.then(value => console.log(value), reason => console.log(reason))
.then(val => console.log(val));
Uncaught TypeError: Cannot read property 'then' of undefined
-
链式调用 所以要返回一个新的 promise
-
new promise 里面 reject 不会影响 then 里面的状态?
实现链式调用:
then(onFulfilled, onRejected) {
//1 两个参数的校验
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : () => {};
onRejected =
typeof onRejected === "function"
? onRejected
: err => {
throw err;
};
//3 返回一个新的Promise实例
let newThen = new Yu((resolve, reject) => {
//2 执行两个传进来的函数 是对应的状态的时候 才执行
if (this.state === Yu.FUIFILLED) {
fakeMicroTask(() => {
try {
onFulfilled(this.value);
} catch (e) {
onRejected(this.value);
}
});
}
if (this.state === Yu.REJECTED) {
fakeMicroTask(() => {
try {
onRejected(this.value);
} catch (e) {
onRejected(this.value);
}
});
}
if (this.state === Yu.PENDING) {
//因为不知道什么时候成功或者失败,所以要暂时将函数保存
this.callbacks.push({
onFulfilled: value => {
try {
onFulfilled(value);
} catch (err) {
onRejected(err);
}
},
onRejected: reason => {
try {
onRejected(value);
} catch (err) {
onRejected(err);
}
}
});
}
});
return newThen;
}
then 值穿透的问题 的处理
参数校验的时候 直接返回this.value 就行
//1 两个参数的校验
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : () => this.value;
onRejected =
typeof onRejected === "function" ? onRejected : () => this.value;
then 新增promise 异常处理
then(onFulfilled, onRejected) {
//1 两个参数的校验
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : () => this.value;
onRejected =
typeof onRejected === "function" ? onRejected : () => this.value;
// onRejected =
// typeof onRejected === "function"
// ? onRejected
// : err => {
// throw err;
// };
//3.1 新建一个新的实例
let newPromiseInstance = new Yu((resolve, reject) => {
//2 执行两个传进来的函数 是对应的状态的时候 才执行
if (this.state === Yu.FUIFILLED) {
fakeMicroTask(() => {
try {
let result = onFulfilled(this.value);
resolve(result);
} catch (e) {
reject(e);
}
});
}
if (this.state === Yu.REJECTED) {
fakeMicroTask(() => {
try {
let result = onRejected(this.value);
//这里也是要resolve 只是处理上次then onRejected 里面返回的值
resolve(result);
} catch (e) {
reject(e);
}
});
}
if (this.state === Yu.PENDING) {
//因为不知道什么时候成功或者失败,所以要暂时将函数保存
this.callbacks.push({
onFulfilled: value => {
try {
let result = onFulfilled(value);
resolve(result);
} catch (err) {
reject(err);
}
},
onRejected: reason => {
try {
let result = onRejected(reason);
resolve(result);
} catch (err) {
reject(err);
}
}
});
}
});
//3.2 返回一个新的promise实例
return newPromiseInstance;
}
调用看一下处理完的效果 主要就是在then里面三个状态里面加try catch 并且catch里面的错误手动调用reject函数,并且将错误传递进去
判断 then 里面返回值是普通值 还是一个新的 Promise?
- 该对象的状态和结果由回调函数的返回值决定
- 如果返回值是Promise对象:
- 返回值成功, 新Promise就是成功
- 返回值失败, 新Primise就是失败
- 如果返回值不是Promise对象
- 新Promsie就是成功,它的值就是返回值
onFulfilled 返回的是普通值,直接resolve, 返回的是promise 的实例let result = onFulfilled(this.value))
这种if (result instanceof Yu)
是promise 的实例,就调用result.then(resolve, reject)并且传入外层then的 resolve, reject方法
翻译成代码就是下面的意思:
//成功里面
if (result instanceof Yu) {
// result.then(
// value => {
// resolve(value);
// },
// reason => {
// //处理拒绝里面的返回
// reject(reason);
// }
// );
// 等价于;
result.then(resolve, reject);
} else {
//返回普通值的话 直接改变状态
resolve(result);
}
//失败里也要改
//pending里面也要改
现在的 then 方法
then(onFulfilled, onRejected) {
//1 两个参数的校验
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : () => this.value;
onRejected =
typeof onRejected === "function" ? onRejected : () => this.value;
// onRejected =
// typeof onRejected === "function"
// ? onRejected
// : err => {
// throw err;
// };
//3.1 新建一个新的实例
let newThen = new Yu((resolve, reject) => {
//2 执行两个传进来的函数 是对应的状态的时候 才执行
if (this.state === Yu.FUIFILLED) {
fakeMicroTask(() => {
try {
let result = onFulfilled(this.value);
if (result instanceof Yu) {
// result.then(
// value => {
// resolve(value);
// },
// reason => {
// //处理拒绝里面的返回
// reject(reason);
// }
// );
// 等价于;
result.then(resolve, reject);
} else {
//返回普通值的话 直接改变状态
resolve(result);
}
} catch (e) {
onRejected(this.value);
}
});
}
if (this.state === Yu.REJECTED) {
fakeMicroTask(() => {
try {
let result = onRejected(this.value);
if (result instanceof Yu) {
result.then(resolve, reject);
} else {
//返回普通值的话 直接改变状态
resolve(result);
}
} catch (e) {
onRejected(this.value);
}
});
}
if (this.state === Yu.PENDING) {
//因为不知道什么时候成功或者失败,所以要暂时将函数保存
this.callbacks.push({
onFulfilled: value => {
try {
let result = onFulfilled(value);
if (result instanceof Yu) {
result.then(resolve, reject);
} else {
//返回普通值的话 直接改变状态
resolve(result);
}
} catch (err) {
onRejected(err);
}
},
onRejected: reason => {
try {
let result = onRejected(value);
if (result instanceof Yu) {
result.then(resolve, reject);
} else {
//返回普通值的话 直接改变状态
resolve(result);
}
} catch (err) {
onRejected(err);
}
}
});
}
});
//3.2 返回一个新的promise实例
return newThen;
}
上面很多都是重复的,可以把相同部分取出来, 代码重构
parse(result, resolve, reject) {
try {
//去掉这一行 因为成功和失败调用的不一样 在外部传进来
// let result = onFulfilled(this.value);
if (result instanceof Yu) {
result.then(resolve, reject);
} else {
//返回普通值的话 直接改变状态
resolve(result);
}
} catch (e) {
onRejected(this.value);
}
}
现在整体看起来是这样 调用parse:
const fakeMicroTask = (cb, timer = 1000) => setTimeout(cb, timer);
class Yu {
static PENDING = "pending";
static FUIFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.state = Yu.PENDING;
this.value = null;
this.callbacks = [];
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (e) {
this.reject(e);
}
}
resolve(value) {
if (this.state === Yu.PENDING) {
this.state = Yu.FUIFILLED;
this.value = value;
fakeMicroTask(() => {
this.callbacks.forEach(cbObj => {
cbObj.onFulfilled(value);
});
});
}
}
reject(reason) {
if (this.state === Yu.PENDING) {
this.state = Yu.REJECTED;
this.value = reason;
fakeMicroTask(() => {
this.callbacks.forEach(cbObj => {
cbObj.onRejected(reason);
});
});
}
}
parse(result, resolve, reject) {
try {
//去掉这一行 因为成功和失败调用的不一样 在外部传进来
// let result = onFulfilled(this.value);
if (result instanceof Yu) {
result.then(resolve, reject);
} else {
//返回普通值的话 直接改变状态
resolve(result);
}
} catch (e) {
onRejected(this.value);
}
}
then(onFulfilled, onRejected) {
//1 两个参数的校验
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : () => this.value;
onRejected =
typeof onRejected === "function" ? onRejected : () => this.value;
//3.1 新建一个新的实例
let newPromiseInstance = new Yu((resolve, reject) => {
//2 执行两个传进来的函数 是对应的状态的时候 才执行
if (this.state === Yu.FUIFILLED) {
fakeMicroTask(() => {
this.parse(onFulfilled(this.value), resolve, reject);
});
}
if (this.state === Yu.REJECTED) {
fakeMicroTask(() => {
this.parse(onRejected(this.value), resolve, reject);
});
}
if (this.state === Yu.PENDING) {
//因为不知道什么时候成功或者失败,所以要暂时将函数保存
this.callbacks.push({
onFulfilled: value => {
this.parse(onFulfilled(value), resolve, reject);
},
onRejected: reason => {
this.parse(onRejected(reason), resolve, reject);
}
});
}
});
//3.2 返回一个新的promise实例
return newPromiseInstance;
}
let p = new Yu((resolve, reject) => {
resolve("success");
})
.then(
value => {
console.log("first then " + value);
return "alex from firs then ";
},
reason => console.log(reason)
)
.then(val => console.log("second " + val));
测试then中的链式操作以及then里面返回普通值的情况
- 情况1 resolve一个“解决”,第一个then里面成功的回调里面返回普通值,第二个then里面成功的回调打印第一个then里面返回的值
- 情况2 reject一个值, 第一个then里面失败的回调里面返回普通值,在第二个then里面成功的回调里面打印第一个then里面失败的回调里面返回普通值
- 情况3 测试pending状态,就是调用resolve的时候加异步,第一个then成功回调里面返回普通值,第二个then成功回调里面输出上一个then成功回调里面返回的值
- 情况4 测试pending状态,就是调用reject的时候加异步,第一个then失败回调函数里面返回普通值, 第二个then成功回调里面输出上一个then失败回调函数里面返回的值
then 返回promise的处理
上面处理的都是then返回基本值的情况, 如果返回一个pormise的话, 我们现在的版本是不对的, 要做一下处理, 就是在then里面原来三个状态判断的地方从直接resolve改成先判断上一个的结果是不是promise的实例 是的话用结果的then方法再次传递进去resolve reject ,不是的话,直接用resolve result 看代码: 先看then里面 fulfilled的状态的情况。
简化里面的代码
就变成下面这种写法了
再改造一下 then里面 rejected 和pending的情况的 对then里面返回Promise的处理
rejected 改造前:
rejected改造后:
pending的情况的改造前,要对两种情况分别处理:
pending 的情况改造后:
现在then方法:
then(onFulfilled, onRejected) {
//1 两个参数的校验
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : () => this.value;
onRejected =
typeof onRejected === "function" ? onRejected : () => this.value;
//3.1 新建一个新的实例
let newPromiseInstance = new Yu((resolve, reject) => {
//2 执行两个传进来的函数 是对应的状态的时候 才执行
//成功的判断以及处理
if (this.state === Yu.FUIFILLED) {
//放在异步队列
fakeMicroTask(() => {
//增加错误处理
try {
//对then onFulfilled 返回值是普通值还是新的Promise的处理
//取到返回值
let result = onFulfilled(this.value);
//返回值是 Promise的实例的情况
if (result instanceof Yu) {
result.then(resolve, reject);
} else {
//返回值不是 Promise的实例的情况
resolve(result);
}
} catch (e) {
//对then里面onFulfilled 或者onRejected 函数里面抛出异常或者直接使用未声明的变量的容错处理,会在下一个then的onRejected里面接收到
reject(e);
}
});
}
//失败的判断以及处理
if (this.state === Yu.REJECTED) {
fakeMicroTask(() => {
try {
//对then onRejected 返回值是普通值还是新的Promise的处理
let result = onRejected(this.value);
if (result instanceof Yu) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (e) {
reject(e);
}
});
}
if (this.state === Yu.PENDING) {
//因为不知道什么时候成功或者失败,所以要暂时将函数保存
this.callbacks.push({
onFulfilled: value => {
try {
//对then pending的 onFulfilled 返回值是普通值还是新的Promise的处理
let result = onFulfilled(this.value);
if (result instanceof Yu) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (e) {
reject(e);
}
},
onRejected: reason => {
try {
//对then pending的 onRejected 返回值是普通值还是新的Promise的处理
let result = onRejected(this.value);
if (result instanceof Yu) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (e) {
reject(e);
}
}
});
}
});
//3.2 返回一个新的promise实例
return newPromiseInstance;
}
then 方法的小重构
上面三个状态里面的try catch 里面相似内容过多,我们可以封装一个小的函数统一处理:
parse(result, resolve, reject) {
try {
//去掉这一行 因为成功和失败调用的不一样 在外部传进来
// let result = onFulfilled(this.value);
if (result instanceof Yu) {
//then 里面成功或者失败的 回调函数里面返回一个promise的实例的时候 调用then传入外层的resolve reject继续处理
result.then(resolve, reject);
} else {
//返回普通值的话 直接改变状态
resolve(result);
}
} catch (e) {
reject(this.value);
}
}
去掉注释:
parse(result, resolve, reject) {
try {
if (result instanceof Yu) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (e) {
reject(this.value);
}
}
接下来对重复部分替换,成parse函数
对then里面返回一个promise的 并且是resolve的状态的改造后的测试
测试对then里面返回一个promise的情况, 并且故意写错的情况
如果将故意写错的一行,放在resovle 后面会输出什么? 原生的Primise的处理是这样的
结果是:不会处理, 放前面会处理
我们实现的Yu也是这样:
同理使用parse函数和继续改造then里面pending 和onRejected的状态里面的重复。
改造后的rejected:
测试rejected里面改造后的正确情况, 这时候 第一个then里面要在第二个参数 也就是onRejected回调函数里返回新的promise
改造前的pending的状态:
改造后的:
测试pending resolve 的情况
测试pending reject的情况
改造完pending后的整体的then方法:
对比之前的then方法,代码减少了很多,也更易读
原生的Promise没有对异步调用resolve 里面出现错误做处理,我们这里先不考虑这个情况了。
Promise 返回类型的约束
原生Promise的表现:
说明then里面的方法是异步执行的 既然是异步的就可以拿到then返回的新的primise 实例p
我们自己的实现里面没有做处理, 输出的结果是这样的:
可以统一在parse函数里面做处理:
parse(newReturnedPromiseInstance, result, resolve, reject) {
//If promise and x refer to the same object, reject promise with a TypeError as the reason.
if (newReturnedPromiseInstance === result) {
throw new TypeError("Chaining cycle detected for promise");
}
try {
if (result instanceof Yu) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (e) {
reject(this.value);
}
}
然后在then里面调用parse的地方做修改:
测试一下 ,发现可以了
5 实现Promise.resolve
原生Promise 的resolve reject 传入一个基本值的情况
我们的实现:
static resolve(value) {
return new Yu((resolve, reject) => {
resolve(value);
});
}
也要考虑传入的是一个promise对象的情况 所以代码改为:
static resolve(value) {
return new Yu((resolve, reject) => {
if (value instanceof Yu) {
value.then(resolve, reject);
} else {
resolve(value);
}
});
}
测试Yu.resolve
6 实现Promise.reject
同理 Yu.reject
static reject(reason) {
return new Yu((resolve, reject) => {
if (reason instanceof Yu) {
reason.then(resolve, reject);
} else {
reject(reason);
}
});
}
测试Yu.reject
7 实现Promise.all
所有的成功 才成功 ,所以需要一个数组计数 看结果数组和传入的primises数组是否相同,是的话所有的结果数组作为参数 传入到resolve里面
代码实现
static all(promisesArr) {
let values = [];
return new Yu((resolve, reject) => {
promisesArr.forEach(promise => {
promise.then(
val => {
values.push(val);
//相等的时候 才做resolve的处理
if (values.length == promisesArr.length) {
resolve(values);
}
},
reason => {
reject(reason);
}
);
});
});
}
测试有一个失败的情况
测试都成功的情况
8 实现Promise.race
static race(promsisesArr) {
return new Yu((resolve, reject) => {
promsisesArr.map(promise => {
promise.then(
value => {
resolve(value);
},
reason => {
reject(reason);
}
);
});
});
}
9 测试todo 后面补上
10 总结:
- Yu 是一个构造函数,
- 上面有state存当前状态,默认是pending, 还可以是fulfilled rejected
- 还有一个 this.value 保存外部传递进来的值
- 接收一个回调函数 executor 需要做错误处理,这个回调函数里面接收两个参数 是resolve, reject 要注意this绑定的问题,
- executor在构造函数里面调用,是同步的
- 构造函数上面还有一个callbacks函数,用来存onFulfilled 和onRejected函数,方便后面resolve 或者reject 函数调用
- promise状态改变一开始需要手动调用resolve或者reject 分同步和异步两种情况
- Yu 的原型上面有resovle reject then 方法
- resolve 方法里面做的事情是有三件事情:
- 当前状态是pending的时候,将传入进来的value保存在 this.value上
- 当前状态是pending的时候,修改当前状态为fulfilled
- 如果当前实例上面callbacks里面有值的话, 就循环它,取出里面的onFulfilled的函数,执行它,并且将resolve的参数传递给他
- reject 方法里面做的事有三件事:
- 当前状态是pending的时候,将传入进来的reason保存在 this.value上
- 当前状态是pending的时候,修改当前状态为rejected
- 如果当前实例上面callbacks里面有值的话, 就循环它,取出里面的onRejected的函数,执行它,并且将resolve的参数传递给他
- then 方法
-
返回一个新的Promise实例,通过原型链就可以继续使用原型链上面的方法
-
then的两个参数要做处理
- 处理错误
- 处理参数不是函数的情况
- 处理第二个参数抛出异常的情况
-
then里面有三种状态需要分别处理 3.1 pending状态,pending状态的回调函数的执行还是在resolve 和reject函数里面。同过循环callbacks执行
- 3.1.1 onFulfilled 不确定当前状态,所以要保存到之前callbacks上面, 取到 onFulfilled的返回值,try catch 处理 并且判断返回值是不是Promise的实例,是的话,调用结果的then方法,传入resolve ,reject ,否则直接resolve(返回值) - 3.1.2 onRejected 不确定当前状态,所以要保存到之前callbacks上面,取到 onRejected的返回值,try catch 处理 并且判断返回值是不是Promise的实例,是的话,调用结果的then方法,传入resolve ,reject ,否则直接resolve(返回值)
3.2 fulfilled的状态
- 放在异步里面,调用resolve
3.3 rejected的状态
- 放在异步里面, 调用reject
-
then里面返回的新的promise不能在下一个then里面是一个的处理,要在异步里面才可以取到上一个实例
-
三种状态的错误处理
-
重复代码的过抽离
-
- resolve 方法里面做的事情是有三件事情:
- Yu构造函数上面有all race resolve reject 方法
- all : 有一个失败就失败,多个都成功才成功, 多个成功是内部维护一个数组。每个promise.then里面 传入成功的value 到数组内, 最后判断两个数组长度是否相等, 相等的话代表成功,返回有所有异步成功值的数组
- race : 有一个失败就是失败,有一个成功就改变状态为成功。
- resolve:
- 传入的参数是基本值的情况
- 传入的参数是一个promise实例的情况
- resolve:
- 传入的参数是基本值的情况
- 传入的参数是一个promise实例的情况
- 实现的过程中 还会有一些细节不完善,比如这里没有实现一些更加细节的边界处理,欢迎指正,
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<script>
const fakeMicroTask = (cb, timer = 1000) => setTimeout(cb, timer);
class Yu {
static PENDING = "pending";
static FUIFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.state = Yu.PENDING;
this.value = null;
this.callbacks = [];
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (e) {
this.reject(e);
}
}
resolve(value) {
if (this.state === Yu.PENDING) {
this.state = Yu.FUIFILLED;
this.value = value;
fakeMicroTask(() => {
this.callbacks.forEach(cbObj => {
cbObj.onFulfilled(value);
});
});
}
}
reject(reason) {
if (this.state === Yu.PENDING) {
this.state = Yu.REJECTED;
this.value = reason;
fakeMicroTask(() => {
this.callbacks.forEach(cbObj => {
cbObj.onRejected(reason);
});
});
}
}
parse(newReturnedPromiseInstance, result, resolve, reject) {
//If promise and x refer to the same object, reject promise with a TypeError as the reason.
if (newReturnedPromiseInstance === result) {
throw new TypeError("Chaining cycle detected for promise");
}
try {
if (result instanceof Yu) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (e) {
reject(this.value);
}
}
then(onFulfilled, onRejected) {
//1 两个参数的校验
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : () => this.value;
onRejected =
typeof onRejected === "function" ? onRejected : () => this.value;
//3.1 新建一个新的实例
let newPromiseInstance = new Yu((resolve, reject) => {
//2 执行两个传进来的函数 是对应的状态的时候 才执行
if (this.state === Yu.FUIFILLED) {
fakeMicroTask(() => {
this.parse(
newPromiseInstance,
onFulfilled(this.value),
resolve,
reject
);
});
}
if (this.state === Yu.REJECTED) {
fakeMicroTask(() => {
this.parse(
newPromiseInstance,
onRejected(this.value),
resolve,
reject
);
});
}
if (this.state === Yu.PENDING) {
//因为不知道什么时候成功或者失败,所以要暂时将函数保存
this.callbacks.push({
onFulfilled: value => {
this.parse(
newPromiseInstance,
onFulfilled(this.value),
resolve,
reject
);
},
onRejected: reason => {
this.parse(
newPromiseInstance,
onRejected(this.value),
resolve,
reject
);
}
});
}
});
//3.2 返回一个新的promise实例
return newPromiseInstance;
}
static resolve(value) {
return new Yu((resolve, reject) => {
if (value instanceof Yu) {
value.then(resolve, reject);
} else {
resolve(value);
}
});
}
static reject(reason) {
return new Yu((resolve, reject) => {
if (reason instanceof Yu) {
reason.then(resolve, reject);
} else {
reject(reason);
}
});
}
static all(promisesArr) {
let values = [];
return new Yu((resolve, reject) => {
promisesArr.forEach(promise => {
promise.then(
val => {
values.push(val);
//相等的时候 才做resolve的处理
if (values.length == promisesArr.length) {
resolve(values);
}
},
reason => {
reject(reason);
}
);
});
});
}
static race(promsisesArr) {
return new Yu((resolve, reject) => {
promsisesArr.map(promise => {
promise.then(
value => {
resolve(value);
},
reason => {
reject(reason);
}
);
});
});
}
}
//测试Yu.all
let p1 = new Yu(resolve => {
resolve(1);
});
let p2 = new Yu((resolve, reject) => {
reject("拒绝");
});
Yu.all([p1, p2]).then(
arrs => {
console.log(arrs);
},
err => {
console.log(err);
}
);
// //测试Yu.resolve传入基本值的情况
// Yu.resolve("test").then(val => {
// console.log(val);
// });
// //测试Yu.resolve传入promsie的情况
// let p = new Yu((resolve, reject) => {
// resolve("yu 成功");
// });
// Yu.resolve(p).then(val => {
// console.log(val);
// });
// console.log(
// Yu.reject("reject Yu ").then(null, reason => {
// console.log(reason);
// })
// );
//测试Yu.reject传入基本值的情况
// Yu.reject("test").then(null, val => {
// console.log(val);
// });
// //测试Yu.reject传入promsie的情况
// let p = new Yu((resolve, reject) => {
// reject("yu 拒绝");
// });
// Yu.reject(p).then(null, err => {
// console.log(err);
// });
//test diy Promsie
// let p = new Yu((resolve, reject) => {
// setTimeout(() => {
// reject("拒绝");
// }, 1000);
// })
// .then(
// value => {
// console.log(value);
// return new Yu((resolve, reject) => {
// resolve("Yu first then resolve");
// });
// },
// reason => {
// console.log(reason);
// return new Yu((resolve, reject) => {
// console.log(aaaa);
// resolve("Yu first then reject");
// });
// }
// )
// .then(
// val => console.log(val),
// reason => {
// console.log("second then rejected function " + reason);
// }
// );
//test chain promise
// let p1 = new Yu(resolve => {
// resolve(222);
// });
// let p2 = p1.then(val => {
// return p2;
// });
// let p = new Promise((resolve, reject) => {
// resolve("111");
// });
// let p2 = p.then(val => {
// return p2;
// });
// console.log(p2);
//test promise
// let p2 = new Promise((resolve, reject) => {
// setTimeout(() => {
// console.log(AAA);
// resolve("success");
// }, 1000);
// })
// .then(
// val => {
// console.log(val);
// return new Promise((resolve, reject) => {
// resolve("first then resolve");
// });
// },
// reason => {}
// )
// .then(
// val => {
// console.log(val);
// },
// reason => {
// console.log(reason);
// }
// );
//test Promsie.resolve Promise.reject
// let p1 = new Promise(resolve => {
// resolve("成功");
// });
// Promise.resolve(p1).then(val => {
// console.log(val);
// });
// let p2 = new Promise((resolve, reject) => {
// reject("拒绝");
// });
// Promise.reject(p2).then(
// val => {
// console.log(val);
// },
// reason => {
// console.log(reason);
// }
// );
// test Promise.all
// let p11 = new Promise(resolve => {
// resolve(111);
// });
// let p22 = new Promise((resolve, reject) => {
// // reject(2);
// resolve(222);
// });
// Promise.all([p11, p22]).then(
// arrs => {
// console.log(arrs);
// },
// err => {
// console.log(err);
// }
// );
</script>
</body>
</html>
致谢
- 能看到这里,说明是真的认真读了,感谢!
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!