1.核心实现
let promise = new Promise((resolve,reject) => {
resolve('ok');
reject('err')
})
promise.then(
(value) => {
console.log(value);},
(err) => {
console.log(err);}
)
根据Promise的使用方法得到一些信息:
①Promise就是一个类 在执行这个类的时候 需要传递一个回调函数进去 称之为执行器,执行器会立即执行
② 有三种状态 fulfilled rejected pending
pending -->fulfilled
pending -->rejected
一旦确定就不可以更改了
③resolve和reject函数是用来更改状态的
resolve:fulfilled
reject:rejected
④then方法内部做的事情就是判断状态,成功就调用成功的回调函数,失败就调用失败的回调函数
⑤ then方法中成功回调函数有一个参数表示成功之后的值,then失败函数的参数表示失败的原因
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MyPromise {
constructor(executor){
executor(this.resolve,this.reject)
}
status = PENDING;//定义初始状态为pending
value = undefined;//定义成功的值 初始为undefined
reason = undefined;//定义失败的原因 初始为undefined
resolve =value => {
//定义为箭头函数是为了在使用的时候this指向这个类的实例对象 MyPromise
//如果状态不是pending就阻止向下执行
if(this.status !== PENDING) return
// 更改状态
this.status = FULFILLED;
//保存成功的值
this.value = value
}
reject = reason => {
//如果状态不是pending就阻止向下执行
if(this.status !== PENDING) return
// 更改状态
this.status = REJECTED;
//保存失败的原因
this.reason = reason;
}
then (successCallback,failCallback){
if(this.status === FULFILLED){
successCallback(this.value)
}else if(this.status === REJECTED){
failCallback(this.reason)
}
}
}
2.加入异步逻辑
不会马上知道异步到底是成功还是失败,就需要把成功和失败的回调函数保存起来,等待异步执行完之后再执行回调
3.实现then方法多次调用
如果是同步立即执行就可以
如果是异步需要把回调函数放在数组里保存,然后成功时依次调用
如果使用一个变量而非队列来储存回调,那么即使多次p1.then()也只会执行一次回调
4.then方法链式调用
后面then方法回调函数拿到的值是上一个then方法回调函数返回的的值
能够链式调用就说明每个then方法都返回一个promise 这样才可以链式调用并且还要将回调返回值传递给下一个then方法的回调
但是呢如果当返回值是一个promise对象的时候 就不能直接调用resolve(x)了,得先判断promise对象返回的结果再决定调用resolve还是reject
5.then方法中返回的promise是自己本身的时候会发生promise循环调用报错
先看一下es2015中的promise
在实现自己的promise的时候也要考虑到这种情况并且能把错误报出来
6.处理异常
①执行器代码发生错误
②在then方法的回调函数中发生错误 会在下一个then方法中捕获到
③完善then方法中失败和等待的状态
几乎和成功状态的代码一样
在循环调用回调函数的时候就不用传参数了
7.then方法的参数是可选的
先看下es2015中的promise
在我们自己实现的promise中也要支持不传参数的情况
8.all方法
测试代码:
function p1() {
return new MyPromise((resolve, reject) => {
setTimeout(()=>{
resolve('ok');
},1000)
})
}
function p2() {
return new MyPromise((resolve, reject) => {
resolve('ok2');
})
}
MyPromise.all(['a','b',p1(),p2(),'c']).then((value)=>{
console.log(value);
})
实现及结果:
最终实现:
使用计数器 判断当前执行的个数是否等于传入参数的个数
static all(array){
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 是的话将promise返回值放入结果中
current.then(
(value)=>{
addData(i,value)},
(reason)=>{
reject(reason)}
)
}else{
addData(i,current)
}
}
})
}
9.resolve
static resolve(value){
if(value instanceof MyPromise) return value;//如果是promise 直接返回promise对象
// 如果是普通值 要生成一个promise返回
return new MyPromise(resolve => resolve(value));
}
10.finally
无论promise成功还是失败,finally中的回调函数都会被执行一次(所以可以使用.then方法在每个状态中都会执行),并且在finally后可以链式调用then方法得到promise最终返回的值,所以finally要返回一个promise(正好.then方法返回的是一个promise)
但是当callback返回一个promise时,不会等待promise执行完就return了value
最终实现:
把callback的返回值转成一个promise(这里就可以用resolve方法了),返回这个promise的返回值,这样就能把callback的返回值中的代码执行完再执行finally后的then链式调用
finally(callback){
return this.then((value)=>{
return MyPromise.resolve(callback(value)).then(value => value)
},(reason)=>{
return MyPromise.resolve(callback(reason)).then(reason => {
throw reason})
})
}
11.catch
catch(failCallback){
return this.then(undefined,failCallback);//catch之后还能链式调用then方法多以应该返回一个promise,所以return出去this.then()
}
完整代码:
/*
* @Author: liuyj
* @Date: 2021-01-30 20:07:03
* @LastEditTime: 2021-01-31 21:38:44
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \my-code\mypromise.js
*/
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MyPromise {
constructor(executor) {
try {
//捕获执行器发生错误
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING;//定义初始状态为pending
value = undefined;//定义成功的值 初始为undefined
reason = undefined;//定义失败的原因 初始为undefined
successCallback = [];//保存成功回调函数
failCallback = [];
resolve = value => {
//定义为箭头函数是为了在使用的时候this指向这个类的实例对象 MyPromise
//如果状态不是pending就阻止向下执行
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 => {
//如果状态不是pending就阻止向下执行
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; //判断下then方法中有没有传参数,如果没有默认给一个
failCallback = failCallback ? failCallback : reason => {
throw reason;};
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
//这里用setTimeout不是为了延迟而是为了创建异步代码 拿到promise2之后再传递
try {
//捕获回调函数发生错误
let x = successCallback(this.value); //这是上一个成功回调函数返回值
//去判断返回值是promise还是普通值之后再做相应的操作,
// 这里的promise2还拿不到,所以我们这块代码写成异步,等同步代码执行完就会创建完成一个promise2,这时候再去传递
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);//错误传递给下一个then方法的回调
}
}, 0)
} else if (this.status === REJECTED) {
//这里的代码几乎和FULFILLED的一样 解决then链式调用中上一个then方法的回调函数有返回值的情况并且能捕获错误
setTimeout(() => {
try {
let x = failCallback(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);//错误传递给下一个then方法的回调
}
}, 0)
} else {
//当是等待状态时 不能执行回调函数 要把回调函数保存起来 当异步完成时再执行
// this.successCallback.push(successCallback);
// this.failCallback.push(failCallback);
this.successCallback.push(()=>{
//这里写成这种形式 在循环调用回调函数的时候就不用再传参数了
setTimeout(() => {
//这里的代码几乎和FULFILLED的一样 解决then链式调用中上一个then方法的回调函数有返回值的情况并且能捕获错误
try {
let x = successCallback(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
});
this.failCallback.push(()=>{
//这里写成这种形式 在循环调用回调函数的时候就不用再传参数了
setTimeout(() => {
//这里的代码几乎和FULFILLED的一样 解决then链式调用中上一个then方法的回调函数有返回值的情况并且能捕获错误
try {
let x = failCallback(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
});
}
})
return promise2;
}
catch(failCallback){
return this.then(undefined,failCallback);//catch之后还能链式调用then方法多以应该返回一个promise,所以return出去this.then()
}
finally(callback){
return this.then((value)=>{
return MyPromise.resolve(callback(value)).then(value => value)
},(reason)=>{
return MyPromise.resolve(callback(reason)).then(reason => {
throw reason})
})
}
static all(array){
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 是的话将promise返回值放入结果中
current.then(
(value)=>{
addData(i,value)},
(reason)=>{
reject(reason)}
)
}else{
addData(i,current)
}
}
})
}
static resolve(value){
if(value instanceof MyPromise) return value;//如果是promise 直接返回promise对象
// 如果是普通值 要生成一个promise返回
return new MyPromise(resolve => resolve(value));
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
//当then回调函数的返回值是promise对象 并且这个对象是自己本身的时候报错
return reject(new TypeError('Chaining cycle detected for promise #' ))
}
if (x instanceof MyPromise) {
//当then回调函数的返回值是promise对象时
x.then(resolve, reject);
} else {
//当then回调函数的返回值是普通值时
resolve(x);
}
}