1. 为什么“看任务列表”这件事值得单独拎出来讲但凡用 Yarn 跑过稍大一点的项目你大概率遇到过这种场景终端里敲下yarn dev或者yarn build屏幕开始哗哗刷日志然后你去倒了杯水回来发现——忘了刚才到底跑了几个任务、哪个任务卡住了、哪个任务还在后台占着资源。尤其是 monorepo 里动辄十几个 workspace 同时启动或者用concurrently、npm-run-all这类工具并行跑脚本的时候任务列表的管理就变成了一个很实际的问题。“命令查看 yarn 当前任务列表”这个标题表面上看是在问一条命令但它背后真正指向的是三件事第一Yarn 本身有没有原生的任务查看能力第二如果没有我们怎么通过系统层面的手段把正在跑的 Yarn 进程和脚本任务捞出来第三在 monorepo 和并行脚本的场景下怎么快速判断哪个任务还活着、哪个已经挂了、哪个在偷偷吃 CPU。这篇文章适合所有日常用 Yarn 做包管理和脚本编排的人看——不管你是刚接触前端工程化的新手还是已经在维护多包仓库的老手。我会从 Yarn 的进程模型讲起把“查看任务列表”这件事拆成几个层次Yarn 自己提供了什么、操作系统层面能看到什么、脚本编排工具又额外给了什么最后给出一套我自己在用的排查流程和速查表。全程都是可以直接复制粘贴的操作不玩虚的。需要先说明一点Yarn 从 1.x 到 2/3/4也就是 Berry 系列在进程管理上的行为差异很大很多网上流传的命令在 Berry 下根本不适用。所以下面我会把版本差异单独拎出来讲避免你照着老教程操作却查不到东西。2. Yarn 的进程模型与任务本质拆解2.1 Yarn 到底“跑”了什么要查看任务列表先得搞清楚 Yarn 执行一条脚本时底层发生了什么。当你敲下yarn buildYarn 做的事情大致是读取package.json里的scripts字段找到build对应的命令字符串然后通过一个 shell 去执行它。在类 Unix 系统上这个 shell 通常是/bin/shYarn 1.x 默认行为在 Windows 上则是cmd.exe。关键点在于Yarn 本身并不是一个常驻的守护进程。它执行完脚本就退出了不会像 Docker 那样维护一个“容器列表”。所以严格来说Yarn 没有“当前任务列表”这种概念——它没有状态存储没有后台调度器也没有一个可以查询的 API。你看到的“任务”本质上就是操作系统里正在运行的进程树。这就解释了为什么很多人搜“yarn 查看任务列表”会失望因为官方文档里根本没有这条命令。真正能查的是操作系统层面的进程信息以及脚本编排工具自己维护的状态。2.2 Yarn 1.x 与 Berry 的进程行为差异Yarn 1.x 在执行脚本时会 fork 一个子进程来跑命令父进程等待子进程结束。如果你用ps去看能看到一个node进程Yarn 自己下面挂着一个sh进程sh下面才是真正的构建工具进程。这个层级关系很重要因为它决定了你用pkill或者kill的时候到底杀的是哪一层。Yarn Berry2.x 及以上改了不少东西。它默认不再依赖系统的sh而是用一个内置的 shell 解释器基于shell-quote之类的实现来解析脚本。这意味着进程树的结构可能和 1.x 不一样某些情况下你看到的子进程会少一层。另外 Berry 引入了yarn run的插件机制理论上可以通过插件扩展出任务查看能力但官方并没有提供现成的“列出运行中任务”的插件。提示如果你在 Berry 项目里执行yarn run不带参数它列出的是package.json里定义的所有脚本而不是“正在运行的任务”。这两个概念经常被混淆注意区分。2.3 “任务列表”的三种理解层次我把“查看 yarn 当前任务列表”拆成三个层次方便你按需选择静态脚本列表package.json里定义了哪些脚本用yarn run或yarn run --json就能看。这是“有哪些任务可以跑”不是“正在跑什么”。动态进程列表当前系统里有哪些 Yarn 相关的进程在运行用ps、pgrep、top等系统工具查看。这是最接近“当前任务列表”的答案。编排工具状态如果你用concurrently、npm-run-all、turbo、nx这类工具跑多任务它们各自有日志前缀和状态输出能告诉你哪个子任务在跑、哪个已退出。大部分人的真实需求落在第二层和第三层之间。下面我就按这个顺序展开。3. 系统层面查看 Yarn 运行任务的实操方法3.1 用 ps 和 pgrep 精准捞出 Yarn 进程最直接的办法是用ps配合grep。但直接ps aux | grep yarn有个经典坑grep自己也会出现在结果里。所以更稳妥的写法是ps aux | grep -E [y]arn|[n]ode.*scripts方括号的写法是让grep匹配yarn但自身命令行里显示的是[y]arn从而不被自己匹配到。这个技巧在排查进程时非常常用。如果你只想要进程 ID用pgrep更干净pgrep -af node-a显示完整命令行-f匹配整个命令行而不只是进程名。这样你能看到类似node /path/to/yarn.js run build这样的完整信息一眼就能判断是哪个脚本。实测下来在 Yarn 1.x 项目里一个正在跑的yarn build通常会呈现为两层一层是node .../yarn.js build另一层是它 fork 出来的sh -c ...。如果你用pgrep -af yarn可能只抓到第一层漏掉真正干活的子进程。所以更推荐按node来抓再人工过滤。3.2 用 pstree 看清进程父子关系ps是平铺的进程多了就看不清谁是谁的子进程。这时候pstree就派上用场了pstree -p $(pgrep -f yarn.js | head -1)这条命令会以第一个 Yarn 进程为根把整棵进程树画出来每个节点带 PID。你能清楚看到yarn - sh - node - esbuild这样的链路。对于判断“某个任务是不是卡在子进程上”特别有用。如果系统里没装pstree可以用ps的--forest选项替代ps -ef --forest | grep -A 20 yarn--forest会用 ASCII 字符画出层级效果类似。注意-A 20是显示匹配行之后的 20 行具体数字按你的进程深度调整。3.3 用 top 和 htop 观察资源占用进程列表只能告诉你“谁在跑”但判断“谁卡住了”往往要看 CPU 和内存。top是标配但交互式操作对脚本不友好。非交互式抓一次快照可以这样top -b -n 1 | head -30-b是批处理模式-n 1表示只刷新一次。这样输出可以直接管道给其他命令处理。htop更直观支持树形视图和颜色标记。启动后按F5切到树形模式再按F4输入yarn过滤就能看到所有 Yarn 相关进程及其资源占用。我个人的习惯是先用htop扫一眼有没有 CPU 长期 100% 或者内存暴涨的进程再用pstree定位它属于哪个任务。注意在容器环境比如某些 CI 或开发容器里top和htop看到的进程可能被限制在容器的 PID namespace 内宿主机上的其他进程看不到。这是正常现象不是命令失效。3.4 跨平台差异Windows 下怎么查Windows 上没有ps和pgrep对应的是tasklist和wmic。查看 Node 相关进程tasklist | findstr node想要更详细的命令行信息用 PowerShellGet-CimInstance Win32_Process -Filter Namenode.exe | Select-Object ProcessId, CommandLine这条命令会列出所有 Node 进程的 PID 和完整命令行效果等价于 Linux 下的pgrep -af node。如果你在 Windows 上用 Git Bash 或 WSL那就可以直接用前面 Linux 的那套命令因为 WSL 本身就是一个 Linux 环境。4. 脚本编排工具下的任务列表查看4.1 concurrently 的日志前缀与状态判断concurrently是前端项目里最常见的并行脚本工具。它的典型用法是{ scripts: { dev: concurrently \yarn dev:web\ \yarn dev:api\ } }跑起来之后每个子任务的输出都会带一个彩色前缀比如[web]、[api]。这个前缀就是你的“任务列表”——哪个前缀还在刷日志哪个任务就还活着某个前缀突然不输出了要么是任务结束了要么是卡住了。concurrently还支持--names自定义前缀名以及--prefix-colors指定颜色。我一般会这样配置concurrently --names WEB,API,DB --prefix-colors cyan,magenta,yellow yarn dev:web yarn dev:api yarn dev:db这样一眼就能区分三个任务。如果某个任务挂了concurrently默认会等所有任务结束才退出但你可以加--kill-others-on-fail让它在任一任务失败时立刻杀掉其他任务避免僵尸进程堆积。4.2 npm-run-all 的并行与串行状态npm-run-all提供了run-p并行和run-s串行两个命令。它的输出相对简洁不会给每个任务加彩色前缀但会在任务开始和结束时打印状态行比如 run-p dev:web dev:api以及每个子任务的$ yarn dev:web。查看“当前任务列表”在npm-run-all场景下主要靠观察哪些子任务的输出还在继续。它没有提供一个“列出运行中任务”的命令但你可以结合系统层面的ps来交叉验证。我通常的做法是先看终端里哪些任务还在刷日志再用pgrep -af node确认对应的进程确实存在。4.3 turbo 和 nx 的任务面板如果你用的是turbo或nx这类现代 monorepo 工具它们对任务状态的管理要完善得多。turbo在跑turbo run dev时会给每个 package 的任务分配一个独立的输出区域并在任务完成时打印耗时和缓存命中情况。nx则有nx graph和nx show projects之类的命令来查看项目结构运行时的任务状态则通过终端输出和--output-style控制。这两个工具本质上都是“任务编排器”它们自己维护了一份任务状态所以查看“当前任务列表”最靠谱的方式就是看它们的终端输出。turbo还支持--dry-run预览将要执行的任务列表这个在调试配置时非常有用turbo run build --dry-run它会列出所有会被执行的任务及其依赖关系但不真正执行。这算是“静态任务列表”的一种高级形态。5. 一套可复用的任务排查流程与速查表5.1 从“感觉卡住了”到定位问题的四步法我在实际项目里总结了一套排查流程基本能覆盖 90% 的“任务列表看不清”场景看终端前缀如果用了concurrently或turbo先看哪个前缀不再输出。这是最快的初筛。抓进程快照执行pgrep -af node看还有哪些 Node 进程活着命令行里带的是哪个脚本。画进程树用pstree -p PID或ps -ef --forest看父子关系确认卡住的是 Yarn 本身还是它 fork 出来的子进程。看资源占用用top -b -n 1或htop看 CPU 和内存判断是死锁、死循环还是单纯在等 I/O。这四步走下来基本能判断出是哪个任务出了问题以及问题是出在脚本逻辑、依赖安装还是系统资源上。5.2 常见问题速查表现象可能原因排查命令处理方式yarn run列出的脚本和预期不符看的是静态脚本列表不是运行中任务yarn run --json改用pgrep -af node查动态进程ps aux | grep yarn结果里有 grep 自己grep 匹配到了自身命令行ps aux | grep [y]arn用方括号技巧排除自身进程列表里只有 yarn 没有子进程子进程已退出或 Yarn 在等待pstree -p PID检查脚本是否卡在输入等待Windows 下查不到命令行tasklist 默认不显示命令行Get-CimInstance Win32_Process用 PowerShell 替代容器里看不到宿主机进程PID namespace 隔离ps aux在容器内执行属正常现象进容器内查任务结束后进程仍残留子进程未被正确回收pgrep -af node用pkill -P PID清理子进程5.3 几个我踩过的坑第一个坑是误杀父进程导致子进程变孤儿。有次我用kill杀掉了 Yarn 主进程以为任务就停了结果构建工具的子进程还在后台跑继续占着端口。后来学乖了杀之前先用pstree看清楚层级优先杀最底层的实际工作进程或者用pkill -P PID按父进程 ID 批量清理子进程。第二个坑是在 Berry 项目里套用 1.x 的命令。Berry 的yarn run行为和 1.x 有差异某些在 1.x 下能用的--silent、--verbose参数在 Berry 下含义变了。查进程时如果只按yarn关键字抓可能抓不到 Berry 的进程因为它可能以node .yarn/releases/yarn-4.x.cjs的形式出现。所以按node抓再过滤更保险。第三个坑是忽略了 shell 层的包装。有些脚本里写了sh -c xxx yyy这时候进程树里会多一层shpstree看起来会多一个节点。如果不注意可能会误以为有两个任务在跑。实际上那只是同一个任务的不同执行阶段。6. 把“查看任务列表”变成日常习惯说到底Yarn 没有原生的“任务列表”命令这不是缺陷而是它的设计定位决定的——它是一个包管理器和脚本运行器不是一个进程管理器。真正要查看当前任务靠的是操作系统工具加编排工具的日志输出。把pgrep -af node、pstree -p、htop这几个命令用熟再结合concurrently的前缀和turbo的任务面板基本就能做到对项目里跑着什么一目了然。我个人的习惯是在package.json里加一个ps脚本把常用排查命令封装起来{ scripts: { ps: pgrep -af node || echo no node process } }这样敲yarn ps就能快速看一眼当前有哪些 Node 任务在跑。虽然简单但在多任务并行的时候比来回切终端窗口高效得多。另外如果你经常需要清理残留进程可以再配一个kill:node脚本用pkill -f yarn.js批量结束但用之前一定确认没有其他重要 Node 进程在跑免得误伤。