使用JS链接承诺的正确方法

时间:2013-02-01 21:02:19

标签: javascript node.js promise deferred fs

任务如下。我需要使用fs2库中的rmdir删除文件夹及其内容。它返回deffered promise对象。完成后我需要再次创建文件夹。并且函数应该返回承诺以进一步链接。

我现在的代码是这样的:

function clearOutputDir() {
    var def = deferred();
    var def2 = deferred();

    if (fs.existsSync(outputFolder)) {
        def.resolve(fs2.rmdir(outputFolder, {recursive: true, force: true}));
    } else {
        def.resolve();
    }

    def2.resolve(def.promise.then(function () {
        return deferred.promisify(fs.mkdir)(outputFolder);
    }));

    return def2.promise;
}

看起来很有效,但它太难看了。没有def和def2可以更简单吗?

2 个答案:

答案 0 :(得分:2)

首先,没有必要自己创建未解决的promises,使用fs2函数返回的更清晰,“然后”它们,Plynx解决方案在这种情况下是很好的暗示

其次,由于事物的异步性(以及文件系统函数内部如何工作),你不应该使用 fs.exists 函数,它通常被弃用,好主意是不使用它根本不做,而是直接做你想做的事情,并依赖最终的错误代码。 请参阅:https://groups.google.com/forum/?fromgroups=#!topic/nodejs/gRRuly79oRc它为此提供了更多信息。

获得解决方案: 除了宣传 fs.mkdir 之外,您还可以使用fs2中的mkdir,因为除非提供自定义选项,否则它与 fs.mkdir 完全相同(后备),并执行什么操作你想要,回报承诺。

function clearOutputDir(outputFolder) {
    return fs2.rmdir(outputFolder, { recursive: true, force: true }).then(null, function (e) {
         // Ignore "No such dir" error, otherwise propagate further
         if (e.code === 'ENOENT') return null;
         throw e;
     }).then(fs2.mkdir.bind(fs2, outputFolder));
}
仅当 fs2.rmdir 成功或dir不存在时,

fs2.mkdir 才会运行。我使用 bind 将其传递给 outputFolder ,它具有与以下相同的效果:

function clearOutuputDir(outputFolder) {
    ...
    }).then(function () { return fs2.mkdir(outputFolder); });
}

如果你决定使用 promisify ,那么重用promisified版本总是更好,并且不要在每次函数调用时创建它:

var mkdir = deferred.promisify(fs.mkdir);
function clearOutputDir(outputFolder) {
    ...
   }).then(function () { return mkdir(outputFolder); });
}

答案 1 :(得分:1)

考虑将final-fs库用于此目的。看看它的链接示例 - 它非常干净。

它使用when库进行异步调用,因此几乎不可能陷入回调地狱。链接非常简单 - 通过在解析函数中返回Promise来完成。

代码看起来像这样:

var ffs = require('final-fs');

/**
 * @param {string} outputDir
 * @returns {Promise}
 */
function clearOutputDir(outputDir) {
    return ffs.exists(outputDir)
        .then(function (exists) {
            if (exists) {
                return ffs.rmdirRecursive(outputDir);
            }
        })
        .then(function () {
            return ffs.mkdir(outputDir);
        });
}