动手做Get your hands on it
练习跟着课文走 —— 每节课尾都有本课的练习。这一页是全部练习的总库,想集中刷题的时候来。 每个练习都写清了它来自哪一节,卡住了就回去看那一节。Practice follows the lessons — every lesson ends with the exercises for that lesson. This page is the whole library, for when you want to drill in one sitting. Each exercise names the lesson it came from, so you can go back when you stall.
练习Exercises
筛出 148 个练习 · 第 5 / 13 页。Showing 148 · page 5 / 13.只给签名。这是 Q2 的完整答案,写对了这道题就通了。 写完可以在本机 npm run q2 验证。
You get only the signature. This is the complete answer to Q2: get it right and the question is done. When you finish you can check it here with npm run q2.
- 同一时刻最多 limit 个任务在运行At most limit tasks are running at the same time
- 某个任务结束后,立刻启动下一个(不是等一批都结束)As soon as one task finishes, start the next one (do not wait for a whole batch)
- 任何任务失败都不能让整体抛错No failing task may make the whole call throw
- 返回数组的顺序必须与 tasks 一致The order of the returned array must match tasks
- 成功写 { status: "fulfilled", value },失败写 { status: "rejected", reason }On success write { status: "fulfilled", value }; on failure write { status: "rejected", reason }
看答案之前,先确认你已经自己动手写过一遍。看懂别人的答案和自己写出来,是两种能力。Before you open this, make sure you have written it yourself once. Following someone else's answer and producing your own are two different skills.
跑 npm run q2,没有报错,但一行task N START 都没有,直接就出结果了 —— 而且结果里的 value 长得很奇怪。
You run npm run q2. Nothing reports an error, but not one task N START line appears; the results come out right away. And the value in each result looks strange.
四个空。第 2 个是「只改一个字段」的写法,第 4 个考的是 「全选」和「反选」的区别。
Four blanks. The second is how you change one field only. The fourth is about the difference between select-all and invert-selection.
已有 todos 和 filter 两个 state。 写出可见列表和「清除已完成」,注意筛选态下的写操作该作用于谁。
You already have the two states todos and filter. Write the visible list and the clear-completed action, and think about which list a write should act on while a filter is on.
- visible 是派生数据,不许用 useState 或 useEffectvisible is derived data: no useState and no useEffect
- filter 为 "all" 时显示全部,"active" 显示未完成,"done" 显示已完成When filter is "all" show everything, "active" shows the unfinished ones, "done" shows the finished ones
- clearDone 移除所有已完成项,保留未完成项clearDone removes every finished item and keeps the unfinished ones
- 写操作必须作用于 todos,不能作用于 visibleA write has to act on todos, never on visible
- 不许修改原数组Do not change the original array
看答案之前,先确认你已经自己动手写过一遍。看懂别人的答案和自己写出来,是两种能力。Before you open this, make sure you have written it yourself once. Following someone else's answer and producing your own are two different skills.
三个空,全在这九行里。第 2 个空漏了会「越跳越快」, 第 3 个空写错会「卡在 1 不动」。
Three blanks, all within these nine lines. Miss the second and the clock speeds up with every start. Get the third wrong and the display freezes at 1.
两个 state、一个 effect、一个 reset、一个 mm:ss 格式化。 检查器会专门查清理函数和函数式更新。
Two states, one effect, one reset, and one mm:ss formatter. The checker looks specifically for the cleanup function and the updater form.
- format(65) 要返回 "01:05",个位数补零format(65) has to return "01:05", padding single digits with a zero
- 点 Start 开始每秒加一,点 Pause 停下并保留当前值Start begins adding one per second; Pause stops and keeps the current value
- Reset 停下来并清零(按钮文字回到 Start)Reset stops and goes back to zero (the button text returns to Start)
- effect 必须返回清理函数清掉定时器The effect has to return a cleanup function that clears the interval
- 必须用函数式更新,避免过期闭包Use the updater form, so there is no stale closure
- 按钮文字:跑着显示 Pause,停着显示 StartButton text: Pause while running, Start while stopped
看答案之前,先确认你已经自己动手写过一遍。看懂别人的答案和自己写出来,是两种能力。Before you open this, make sure you have written it yourself once. Following someone else's answer and producing your own are two different skills.
点了几次 Start / Pause 之后,秒数开始一次跳好几秒。 下面是真实的测试输出。
After a few clicks of Start and Pause, the seconds start jumping several at a time. Below is the real test output.
四个空。第 1 和第 4 个合起来解决竞态,第 2 个是 fetch 的经典坑。
Four blanks. The first and the fourth together settle the race. The second is the classic fetch trap.
三个 state 已给好。写出 effect 和三个提前返回。 检查器会查 res.ok、清理函数、竞态防护和 AbortError 过滤。
The three states are given. Write the effect and the three early returns. The checker looks for res.ok, the cleanup function, the race protection and the AbortError filter.
- 从 /api/users/{userId} 取数Fetch from /api/users/{userId}
- 非 2xx 响应要当成错误处理,错误信息形如 HTTP 404Treat any non-2xx response as an error, with a message like HTTP 404
- userId 变化时重新取数,并把上一次的结果作废(竞态防护)Refetch when userId changes, and void the previous result (race protection)
- 用 AbortController 掐掉在途请求,但 AbortError 不展示给用户Use AbortController to cut off the request in flight, but never show AbortError to the user
- 渲染顺序:loading → error → 空数据 → 正常数据Render order: loading, then error, then no data, then the data
- effect 本身不能是 async 函数The effect itself must not be an async function
看答案之前,先确认你已经自己动手写过一遍。看懂别人的答案和自己写出来,是两种能力。Before you open this, make sure you have written it yourself once. Following someone else's answer and producing your own are two different skills.
快速点两个用户,界面最后显示的是先点的那个。 慢一点点就没问题。控制台干净。
Click two users quickly and the screen ends up showing the one you clicked first. Click a little slower and it is fine. The console is clean.
四个空。第 2 个是递归调用本身,第 4 个是「往下一层」。
Four blanks. The second is the recursive call itself, and the fourth is one level further down.
这是这道题真正的难点。目标节点可能在任意深度, 要返回一棵新树,而且原树一个字节都不能改。
This is the hard part of the question. The target node can be at any depth, you have to return a new tree, and not one byte of the original may change.
- 找到 id === parentId 的节点,把 reply 追加到它的 replies 末尾Find the node whose id === parentId and append reply to the end of its replies
- 返回新数组、新节点对象,不修改原数据Return a new array and new node objects, without changing the original data
- 目标可能在任意深度,需要递归往下找The target can be at any depth, so recurse downwards to find it
- 不许用 JSON.parse(JSON.stringify(...)) 深拷贝Do not deep-copy with JSON.parse(JSON.stringify(...))
- 不许用 push / splice / 直接赋值Do not use push / splice / direct assignment
看答案之前,先确认你已经自己动手写过一遍。看懂别人的答案和自己写出来,是两种能力。Before you open this, make sure you have written it yourself once. Following someone else's answer and producing your own are two different skills.