简体   繁体   English

NodeJS Promise(Q) - 如果promise失败,如何获取值?

[英]NodeJS Promise (Q) - How to get a value if the promise fails?

I´m starting to use promises in my NodeJS projects and I run into a problem. 我开始在我的NodeJS项目中使用promises并遇到问题。 After I read the Promises/A+ spec and googling a lot I didn´t find a nice solution for the case that I need to access a value which gets produced in a promise chain. 在我阅读了Promises / A +规范和google搜索后,我找不到一个很好的解决方案,我需要访问一个在promise链中生成的值。 In my example I want to check when an error occurs if the image was created and if so, I want to delete it. 在我的示例中,我想检查何时创建图像时发生错误,如果是,我想删除它。

Code: 码:

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);

I recommend this approach: 我推荐这种方法:

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

Assuming you trust makeImage, removeImage, and doSomeCoolThings to return Q promises and never throw. 假设您信任makeImage,removeImage和doSomeCoolThings以返回Q promises并且永不抛出。 Otherwise, there's always Q.fcall which eliminates these concerns. 否则,总会有Q.fcall消除这些顾虑。

If you wish to retain the image in the success case, and only delete it if there's a failure, rethrowing the error: 如果您希望在成功案例中保留图像,并且仅在出现故障时将其删除,请重新抛出错误:

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

Also, instead of: 而且,而不是:

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

You can: 您可以:

return Q.resolve(x);

Instead of: 代替:

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

You could return an object containing both the error and additional data that you need in the error handler, like so: 您可以返回一个对象,其中包含错误处理程序中所需的错误和其他数据,如下所示:

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

Then you can access imgPath with err.data.imgPath inside deleteImageIfPresent function. 然后你可以在deleteImageIfPresent函数中使用err.data.imgPath访问imgPath。

You will probably want to handle errors created in 3rd party libraries. 您可能希望处理在第三方库中创建的错误。 You can catch them in one error handler and re-throw the error with an explicit reject wrapping in an object and adding the data you need. 您可以在一个错误处理程序中捕获它们,并使用显式拒绝包装在对象中并添加所需的数据来重新抛出错误。


Also as a side note, there is no .fail in Promises/A+. 另外作为旁注,Promises / A +中没有.fail。 Use: 使用:

promise.then(onFulfilled, onRejected);

Not technically an error but since you mentioned it. 从技术上讲,这不是错误,而是因为你提到它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM