2014-01-14 88 views
3

我開始在我的NodeJS項目中使用承諾,並遇到問題。在閱讀Promises/A +規範並搜索了很多內容之後,我沒有找到一個很好的解決方案,我需要訪問在承諾鏈中生成的值。在我的示例中,我想檢查圖像是否創建時發生錯誤,如果是,我想刪除它。NodeJS Promise(Q) - 如果承諾失敗,如何獲得價值?

代碼:

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

我認爲將imagePath保存到某處可能最簡單,或者在失敗塊內再次調用makeImage。 –

+0

makeImage是一個非常昂貴的方法 - 所以這是不可能的。我正在尋找一個不同的解決方案,而不是保存在一個臨時變量=) – stahlstift

回答

4

我推薦這種方法:

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

非常感謝Kris Kowal。對於Q和你的幫助=) – stahlstift

+0

當然'Q.fcall.then(路徑){...});'是無效的JavaScript;有一個缺少的功能('(在兩個地方)。 –

0

相反的:

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

你可以返回一個包含兩個錯誤和附加數據的對象,你在錯誤處理程序所需要的,就像這樣:

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

然後你可以通過err.data.imgPath裏面的deleteImageIfPresent函數訪問imgPath。

您可能會想要處理在第三方庫中創建的錯誤。您可以在一個錯誤處理程序中捕獲它們,並重新拋出錯誤,並顯式拒絕包裝在對象中並添加所需的數據。


另外,作爲一個方面說明,有在承諾/ A +無.fail。使用:

promise.then(onFulfilled, onRejected); 

不是技術上的錯誤,但自從你提到它。

+0

在Q是一種失敗的方法,但感謝您的信息。我會明天檢查你的解決方案=) – stahlstift