Node.js中异步回调代码块执行顺序异常导致输出不符合预期问题
为什么回调块会在外部代码后执行?
这事儿的核心在于Node.js的异步非阻塞I/O模型,咱们一步步拆解你这段代码的执行过程就懂了:
- 首先,
fs.readdir本身是异步方法,它会把读取目录的任务交给操作系统线程池处理,主线程继续推进(这里咱们重点看它回调里的逻辑)。 - 当
fs.readdir的回调触发、拿到files列表后,进入for...in循环:- 每次循环调用
fs.readFile——这又是一个异步I/O操作。Node.js不会卡在这儿等文件读完,而是把读文件的任务扔给线程池,直接跳到下一行执行console.log(2)。 - 假设你的
files里有2个符合条件的文件(排除了portfolio.js),那循环会连续执行两次console.log(2),先输出2 2。
- 每次循环调用
- 等主线程把当前所有同步代码(也就是循环里的
console.log(2))执行完、空闲下来后,才会去处理事件队列里的异步任务。这时候线程池里的文件读取已经完成,对应的fs.readFile回调被依次触发,于是执行回调里的console.log(1),输出1 1。
简单说就是:异步I/O方法的回调不会阻塞主线程,会被放到任务队列里等主线程处理完当前同步代码后再执行,这就是你看到2先打印、1后打印的原因。
如果想要让1在2之前打印,你可以把console.log(2)放到fs.readFile的回调里(确保等文件读完再打印);如果想要严格按文件顺序依次执行1、2、1、2,可以用async/await把异步代码改成同步风格的写法,比如:
const fs = require('fs').promises; // 使用Promise版本的fs API async function processFiles() { const files = await fs.readdir("./my_stocks"); for (const file of files) { if (file !== 'portfolio.js') { const fn = `./my_stocks/${file}`; const data = await fs.readFile(fn); const arr = data.toString().split('\n'); console.log(1); await fs.appendFile("./my_stocks/portfolio.js", JSON.stringify(stock_detail)); console.log(2); } } } processFiles().catch(err => console.error(err));
这样就能保证每个文件的1打印后再输出2,顺序完全符合预期。
内容的提问来源于stack exchange,提问作者Avichal Jain
相关产品推荐
相关产品推荐

