node-mkdirp 项目源码阅读

发布于 2022-10-23 14:16:04 字数 3382 浏览 123 评论 0

node-mkdirp 是一个linux命令 mkdir -p 的 node 版本,也就是创建多级目录。node-mkdirp 值得新手学习的地方在于学习对于错误码的利用和基本的 API 使用。我曾经也写过一个创建多级目录的方法,不过自己都只是通过 split 方法对目录分隔开后逐层判断是否存在,再创建。node-mkdirp 的方式则是通过 fs.mkdir 的错误码来判断,挺巧妙的。

var path = require('path');
var fs = require('fs');
var _0777 = parseInt('0777', 8);

module.exports = mkdirP.mkdirp = mkdirP.mkdirP = mkdirP;

function mkdirP (p, opts, f, made) {
    // 如果opts是函数,则说明这是指定的回调,非函数且非对象则opt是指定的mode
    if (typeof opts === 'function') {
        f = opts;
        opts = {};
    }
    else if (!opts || typeof opts !== 'object') {
        opts = { mode: opts };
    }

    var mode = opts.mode;
    var xfs = opts.fs || fs;

    if (mode === undefined) {
        mode = _0777 & (~process.umask());
    }
    if (!made) made = null;

    var cb = f || function () {};
    p = path.resolve(p);

    // 尝试创建目录,mkdir创建一个不存在的目录时候会返回的错误码是ENOENT
    xfs.mkdir(p, mode, function (er) {
        // 无错误则表明创建的就是最后一级目录了
        if (!er) {
            made = made || p;
            return cb(null, made);
        }
        switch (er.code) {
            // 错误码是ENOENT表明无此文件或目录,则不断尝试创建父级目录
            case 'ENOENT':
                mkdirP(path.dirname(p), opts, function (er, made) {
                    // 无错误则继续尝试创建传入的目录,有错误则说明是已经存在,则直接执行回调
                    if (er) cb(er, made);
                    else mkdirP(p, opts, cb, made);
                });
                break;

            // In the case of any other error, just see if there's a dir
            // there already.  If so, then hooray!  If not, then something
            // is borked.
            // 出现其他错误主要是目录存在,则获取stat
            default:
                xfs.stat(p, function (er2, stat) {
                    // if the stat fails, then that's super weird.
                    // let the original error be the failure reason.
                    if (er2 || !stat.isDirectory()) cb(er, made)
                    else cb(null, made);
                });
                break;
        }
    });
}

mkdirP.sync = function sync (p, opts, made) {
    if (!opts || typeof opts !== 'object') {
        opts = { mode: opts };
    }

    var mode = opts.mode;
    var xfs = opts.fs || fs;

    if (mode === undefined) {
        mode = _0777 & (~process.umask());
    }
    if (!made) made = null;

    p = path.resolve(p);

    // 同步版本类似于异步版本的处理,不过需要使用try...catch...来捕捉错误
    try {
        xfs.mkdirSync(p, mode);
        made = made || p;
    }
    catch (err0) {
        switch (err0.code) {
            case 'ENOENT' :
                made = sync(path.dirname(p), opts, made);
                sync(p, opts, made);
                break;

            // In the case of any other error, just see if there's a dir
            // there already.  If so, then hooray!  If not, then something
            // is borked.
            default:
                var stat;
                try {
                    stat = xfs.statSync(p);
                }
                catch (err1) {
                    throw err0;
                }
                if (!stat.isDirectory()) throw err0;
                break;
        }
    }

    return made;
};

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

0 文章
0 评论
22 人气
更多

推荐作者

lorenzathorton8

文章 0 评论 0

Zero

文章 0 评论 0

萧瑟寒风

文章 0 评论 0

mylayout

文章 0 评论 0

tkewei

文章 0 评论 0

17818769742

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文