node-mkdirp项目源码阅读

原文链接

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;
};
    原文作者:非常小贝
    原文地址: https://www.jianshu.com/p/4c6faa8cd13d
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞