- 上篇讲到Promise的相关实现,本篇文章着重于讲解Promise相关的试题
Promise状态凝固
const promise = new Promise((resolve, reject) => {
resolve('success1');
reject('error');
resolve('success2');
});
promise.then((res) => {
console.log('then:', res);
}).catch((err) => {
console.log('catch:', err);
})
promise的状态是不可逆的,一旦发生改变,便不会再变化,所以上述输出:
输出: 'then:' success1
Promise值穿透
Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)
then 方法接受的参数是函数,而如果传递的并非是一个函数,它实际上会将其解释为 then(null),这就会导致前一个 Promise 的结果会穿透下面。在上篇的代码中有体现
promise执行顺序
Promise.resolve().then(() => {
console.log(0);
return Promise.resolve(4);
}).then((res) => {
console.log(res)
})
Promise.resolve().then(() => {
console.log(1);
}).then(() => {
console.log(2);
}).then(() => {
console.log(3);
}).then(() => {
console.log(5);
}).then(() =>{
console.log(6);
})
在原生的Promise中Promise.resolve()会产生两次微任务,所以上述代码中第一个Promise.resolve()可以变成以下代码
Promise.resolve().then(() => {
console.log(0);
return 4;
})
.then()
.then()
.then((res) => {
console.log(res)
})
在js引擎中为了让microtask尽快的输出,做了一些优化,连续的多个then如果没有reject或者resolve会交替执行then而不至于让一个堵太久完成用户无响应,所以上面的代码输出
0123456
Promise与async结合
async function async1 (){
console.log(1)
let result = await async2()
console.log(3)
}
async function async2 (){
console.log(2)
}
setTimeout(()=> {
console.log(5)
})
// 注意这里异步的执行顺序
Promise.resolve().then(res => {
console.log(7)
})
async1()
Promise.resolve().then(res => {
console.log(4)
})
console.log(6)
- 输出:
1267345await前面的代码是同步执行的,后面的代码相当于then的链式调用,会被添加到事件队列里,输出上述结果
Promise串形化
- reduce实现
const mergePromise = ajaxArray => {
let data = [] // 收集执行完的结果
return ajaxArray.reduce((pre, next)=> {
return pre.then(next).then((res)=> {
data.push(res)
return data
})
}, Promise.resolve())
};
mergePromise([ajax1,ajax2,ajax3]).then(res => {
console.log('最终按顺序输出结果为:', res)
})
- 模拟队列方式
function run () {
let p = promises.shift()
if (!p) return
return p().then(res=> {
run()
})
}
run()
Promise控制并发
实现原理,构建并发长度的数组,使用promise.race获取最先从并发数组中完成的请求,然后将其从并发数组中删除,并放入新的请求,依次循环
- 函数实现
const request = (url) => {
let second = Math.ceil(Math.random()*5*1000)
return new Promise((resolve, reject)=> {
setTimeout(()=> {
console.log(second+'秒请求完成:', url)
resolve(url)
}, second)
}).then(res => {
console.log('请求完成成后的代码')
return res
})
}
const arr = [
'bytedance.com',
'tencent.com',
'alibaba.com',
'microsoft.com',
'apple.com',
'hulu.com',
'amazon.com'
]
function limitLoad(urls, handler, limit) {
return new Promise((resolve, reject) => {
const sequence = [].concat(urls)
let pool = []
let result = [] // 汇总最终所有结果
pool = sequence.splice(0, limit).map((url, index) => {
return handler(url).then(()=>{
result.push({url, index})
resolve(result)
return index
})
})
let race = Promise.race(pool)
for (let i= 0; i< sequence.length; i++) {
race = race.then(index => {
pool[index] = handler(sequence[i]).then(()=>{
result.push({url: sequence[i], index})
resolve(result)
return index
})
return Promise.race(pool)
})
}
})
}
limitLoad(arr, request, 2).then(res=>console.log(res))
- 类实现
//promise并发限制
class PromisePool {
constructor(max, fn) {
this.max = max; //最大并发量
this.fn = fn; //自定义的请求函数
this.pool = []; //并发池
this.urls = []; //剩余的请求地址
}
start(urls) {
this.urls = urls; //先循环把并发池塞满
while (this.pool.length < this.max) {
let url = this.urls.shift();
this.setTask(url);
}
//利用Promise.race方法来获得并发池中某任务完成的信号
let race = Promise.race(this.pool);
return this.run(race);
}
run(race) {
race
.then(res => {
//每当并发池跑完一个任务,就再塞入一个任务
let url = this.urls.shift();
this.setTask(url);
return this.run(Promise.race(this.pool));
})
}
setTask(url) {
if (!url) return
let task = this.fn(url);
this.pool.push(task); //将该任务推入pool并发池中
console.log(`\x1B[43m ${url} 开始,当前并发数:${this.pool.length}`)
task.then(res => {
//请求结束后将该Promise任务从并发池中移除
this.pool.splice(this.pool.indexOf(task), 1);
console.log(`\x1B[43m ${url} 结束,当前并发数:${this.pool.length}`);
})
}
}
//test
const URLS = [
'bytedance.com',
'tencent.com',
'alibaba.com',
'microsoft.com',
'apple.com',
'hulu.com',
'amazon.com'
]
//自定义请求函数
const requestFn = url => {
return new Promise(resolve => {
setTimeout(() => {
resolve(`任务${url}完成`)
}, 1000)
}).then(res => {
console.log('外部逻辑', res);
})
}
const pool = new PromisePool(5, requestFn); //并发数为5
pool.start(URLS)
Promise实现红绿灯
//1、实现三秒红灯,两秒绿灯,1秒黄灯
function red() {
console.log('red');
}
function green() {
console.log('green');
}
function yellow() {
console.log('yellow');
}
const light = function (timer, cb) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
cb();
resolve();
}, timer);
});
};
const step = async function () {
// promise链式调用版
// Promise.resolve().then(function (resolve) {
// return light(3000, red);
// }).then(function () {
// return light(2000, green);
// }).then(function () {
// return light(1000, yellow);
// }).then(function () {
// step();
// });
// async/await版
while (1){
await light(3000, red);
await light(2000, green);
await light(1000, yellow);
}
}
step();
以上就是我收集的一些关于Promise的试题,基本上可以覆盖现在市面上的大部分面试题,
- 写作不易,欢迎点赞