最近在外网看到了一道面试题:「请准确说出下面这段代码在 react@18 中各个 log 语句的打印顺序」
import { useEffect } from "react";
import { createRoot } from "react-dom/client";
export const App = ({ name }) => {
console.log("log:", 5);
Promise.resolve().then(() => {
console.log("log:", 6);
});
useEffect(() => {
console.log("log:", 7);
});
return (
<div>
<h1>Hello {name}!</h1>
<p>Start editing to see some magic happen :)</p>
</div>
);
};
const root = createRoot(document.getElementById("root"));
console.log("log:", 2);
root.render(<App name="StackBlitz" />);
console.log("log:", 3);
Promise.resolve().then(() => {
console.log("log:", 4);
});
setTimeout(() => {
console.log("log:", 1);
}, 0);
面试官还会接着做进一步的提问,连番拷打候选人:
-
先简单说说你的解题思路是什么;
-
上面代码中,假如把
setTimeout()
的调用放在了root.render()
之前,结果会发生改变吗?如果发生了改变,那最新的打印顺序是什么,为什么呢? -
从源码来看,effect 的 create 函数是在一个被调度的 callback 里面去执行的,为什么它还是会比
Promise.then()
的 callback 函数先执行? -
如果把
useEffect()
的调用放在子组件里面,然后<App >
组件再消费这个子组件,像这样:import { useEffect } from "react"; import { createRoot } from "react-dom/client"; const Child = () => { useEffect(() => { console.log("log:", 7); }); return null; }; export const App = ({ name }) => { console.log("log:", 5); Promise.resolve().then(() => { console.log("log:", 6); }); return ( <div> <h1>Hello {name}!</h1> <p>Start editing to see some magic happen :)</p> <Child /> </div> ); }; const root = createRoot(document.getElementById("root")); console.log("log:", 2); root.render(<App name="StackBlitz" />); console.log("log:", 3); Promise.resolve().then(() => { console.log("log:", 4); }); setTimeout(() => { console.log("log:", 1); }, 0);
结果会发生改变吗?
-
如果在
<App>
组件函数加一个超过5ms
的阻塞操作,结果会是怎么样?像这样:import { useEffect } from "react"; import { createRoot } from "react-dom/client"; function sleep() { const start = performance.now(); while (performance.now() - start < 10) { // block } } const Child = () => { useEffect(() => { console.trace(); console.log("log:", 7); }); return null; }; export const App = ({ name }) => { console.log("log:", 5); Promise.resolve().then(() => { console.log("log:", 6); }); sleep(); return ( <div> <h1>Hello {name}!</h1> <p>Start editing to see some magic happen :)</p> <Child /> </div> ); }; const root = createRoot(document.getElementById("root")); console.log("log:", 2); root.render(<App name="StackBlitz" />); console.log("log:", 3); Promise.resolve().then(() => { console.log("log:", 4); }); setTimeout(() => { console.log("log:", 1); }, 0);
那么最后打印结果是怎样的?打印顺序发生了变化了吗?相比于问题四,为什么会有这种变化?
在题目设计者看来,谁如果能够经受得住这五个问题的拷问,并且给出准确答案,谁就是 react 大师级别的人物。经过我的研究,我对此深信不疑。
不知道,有哪些大佬能够准确给出答案呢?