ES6 Promise、async与await核心机制及面试题解析
本文系统梳理ES6中Promise、async与await的核心机制,涵盖执行顺序、微任务与宏任务调度、错误处理及常见面试题解析。通过具体代码示例,阐明Promise.resolve/reject行为、async函数返回值特性及await对执行流的影响,帮助开发者掌握异步编程底层逻辑。
本文整理在JavaScript学习过程中遇到的关于Promise、async和await的基础面试题。
出题目的:
- 主要考察对Promise、async和await基础概念的掌握程度。
- 同时考察对Event Loop机制、宏任务与微任务执行顺序的理解。
知识点:
- JavaScript执行顺序遵循单线程模型,代码自上而下执行,遵循先同步后异步、先微任务后宏任务的规则。
- new Promise()与Promise.resolve()会触发then方法的执行。
- new Promise((reject)=>{reject()})与Promise.reject()会触发catch方法的执行。
- 在then和catch内部,若没有抛出new Error,则其行为相当于resolve。
- async函数定义相当于返回一个Promise.resolve()。
- await关键字后的代码被视为异步操作,属于微任务;而setTimeout属于宏任务。
- 在初始化Promise时,其构造函数内部的代码会立即执行。
代码:
考点1:Promise.resolve与Promise.reject的执行顺序。
Promise.resolve().then(() => { // 优先寻找then
console.log(1);
}).catch(() => {
console.log(2);
})
// 1
Promise.reject().then(() => { // 优先寻找catch
console.log(1);
}).catch(() => {
console.log(2);
})
// 2
考点2:then和catch内部未抛出new Error()时,其行为相当于resolve。
Promise.resolve().then(() => {
console.log(1);
}).catch(() => {
console.log(2);
}).then(() => {
console.log(3);
})
// 1 3
Promise.reject().then(() => {
console.log(1);
}).catch(() => {
console.log(2);
}).then(() => {
console.log(3);
})
// 2 3
Promise.reject().then(() => {
console.log(1);
}).catch(() => {
console.log(2);
throw new Error();
}).then(() => {
console.log(3);
})
// 2 报错
Promise.reject().then(() => {
console.log(1);
}).catch(() => {
console.log(2);
throw new Error();
}).then(() => {
console.log(3);
}).catch(() => {
console.log(4);
})
// 2 4
考点3:async函数定义相当于返回一个Promise.resolve。
const res = async function fn() {
return 100;
}
console.log(res()); // 返回一个resolve状态的Promise对象 Promise {<fulfilled>: 100}
res().then(()=>{
console.log(0);
}).catch(()=>{
console.log(1);
})
// 0
(async function () {
const a = fn();
const b = await fn();
console.log(a); // Promise {<fulfilled>: 100}
console.log(b); // 100
})()
考点4:await关键字的代码执行顺序。
async function fn1() {
console.log("fn1 start");
await fn2();
console.log("fn1 end");
}
async function fn2() {
console.log("fn2 start");
}
console.log("start");
fn1();
console.log("end");
/**
* 打印顺序:
* start
* fn1 start
* fn2 start
* end
* fn1 end
*/
async function fn1() {
console.log("fn1 start");
await fn2();
console.log("fn1 end");
await fn3();
console.log("fn3 end");
}
async function fn2() {
console.log("fn2");
}
async function fn3() {
console.log("fn3");
}
console.log("start");
fn1();
console.log("end");
/**
* 打印顺序:
* start
* fn1 start
* fn2
* end
* fn1 end
* fn3
* fn3 end
*/
考点5:Promise与setTimeout的执行顺序对比。
console.log("start");
setTimeout(()=>{
console.log("setTimeout")
});
Promise.resolve().then(()=>{
console.log("Promise")
})
console.log("end")
/**
* 打印顺序:
* start
* end
* Promise
* setTimeout
*/
async function fn1() {
console.log("fn1 start");
await fn2();
console.log("fn1 end"); // await后面的代码为"微任务代码"
}
async function fn2() {
console.log("fn2");
}
console.log("start");
setTimeout(()=>{
console.log("setTimeout"); // 宏任务
});
fn1();
console.log("end");
/**
* 打印顺序:
* start
* fn1 start
* fn2
* end
* fn1 end
* setTimeout
*/
附:promise与async await结合使用
昨天看到一道字节外包的面试题。
const list = [1, 2, 3];
const square = num => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(num * num);
}, 1000);
});
}
function test() {
// 修改这里的代码
list.forEach(async x => {
const res = await square(x);
console.log(res);
});
}
test()题目要求将同步执行的数组替换为异步打印操作。
测试验证表明,forEach与for循环不同,for循环可以修改数组值,而forEach无法直接获取特定项的值。这里的异步指的是每执行一次数组循环,就执行一步test()方法。
const list = [1, 2, 3];
const square = num => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(num * num);
}, 1000);
});
}
function test() {
for(let x of list) {
var res = await square(x)
console.log(res)
}
}
test()总结
到此这篇关于ES6中Promise、async和await面试题整理的文章就介绍到这了,更多相关ES6 Promise、async、await面试题内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!
JS语法错误会阻止加载吗?区分SyntaxError与资源加载失败
2026-11-05 16:08:46
JavaScript常见SyntaxError语法错误排查与修复方法
2026-11-05 13:58:44
JS中slice、substring和substr截取字符串的区别
2026-11-05 13:43:47
JS 转 TS 手动迁移最佳实践:从配置 tsconfig 到消除 any 类型
2026-11-05 11:53:32
为什么JS数组push后得到的是数字而不是数组?
2026-11-05 09:59:18
