有些面试官脑洞很大,非要让面试者手写一下Promise.all的实现代码,就很离谱
算了,没有办法,谁让我是打工人,写吧。
- 先准备两个函数用于测试所用。(完整代码在最后)
function fun1 () {
return new Promise((res, rej) => {
setTimeout(() => {
res(1)
}, 1000);
})
}
function fun2 () {
return new Promise((res, rej) => {
setTimeout(() => {
res(2)
}, 10);
})
}
- 先聊一个题外话,关于Promise是异步的还是同步的?这个问题也会经常问到,直接说我的答案,就不写代码来证明了,毕竟这篇文章主要是说手写的问题。
Promise本身属于同步的,但是.then和catch和finally方法是异步的
Promise.all属于异步方法
- 手写Promise.all
在手写之前先要知道它的作用,Promise.all是一个方法,接收一个数组,数组中是一个个的Promise实例对象,Promise.all会等待所以Promise实例都返回成功后在返回成功结果是一个数组(迭代器),如果有一个失败则返回失败。看一段示例代码。
// 输出 [1,2]
Promise.all([fun1(),fun2()]).then(res=>{
console.log(res);
}).catch(err=>console.log(err)).finally()
然后在Promise构造函数上添加一个方法来实现自定义的.all方法,代码如下。
Promise.myall = function (pmarr) {
// 手写Promise.all最终返回的还是一个promise,所以我们创建一个promise并返回
return new Promise((resolve, reject) => {
try {
/**
* 首先要判断迭代器的个数
* 但是这里不能用length的方式去判断,因为它可能不是一个数组,也限定必须是数组
* 要用循环的方式去判断,一定要用forin 因为它不一定是数组可能是对象
*
* 如果你考虑严谨一点的话,可以对pmarr进行一些校验 如下
*/
if (pmarr === undefined) reject('没有迭代器')
let length = 0 // 记录迭代器的个数
let resultLength = 0// 记录已执行的promise个数
let result = [] // 用于存储返回暑假
for (const key in pmarr) {
length++
/**
* 1因为item不一定都是promise对象,所以要全部转一下,
* 2因为每个promise成功或者是失败都有回调,所以我们要去拿到每一个prmoise的返回状态
* 3拿到每一个prmise的返回状态后不能用push的方式添加到result中,返回结果的顺序需要和pmarr的顺序一致
* 4当其中有一项prmise返回的失败则整个promise.all就会返回失败,所以直接reject放在第二个参数中,
* 只要失败一个并返回失败终止循环
* 5判断迭代器是否都执行完,全部执行完后返回成功
*/
Promise.resolve(pmarr[key]).then(res => {
result[key] = res
resultLength++
if (length === resultLength) resolve(result)
}, reject)
}
// 当没有转入迭代器时直接返回成功状态
if (!length) resolve([])
} catch (error) {
reject(error)
}
})
}
// 输出[1,2]
Promise.myall([fun1(),fun2()]).then(res=>{
console.log(res);
})
在测试一下其它情况的结果。因为在myall方法中使用的是forin来遍历的,所以大部分情况都会返回成功状态。可能并不严谨。
// 输出 []
Promise.myall([]).then(res=>{
console.log(res);
})
// 输出 [1, 2, 3]
Promise.myall([1,2,3]).then(res=>{
console.log(res);
})
// 输出 [a: 1, b: 2] 当然原生的promise.all是不支持传入对象的,会抛出错误,
// 如果我们把上面的forin换为其它遍历方式加一个trycatch,打印出错误也是一样的
Promise.myall({a:1,b:2}).then(res=>{
console.log(res);
})
// 输出 []
Promise.myall(null).then(res => {
console.log(res);
}).catch(err => console.log(err))
内容就这些了,如果哪里说的不对或者写的不对,欢迎喷我,你的打击是我成长的动力,嘿嘿!最后在附上所有代码,方便直接CV。点赞不迷路。
function fun1 () {
return new Promise((res, rej) => {
setTimeout(() => {
res(1)
}, 1000);
})
}
function fun2 () {
return new Promise((res, rej) => {
setTimeout(() => {
res(2)
}, 10);
})
}
/**
* Promise本身属于同步的,但是.then和catch和finally方法是异步的
* Promise.all属于异步方法
*
*/
// 输出 [1,2]
// Promise.all([fun1(), fun2()]).then(res => {
// console.log(res);
// }).catch(err => console.log(err)).finally()
/**
* 手写Promise.all
* 在手写之前先要知道它的作用,
* Promise.all是一个方法,接收一个数组,数组中是一个个的Promise实例对象,
* Promise.all会等待所以Promise实例都返回成功后在返回成功结果是一个数组(迭代器),如果有一个失败则返回失败
*/
Promise.myall = function (pmarr) {
// 手写Promise.all最终返回的还是一个promise,所以我们创建一个promise并返回
return new Promise((resolve, reject) => {
try {
/**
* 首先要判断迭代器的个数
* 但是这里不能用length的方式去判断,因为它可能不是一个数组,也限定必须是数组
* 要用循环的方式去判断,一定要用forin 因为它不一定是数组可能是对象
*
* 如果你考虑严谨一点的话,可以对pmarr进行一些校验 如下
*/
if (pmarr === undefined) reject('没有迭代器')
let length = 0 // 记录迭代器的个数
let resultLength = 0// 记录已执行的promise个数
let result = [] // 用于存储返回暑假
for (const key in pmarr) {
length++
/**
* 1因为item不一定都是promise对象,所以要全部转一下,
* 2因为每个promise成功或者是失败都有回调,所以我们要去拿到每一个prmoise的返回状态
* 3拿到每一个prmise的返回状态后不能用push的方式添加到result中,返回结果的顺序需要和pmarr的顺序一致
* 4当其中有一项prmise返回的失败则整个promise.all就会返回失败,所以直接reject放在第二个参数中,
* 只要失败一个并返回失败终止循环
* 5判断迭代器是否都执行完,全部执行完后返回成功
*/
Promise.resolve(pmarr[key]).then(res => {
result[key] = res
resultLength++
if (length === resultLength) resolve(result)
}, reject)
}
// 当没有转入迭代器时直接返回成功状态
if (!length) resolve([])
} catch (error) {
reject(error)
}
})
}
// 输出[1,2]
Promise.myall([fun1(),fun2()]).then(res=>{
console.log(res);
})
// 输出 []
// Promise.myall([]).then(res=>{
// console.log(res);
// })
// 输出 [1, 2, 3]
// Promise.myall([1,2,3]).then(res=>{
// console.log(res);
// })
// 输出 [a: 1, b: 2] 当然原生的promise.all是不支持传入对象的,会抛出错误,
// 如果我们把上面的forin换为其它遍历方式加一个trycatch,打印出错误也是一样的
// Promise.myall({a:1,b:2}).then(res=>{
// console.log(res);
// })
// 输出 []
// Promise.myall(null).then(res => {
// console.log(res);
// }).catch(err => console.log(err))