React Native 面试:JS 异步与事件循环核心知识点
·
一、事件循环(Event Loop)核心机制
1. 基础概念
JavaScript 是单线程语言,事件循环是其实现异步的核心机制。
执行流程:
- 调用栈(Call Stack):同步代码按顺序入栈执行
- Web API / 宿主环境:setTimeout、DOM事件、fetch等异步操作在这里等待
- 任务队列(Task Queue):
- 宏任务(Macrotask):script整体代码、setTimeout、setInterval、setImmediate、I/O、UI渲染
- 微任务(Microtask):Promise.then/catch/finally、queueMicrotask、MutationObserver、process.nextTick(Node)
2. 执行顺序(黄金法则)
同步代码 → 所有微任务 → 一个宏任务 → 所有微任务 → 下一个宏任务...
经典面试题输出:
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => {
console.log('3');
Promise.resolve().then(() => console.log('4'));
});
console.log('5');
// 输出顺序:1 → 5 → 3 → 4 → 2
3. Node.js 事件循环(与浏览器差异)
Node 事件循环分 6 个阶段:
- timers → pending callbacks → idle/prepare → poll → check → close callbacks
关键差异:
process.nextTick优先级高于 Promise- 同一阶段内的宏任务会批量执行完,再清空微任务
- Node 11+ 已与浏览器行为趋同
二、JS 异步演进史
1. 回调函数(Callback)
// 问题:回调地狱(Callback Hell)
getData(function(a) {
getMoreData(a, function(b) {
getMoreData(b, function(c) {
// 嵌套过深,难以维护
});
});
});
缺点:嵌套深、错误处理难、难以并行
2. Promise
// 三种状态:pending → fulfilled / rejected(状态不可逆)
const promise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => resolve('成功'), 1000);
});
promise
.then(res => console.log(res))
.catch(err => console.error(err))
.finally(() => console.log('总会执行'));
常用静态方法:
| 方法 | 特点 | 场景 |
|---|---|---|
Promise.all |
全部成功才成功,一个失败就失败 | 并行请求,缺一不可 |
Promise.race |
谁快用谁 | 超时控制 |
Promise.allSettled |
等所有完成,收集结果 | 需要知道每个的结果 |
Promise.any |
一个成功就成功,全失败才失败 | 容错降级 |
3. Generator + co
function* gen() {
const a = yield fetch('/api/a');
const b = yield fetch('/api/b');
return [a, b];
}
async/await 的前身,需要 co 库自执行
4. async / await(ES2017,终极方案)
async function fetchData() {
try {
const a = await fetchA(); // 暂停等待
const b = await fetchB(a); // 顺序执行
return b;
} catch (err) {
console.error(err); // 统一错误捕获
}
}
并行优化:
// ❌ 串行(慢)
const a = await fetchA();
const b = await fetchB();
// ✅ 并行(快)
const [a, b] = await Promise.all([fetchA(), fetchB()]);
三、React Native 中的异步场景
1. 核心异步 API
setTimeout / setInterval:定时器fetch / axios:网络请求AsyncStorage:本地存储(异步)Animated:动画驱动Bridge 通信:JS ↔ Native 异步消息机制
2. React Native 事件循环特点
- JS 线程独立:有独立的 JS 事件循环,不阻塞 UI 线程
- Bridge 异步:JS 与 Native 通过 Bridge 异步通信,批量处理
- requestAnimationFrame:与屏幕刷新同步(60fps)
- setImmediate / process.nextTick:Hermes 引擎下行为需注意
3. 常见性能陷阱
- JS 线程阻塞:长时间计算导致动画掉帧 → 用
InteractionManager或拆分任务 - Bridge 拥堵:频繁跨线程通信 → 批量发送、减少序列化
- 内存泄漏:组件卸载后未清除定时器/订阅 → useEffect 清理函数
四、高频面试题
Q1:Promise.then 为什么是微任务?
微任务在当前宏任务结束后、下一个宏任务前执行,保证尽快处理异步结果,避免被其他宏任务插队,提升响应性。
Q2:async 函数返回什么?
永远返回 Promise。非 Promise 值会被 Promise.resolve() 包装。
Q3:await 后面的代码是同步还是异步?
await 之前同步,之后是微任务回调。await 会让出线程,等待 Promise resolve 后,后续代码进入微任务队列。
Q4:Promise 构造函数是同步还是异步?
同步执行。只有 .then/.catch/.finally 的回调是异步微任务。
Q5:如何取消 Promise?
Promise 本身不可取消,可用:
AbortController(fetch 原生支持)- 封装可取消的 Promise(加 flag 标记)
Promise.race配合超时 reject
Q6:React Native 中为什么 setTimeout 不准?
JS 线程被占用时事件循环延迟执行;Bridge 通信也可能引入延迟。高精度定时用 requestAnimationFrame 或 Native 模块。
Q7:宏任务微任务经典混合题
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(() => console.log('setTimeout'), 0);
async1();
new Promise(resolve => {
console.log('promise1');
resolve();
}).then(() => console.log('promise2'));
console.log('script end');
答案:
script start → async1 start → async2 → promise1 → script end → async1 end → promise2 → setTimeout
五、进阶考点
1. 事件循环与渲染时机
浏览器中:微任务 → 渲染更新 → 宏任务
- 每次宏任务后不一定渲染,浏览器有自己的渲染节奏(约 16.6ms)
- 微任务中修改 DOM 会合并到一次渲染
2. 任务调度优先级
process.nextTick > Promise.then > queueMicrotask > setTimeout > setImmediate
3. 并发模型总结
- 并行(Parallelism):多线程同时执行(Web Worker / Native 多线程)
- 并发(Concurrency):单线程通过事件循环交替处理多个任务
- JS 是并发非并行(单线程),但宿主环境提供并行能力
4. React Native Hermes 引擎
- 开启 Hermes 后事件循环行为基本一致
- 启动更快、内存占用更低
- 注意:某些非标准 API(如
process.nextTick)行为可能有差异
面试答题技巧: 回答事件循环问题时,先讲"同步代码全部执行完 → 清空微任务队列 → 取一个宏任务执行 → 再清空微任务"这个核心循环,再结合具体题目逐步推演,确保条理清晰。
更多推荐


所有评论(0)