本文首发于知乎专栏——前端面试题汇总,大家可以通过文章底部的阅读原来来访问原文地址
Promise是面试中经常遇到的,如果面试中面试官问你Promise.all()
怎么用,那你面试的岗位可能是差不多高级前端开发的岗位,但如果让你手写一个Promise.all()
那你面试的岗位应该就是资深/专家前端开发的岗位了
上期我们实现了函数的call()
、bind()
、apply()
方法。
Promise.all(iterable)
方法返回一个 Promise
实例,此实例在 iterable
参数内所有的 promise
都“完成(resolved)”或参数中不包含 promise
时回调完成(resolve);如果参数中 promise
有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败 promise
的结果。
例子如下:
var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then(function(values) {
console.log(values);
});
// expected output: Array [3, 42, "foo"]
直接上代码:
Promise.myAll = function (iterators) {
const promises = Array.from(iterators)
const len = promises.length
let count = 0
let resultList = []
return new Promise((resolve, reject) => {
promises.forEach((p, index) => {
Promise.resolve(p)
.then((result) => {
count++
resultList[index] = result
if (count === len) {
resolve(resultList)
}
})
.catch(e => {
reject(e)
})
})
})
}
核心思路:
Promise.myAll()
返回的肯定是一个promise
对象,所以可以直接写一个return new Promise((resolve, reject) => {})
(这应该是一个惯性思维)Promise.resolve()
将参数"包一层",使其变成一个promise
对象resolve
出来,在这里做了计数器(count
),每个内部promise对象决议后就将计数器加一,并判断加一后的大小是否与传入对象的数量相等,如果相等则调用resolve()
,如果任何一个promise对象失败,则调用reject()
方法。一些细节:
可遍历的
参数,所以未必一定是一个数组,所以用Array.from()
转化一下for…of
进行遍历,因为凡是可遍历的
变量应该都是部署了iterator
方法,所以用for…of
遍历最安全var promise1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, 'one');
});
var promise2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, 'two');
});
Promise.race([promise1, promise2]).then(function(value) {
console.log(value);
// Both resolve, but promise2 is faster
});
// expected output: "two"
有了Promise.all()
的铺垫,race就好写多了。
Promise.myRace = function (iterators) {
return new Promise((resolve, reject) => {
for (let p of iterators) {
Promise.resolve(p)
.then((result) => {
resolve(result)
})
.catch(e => {
reject(e)
})
}
})
}
核心思路:
finally()
方法返回一个Promise
。在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。这为在Promise
是否成功完成后都需要执行的代码提供了一种方式。
这避免了同样的语句需要在then()
和catch()
中各写一次的情况。
let isLoading = true;
fetch(myRequest).then(function(response) {
var contentType = response.headers.get("content-type");
if(contentType && contentType.includes("application/json")) {
return response.json();
}
throw new TypeError("Oops, we haven't got JSON!");
})
.then(function(json) { /* process your JSON further */ })
.catch(function(error) { console.log(error); })
.finally(function() { isLoading = false; });
Promise.prototype.myFinally = function finallyPolyfill(callback) {
return this.then(function(value) {
return Promise.resolve(callback()).then(function() {
return value;
});
}, function(reason) {
return Promise.resolve(callback()).then(function() {
Promise.reject(reason);
});
});
};
核心思路:
this
指向的是当前Promise
对象,所以可以直接用this.then()
一些细节:
callback传入的有可能仍然是一个Promsie对象,如果真的是Promise对象,要等该promise决议之后才能执行之后then()方法,但是这个then()中拿到的是finally()之前的决议值,有种"决议值穿透"的感觉。
PS:我在网上找到了最权威的写法,毫无破绽 https://github.com/matthew-andrews/Promise.prototype.finally/blob/master/finally.js
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有