Promise一直是面试被问的重点,根据各种面经记录Promise在面试中经常问道的问题,同时会增加一些前瞻性和拓展性的问题,适合我这种临时抱佛脚的人
前期储备
事件循环(event loop)的执行顺序
详见B栈哈默:什么是Event Loop?
如果用比较文字的形式来解释:
- 一开始整个脚本作为宏任务执行
- 执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列
- 当前宏任务执行完出队,检查微任务列表,有则依次执行,直到全部执行完毕
- 执行浏览器UI线程的渲染工作
- 检查是否有
Web worker
任务,有则执行 - 执行完本轮的宏任务,回到2,依次循环,直到宏任务和微任务队列都为空
微任务包括:MutationObserver
、Promise.then()
或catch()
、Promise
为基础开发的其他技术,比如fetch API
、V8
垃圾回收过程、Node
独有的process.nextTick()
宏任务包括:script
、setTimeout
、setInterval
、setImmediate
、I/O
、UI rednering
注意:在所有任务开始的时候,由于宏任务中包括了script,所以浏览器会先执行一个宏任务,在这个过程中你看到的延迟任务(例如setTimeout
)将被放到下一轮
Promise常考面试题(问答)
(1)简单说一下Promise,谈谈你对Promise的理解
个人遇到这样的问题会从以下几个方面回答: 【基础回答】Promise是什么?有什么作用?解决了什么问题?【进阶回答】Promise相关的一些知识点(这样也可以让面试官顺藤摸瓜,沿着你的回答提问)
所以我会这样回答:
Promise
是ES6
新增的语法,是一种异步编程的一种解决方案,Promise
本质上是一个绑定了回调的对象。 Promise
在一定程度上解决了回调函数的书写结构问题,解决了回调地狱的问题。Promise
可以看作是一个状态机,它有三种状态:pending
,fulfilled
,rejected
,其中初始状态是pending
,可以通过函数resolve
(表示成功)把状态变为fulfilled
,或者通过函数reject
(表示失败)把状态变为rejected
,状态一经改变就不能再次变化。
拓展问1: Promise有几种状态?
拓展问2: Promise的状态可变吗?
状态不可变
const p = new Promise((resolve, reject) => {
resolve(1);
reject(2);
})
p.then(data => {
console.log(data)
}).catch(err => {
console.log(err);
})
拓展问3:什么是回调地狱?
什么是回调地狱? 答: 回调地狱就是嵌套回调问题,具体来说就是异步返回值又依赖于另一个异步返回值(看下面的代码)
function double(value, success, failure) {
setTimeout(()=>{
try {
if (typeof value !== 'number') {
throw 'Must provide number as first argument';
}
success(2*value);
} catch(e) {
failure(e);
}
},1000);
}
const successCallback = (x) => {
double(x, (y) => console.log(`Success:${y}`));
};
const failureCallback = (e) => console.log(`Failure:${e}`);
double(3, successCallback, failureCallback);
拓展问4: Promise是如何解决地狱回调的?
看下面这个例子:
function request1() {
return new Promise(resolve => resolve(1));
};
function request2() {
return new Promise(resolve => resolve(2));
};
function request3() {
return new Promise(resolve => resolve(3));
};
request1()
.then(data => {
console.log('1data',data)
return request2();
})
.then(data => {
console.log('2data',data);
return request3();
});
then里面可以return Promise,来防止地狱回调
(2)你用过Promise吗?为什么要用?
(3)promise的方法有哪些?Promise的API了解多少?
prmoise.all()
Promise.all([]).then(res=> {}).catch(err => {})
该方法接收一个可迭代对象(如Array
,Map
,Set
),返回一个Promise
(新期约),只有当该数组中所有的Promise完成后才会有pending
转变为resolved
执行then
里面的回调函数;若数组中有任意一个promise
被拒绝则会执行失败回调,即catch
方法会捕获到首个被执行的reject
函数。通过该方法获得的成功结果的数组里面的数据顺序和接收到的promise
数组顺序是一致的。
Promise.race()
Promise.race([]).then(res => {}).catch(err => {})
Promise.race()
和Promise.all()
一样都是将多个Promise
实例组合成一个Promise
的静态方法
不同的是:Promise.race()
当传入的数组中有任意一个promise
被拒绝或者成功,则会采用第一个promise
作为返回值,若成功则执行then
,失败执行catch
。
Promise.any()
区别于Promise.all()
, Promise.any()
只要有一个成功,就返回成功的promise
,如果没有一个成功,就返回一个失败的promise
Promise.any([]).then(res => {}).catch(err => {})
Promise.allSelected()
Promise.allSelected([]).then(res => {}).catch(err => {})
返回一个在所有给定的promise都已经fulfilled或rejected后的promise,并带有一个对象数组,每个对象表示对应的promise结果
看文档的例子:
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
const promises = [promise1, promise2];
Promise.allSettled(promises).
then((results) => results.forEach((result) => console.log(result.status)));
(4)async await 和Promise
拓展1:执行async函数,返回的都是Promise对象
看下面这个例子:
async function test1() {
return 1;
};
async function test2() {
return Promise.resolve(1);
};
const res1 = test1();
const res2 = test2();
console.log('res1', res1);
console.log('res2', res2);
根据打印结果,我们可以发现,如果使用async
执行函数,返回一个基本数据类型,会包装成Promise
对象
拓展2:Promise.then 成功的情况,对应的是await
async function test3() {
const p3 = Promise.resolve(3);
p3.then(data => {
console.log('data',data);
});
const data = await p3;
console.log(data);
}
test3();
我们再看另一种情况:
async function test3() {
const data = await 4;
console.log('data',data);
}
test3();
其实await
帮助我们把后面的4
封装成一个Promise
对象
如果我们改一下,改成reject和catch
async function test3() {
const p3 = Promise.reject(3);
p3.catch(data => {
console.log('data',data);
});
const data = await p3;
console.log('data',data);
}
test3();
看到3被打印出来了,但是异常并没有捕获到
拓展3:Promise.catch 异常的情况, 对于try…catch…
我们把上面没有捕获到异常的代码进行改写:
async function test3() {
const p3 = Promise.reject(3);
p3.catch(data => {
console.log('data',data);
});
try {
const data = await p3;
console.log('data',data);
} catch (err) {
console.log('err', err);
}
}
test3();
拓展4: 如何让Promise顺序执行?应用场景是什么?
async await
看下面这个例子:
const p1 = new Promise(resolve => {
setTimeout(()=> {
resolve(1);
}, 3000);
});
const p2 = new Promise(resolve => {
setTimeout(()=> {
resolve(2);
}, 2000);
});
const p3 = new Promise(resolve => {
setTimeout(()=> {
resolve(3);
}, 1000);
});
async function execute() {
await p1.then(data => console.log(data));
await p2.then(data => console.log(data));
await p3.then(data => console.log(data));
};
execute();
Promise常考输入输出题(待补充)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)