写在开头:如果被大佬们看到了有错误还请斧正,如果把萌新带到了沟里,你在爬出来就好了(手动滑稽)
myPromise 中的 then 方法已经完善的差不多了,目前已经能够支持大部分场景的使用,但是 Promise 除了 then 方法之外还有其他的方法的
all 方法的实现
- all 方法是用来解决异步并发问题的
- all 方法允许程序按照异步代码调用的顺序执行异步代码。
- 首先 all 方法会接收一个数组作为参数,在数组中可以填入任何值,这个数组中填入的顺序就是执行之后得到的顺序,all 方法的返回值也是一个 Promise 对象,所以可以在 all 方法后面链式调用 then 方法。
- all 方法中的每一项如果都是成功的那么结果就是成功的,如果有一个是失败的,那么结果就是失败的。
// all 方法是利用一个 Promise 类 . 了一个方法,那么 all 方法应该是一个静态方法
Promise.all(['a', 1, fun()]);
既然 all 方法是一个静态方法,那么就需要在 myPromise 这个类中定义一个静态的 all 方法
class myPromise {
*
*
// all 方法会接收一个数组作为参数
static all(array) {
// 创建一个结果数组用来盛放 all 方法传进来的数组
let result = [];
// 声明一个方法将循环的每一项放入到 result 数组中
function add(index, val) {
result[index] = val;
}
// 由于 all 方法返回的也是一个 Promise 对象,所以在这里创建一个 Promise对象
return new myPromise((resolve, reject) => {
// 接收的既然是一个数组那就循环这个数组
// 看这个数组传递进来的每一项是一个普通值还是一个 Promise 对象
// 如果是普通值就直接将这个值放入结果数组中
// 如果是 Promise 对象,就先执行这个 Promise 对象,在将这执行的结果放入结果数组中
for (let i = 0; i< array.length; i++) {
let current = array[i];
if (current instanceof myPromise) {
current.then((value) => {
add(i, value);
}, (reason) => {
reject(reason);
})
} else {
add(i, array[i]);
}
}
resolve(result);
})
}
*
*
}
这样 all 方法就被简单的实现了,运行,康康结果如何
奈斯~ 就很棒,能运行,不过 <1 empty item> 是个什么玩意儿?这里出现的不应该是 fn1 么?(又一次白给)回头看代码看看怎么肥四吧:
- 在 for 循环中,for 循环是直接执行完成的
- 但是由于有异步代码的延迟执行在 for 循环的执行过程中并没有等待 fn1 的结果
- 在 for 循环结束的时候又直接调用了 resolve 结束了这个状态
- 此时 fn1 还没有执行完
- 所以在输出的时候这里就被输出了空值
啊~ 原来是仗都打完了,貂蝉还在骑马来的路上;现在需要等等骑马来的路上的貂蝉
static all(array) {
let result = [];
// 添加一个标志位
let index = 0;
return new myPromise((resolve, reject) => {
function add(key, val) {
result[key] = val;
// 每一次调用 add 都使得 index++
index++;
// 如果 index 的长度和数组的长度相等,那么也就意味着所有的调用都已经完成,这个时候在 resolve 结果数组
if(index === array.length) {
resolve(result);
}
}
for (let i = 0; i< array.length; i++) {
let current = array[i];
if (current instanceof myPromise) {
current.then((value) => {
add(i, value)
}, (reason) => {
reject(reason)
})
} else {
add(i, array[i])
}
}
resolve(result);
})
}
再次运行之前有问题的代码:
没问题!貂蝉赶上了。all 方法的实现也没有问题了。
Promise.resolve 方法的实现
Promise.resolve 方法的作用是将给定的值转换成为 Promise 对象,也就是说这个方法的返回值就是一个 Promise 对象。
Promise.resolve 方法也能接收一个 Promise 对象,在 resolve 方法中会进行判断,如果接收的是 Promise 对象那么就直接返回这个 Promise 对象。
和 all 方法一样 Promise.resove 方法是一个静态方法,所以需要用 static 关键词进行创建
static resolve(value) {
// 查看接收的值是不是一个 Promise 对象,是就直接返回,不是就把他创建成 Promise 对象并返回
if (value instanceof myPromise) {
return value;
}
return new myPromise((resolve, reject) => {
resolve(value);
})
}
运行起来康康有没有问题
得到了想要的输出结果,没有问题,那么 Promise.resolve 方法就被实现了
finally 方法的实现
finally 方法特点:
- finally 方法中可以读取到 Promise 对象的执行结果。
- 无论当前的 Promise 对象状态是成功的还是失败的,finally 方法中传入的回调函数都是会得到执行的
- finally 方法回调函数中可以继续返回 Promise 对象
function fn() {
return new Promise((resolve, reject) => {
resolve('fn');
})
}
fn().finally(() => {
console.log('finally 方法')
}).then((value) => {
console.log(value)
})
从使用上分析:finally 方法和 then 方法一样是 Promise 原型对象上的一个方法,所以定义方法和 then 方法相同
// finally 方法接收一个回调函数作为参数,因为无论当前的 Promise 对象执行的结果是成功或失败都要调用这个回调函数
finally(callback) {
// 使用 then 方法可以在 finally 方法的内部得到当前 Promise 的状态
// finall 方法后面还可以链式调用 then 方法,所以 finally 方法还需要返回一个 Promise 对象
return this.then((value) => {
callback();
return value;
}, (reason) => {
callback();
throw reason;
})
}
接着运行起来康康结果
没问题,接下来再加上异步的处理逻辑完善 finally 方法
finally(callback) {
return this.then((value) => {
// 借助 myPromise.resolve 方法无论 callback 返回值是不是 Promise 都转为 Promise 在执行
return myPromise.resolve(callback()).then(() => {
value
});
}, (reason) => {
return myPromise.resolve(callback()).then(() => {
throw reason;
});
});
}
catch 方法
- catch 方法是用来处理当前这个 Promise 为失败状态下的情况的
- 在调用 then 方法的时候是可以不用传递失败回调的,直接被 catch 方法捕捉
// 既然只是捕捉失败,那么在 catch 方法捕捉错误信息的时候只传递失败回调就可以了
catch(failCallback) {
return this.then(undefind, failCallback);
}
运行起来康康结果
没有问题,到此 catch 方法也就实现了。
最后就是 myPromise 实现的全过程完成代码了
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected'
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 = 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 ? successCallback : value => value;
failCallback = failCallback ? failCallback : reason => {
throw reason
};
let thenPromise = new myPromise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
let x = successCallback(this.value);
argParsing(thenPromise, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = failCallback(this.reason);
argParsing(thenPromise, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
} else {
this.successCallback.push(() => {
setTimeout(() => {
try {
let x = successCallback(this.value);
argParsing(thenPromise, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
this.failCallback.push(() => {
setTimeout(() => {
try {
let x = failCallback(this.reason);
argParsing(thenPromise, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
}
})
return thenPromise;
}
finally(callback) {
return this.then((value) => {
return myPromise.resolve(callback()).then(() => {
value
});
}, (reason) => {
return myPromise.resolve(callback()).then(() => {
throw reason;
});
});
}
catch(failCallback) {
return this.then(undefined, failCallback);
}
static all(array) {
let result = [];
let index = 0;
return new myPromise((resolve, reject) => {
function add(key, val) {
result[key] = val;
index++;
if (index === array.length) {
resolve(result);
}
}
for (let i = 0; i < array.length; i++) {
let current = array[i];
if (current instanceof myPromise) {
current.then((value) => {
add(i, value)
}, (reason) => {
reject(reason)
})
} else {
add(i, array[i])
}
}
})
}
static resolve(value) {
if (value instanceof myPromise) {
return value;
}
return new myPromise((resolve, reject) => {
resolve(value);
})
}
}
function argParsing(thenPromise, x, resolve, reject) {
if (thenPromise === x) return reject(new TypeError('Promise 被循环调用了'));
if (x instanceof myPromise) {
x.then(resolve, reject);
} else {
resolve(x);
}
}