在 JS 中使用 Promise 链的正确方法

Posted

技术标签:

【中文标题】在 JS 中使用 Promise 链的正确方法【英文标题】:Proper way to use chain of promises with JS 【发布时间】:2013-01-17 06:40:42 【问题描述】:

任务如下。我需要使用 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 可以更简单吗?

【问题讨论】:

【参考方案1】:

首先,不需要自己创建未解决的承诺,使用 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.mkdir 只有在 fs2.rmdir 成功或 dir 不存在时才会运行。我已经使用 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); );

【讨论】:

谢谢。我喜欢最初的方法。认为我理解的问题是 .then 返回承诺。有了它,一切都变得足够清晰了。【参考方案2】:

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

它使用when 库进行异步调用,因此几乎不可能陷入回调地狱。链接非常简单 - 通过在 resolve 函数中返回 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);
        );

【讨论】:

以上是关于在 JS 中使用 Promise 链的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

JS ~ Promise 对象

在 Node.js 中编写非阻塞函数的正确方法

将已解决的承诺值传递到最终的“then”链的最佳方法是啥[重复]

在Node.js使用Promise的方式操作Mysql

手写一个Promise

JavaScript小技能:原型链的运作机制Promise链