【问题标题】:NodeJS Promise (Q) - How to get a value if the promise fails?NodeJS Promise (Q) - 如果 promise 失败,如何获取值?
【发布时间】:2014-03-11 03:51:48
【问题描述】:

我开始在我的 NodeJS 项目中使用 Promise,但遇到了问题。在我阅读了 Promises/A+ 规范并进行了很多谷歌搜索之后,我没有找到一个很好的解决方案来解决我需要访问在 Promise 链中生成的值的情况。在我的示例中,如果创建了图像,我想检查何时发生错误,如果是,我想删除它。

代码:

var Q = require('Q');
var fs = require('fs');

// This produces the imgPath
function makeImage() {
    var deferred = Q.defer();
    deferred.resolve("path/to/image");
    return deferred.promise;
}

function watermark(imgPath) {
    var deferred = Q.defer();
    deferred.resolve(imgPath);
    return deferred.promise;
}

// This function fails
function doSomeCoolThings(imgPath) {
    var deferred = Q.defer();
    deferred.reject(new Error("System is exploded"));
    return deferred.promise;
}

var fileExists = Q.denodeify(fs.readFile);
var deleteFile = Q.denodeify(fs.unlink);

// How do I get the imgPath here?
function deleteImageIfPresent(err) {
    return Q.fcall(function () {
        return imgPath !== undefined;
    })
        .then(fileExists)
        .then(deleteFile);
}

var iKnowThatSolution;

makeImage()
    // Thats not what I want
    //.then(function(imgPath) {
    //    iKnowThatSolution = imgPath;
    //})
    .then(watermark)
    .then(doSomeCoolThings)
    .fail(deleteImageIfPresent);

【问题讨论】:

  • 我认为将 imagePath 保存在某处可能是最简单的,或者在失败块内再次调用makeImage
  • makeImage 是一种非常昂贵的方法 - 所以这是不可能的。我正在寻找与保存在临时变量中不同的解决方案 =)

标签: javascript node.js promise q


【解决方案1】:

我推荐这种方法:

return makeImage().then(function (path) {
    return doSomeCoolThings(path)
    .finally(function () {
        return removeImage(path);
    });
});

假设您信任 makeImage、removeImage 和 doSomeCoolThings 来返回 Q 承诺并且从不抛出。否则,总会有Q.fcall 消除这些顾虑。

如果你希望在成功的情况下保留图像,只有在失败时才将其删除,重新抛出错误:

return Q.fcall(makeImage).then(function (path) {
    return Q.fcall(doSomeCoolThings, path)
    .catch(function (error) {
        return Q.fcall(removeImage, path)
        .thenReject(error);
    });
});

还有,而不是:

var deferred = Q.defer();
deferred.resolve(x);
return deferred.promise;

你可以:

return Q.resolve(x);

【讨论】:

  • 非常感谢克里斯·科瓦尔。对于 Q 和您的帮助 =)
  • 肯定Q.fcall.then(path) {...}); 不是有效的javascript;缺少function((在两个地方)。
【解决方案2】:

代替:

deferred.reject(new Error("System is exploded"));

您可以在错误处理程序中返回一个包含错误和您需要的附加数据的对象,如下所示:

deferred.reject({
  error: new Error("System is exploded"),
  data: {
    imgPath: imgPath,
    ...
  }
});

然后您可以在 deleteImageIfPresent 函数中使用 err.data.imgPath 访问 imgPath。

您可能希望处理在 3rd 方库中创建的错误。您可以在一个错误处理程序中捕获它们,然后通过在对象中显式拒绝包装并添加您需要的数据来重新引发错误。


另外,Promises/A+ 中没有 .fail。使用:

promise.then(onFulfilled, onRejected);

从技术上讲不是错误,但既然你提到了它。

【讨论】:

  • 在 Q 中是一个失败的方法,但感谢您提供的信息。我明天会检查你的解决方案 =)
猜你喜欢
  • 1970-01-01
  • 2017-01-09
  • 2019-03-27
  • 2014-10-15
  • 1970-01-01
  • 2021-04-24
  • 1970-01-01
  • 2020-08-01
  • 1970-01-01
相关资源
最近更新 更多