Node.js 异步文件编程

Node.js 异步文件编程

Tags
文件系统
异步编程
CreatedTime
Aug 19, 2022 02:18 AM
Slug
2020-01-15-fs-async
UpdatedTime
Last updated August 19, 2022

问题描述

Q:使用异步接口,实现递归遍历查找指定文件
异步的优势:
  • 相较于同步接口,异步不阻塞主线程,速度更快。
  • 相较于await,也更快。尤其是只有一个任务在执行的时候,await虽是异步,但是同一个任务中,是按照指令顺序执行的。

设计解决思路

  • *异步的处理技巧是使用一个变量 asyncOps,标记当前正在进行的异步操作数量。**每次异步开始前,+1;结束后,-1。
  • *当一个异步操作完成后,需要检查是否所有异步都完成,完成则触发回调函数。**每次-1 后,检查 asyncOps 是否为 0,如果为 0,那么所有异步都完成,触发回调函数。
为了防止错误回调函数重复触发,使用一个变量进行标识。
// 递归查找文件 // 异步不阻塞主线程,速度更快 // 异步的处理技巧:使用一个变量asyncOps,标记当前正在进行的异步操作数量 // 每次异步开始前,+1;结束后,-1 // 每次-1后,检查asyncOps是否为0,如果为0,那么所有异步都完成,触发回调函数 const fs = require('fs') const join = require('path').join /** * * @param {RegExp} nameRe * @param {String} rootPath * @param {Function} callback */ function find(nameRe, rootPath, callback) { const results = [] let asyncOps = 0 let errored = false finder(rootPath) /** * 只触发一次 * @param {Error} err */ function handleError(err) { if (errored) return errored = true callback(err) } /** * @param {String} path */ function finder(path) { ++asyncOps fs.readdir(path, (err, files) => { if (err) return handleError(err) for (const file of files) { const fpath = join(path, file) ++asyncOps fs.stat(fpath, (err, stats) => { if (err) return handleError(err) if (stats.isDirectory()) { finder(fpath) } else if (stats.isFile() && nameRe.test(file)) { results.push(fpath) } --asyncOps // 回调设计遵循:错误优先 if (!asyncOps) callback(null, results) }) } --asyncOps if (!asyncOps) callback(null, results) }) } } module.exports.find = find

使用效果

const { find } = require('./async-find') const path = require('path') const rootPath = path.join( __dirname, '..', '..', 'algorithm' ) find(/better/, rootPath, (err, results) => { if (err) throw err console.log(results) })