2016-04-15 54 views
3

我想創建一個函數,該函數返回一個承諾,如果有內容拋出錯誤,則返回承諾拒絕。使用拋出承諾

function promiseFunc(options) { 
    return new Promise(() => { 
    return options; 
    }); 
} 

function myfunc(options) { 
    return new Promise(() => { 
    if (!options) throw new Error("missing options"); 

    return promiseFunc(options).then((result) => { 
     if (result.throwerr) throw new Error("thrown on purpose"); 

     return result.value; 
    }); 
    }); 
}; 

我的測試如下:

const myfunc = require("./myfunc"); 

describe('myfunc',() => { 
    it('should fail without options',() => { 
    return myfunc() 
     .then((result) => { throw new Error(result) }, (err) => { 
     console.log("test #1 result:", err.message === "missing options"); 
     }); 
    }); 

    it('should fail on options.throwerr',() => { 
    return myfunc({throwerr: true}) 
     .then((result) => {}, (err) => { 
     console.log("test #2 result:", err.message === "thrown on purpose"); 
     }); 
    }); 

    it('should return options.value',() => { 
    return myfunc({value: "some result", throwerr: false}) 
     .then((result) => { 
     console.log("test #3 result:", result === "some result"); 
     }, (err) => {}); 
    }); 
}); 

第一次測試通過,但第二和第三失敗。

日誌#2甚至沒有運行,所以我認爲「故意拋出」會弄亂某些東西,因此我創建了測試#3,在那裏我不扔任何東西,但仍然失敗。 我錯過了什麼?

解決方案:

function promiseFunc(options) { 
    return new Promise(resolve => { 
    return resolve(options); 
    }); 
} 

function myfunc(options) { 
    return new Promise((resolve, reject) => { 
    if (!options) throw new Error("missing options"); 

    return promiseFunc(options).then(result => { 
     if (result.throwerr) throw new Error("thrown on purpose"); 

     return resolve(result.value); 
    }).catch(err => { 
     return reject(err); 
    }); 
    }); 
}; 
+0

避免['Promise' constructor antipattern](http://stackoverflow.com/q/23803743/1048572)! – Bergi

回答

1

您忘記了傳遞一個帶有解析和拒絕參數的函數,因此您的promise不起作用。

function promiseFunc(options) { 
    return new Promise(resolve => { // resolve function 
    resolve(options) 
    }) 
} 

module.exports = function myfunc(options) { 
    return new Promise((resolve, reject) => { // since you may either resolve your promise or reject it, you need two params 
    if (!options) { 
     return reject(new Error("missing options")) 
    } 

    return promiseFunc(options).then(result => { 
     if (result.throwerr) { 
     return reject(new Error("thrown on purpose")) 
     } 
     resolve(result.value) 
    }) 
    }) 
} 

...和測試(摩卡)

const assert = require('assert'), 
     myfunc = require("./myfunc") 

describe('myfunc',() => { 
    it('should fail without options', done => { // mind the callback, promises are always async 
    myfunc() 
     .catch(err => { 
     assert(err.message === "missing options") 
     done() // <- called here 
     }) 
    }) 

    it('should fail on options.throwerr', done => { 
     myfunc({throwerr: true}) 
     .catch(err => { 
      assert(err.message === "thrown on purpose") 
      done() 
     }) 
    }) 

    it('should return options.value', done => { 
    return myfunc({value: "some result", throwerr: false}) 
     .then(result => { 
      assert(result === "some result") 
      done() 
     }) 
    }) 
}) 
+0

是的,它可以工作,但是如果在返回解析/拒絕之前在myfunc中引發錯誤呢? 順便說一句,摩卡doc說,如果你返回一個承諾,你不需要完成回調。 – user2252655

+0

在myfunc中,第一個罰球很好,只有嵌套的罰球會弄亂測試。 – user2252655

+0

不知道摩卡 - 謝謝。 關於承諾 - 它們會自動捕獲承諾主體內的所有未捕獲的錯誤。但是,最好使用拒絕回調而不是拋出錯誤。把它看作是一個控制結構,在這裏你可以執行兩個動作中的一個 - 如果出現錯誤(例如選項未定義),履行承諾或拒絕承諾 –

0

我想創建一個返回一個承諾的功能,如果發生內拋出一個錯誤,它返回承諾拒絕。

這將做到這一點...

var q = require('q'); // In recent versions of node q is available by default and this line is not required 

function iReturnAPromise(num) { 

    var def = q.defer(); 

    if (typeof num=== 'number') { 

     try { 
      var value = 100/num; 
      def.resolve(value); 
     } catch(e) { 
      def.reject("oops a division error - maybe you divided by zero"); 
     } 
    } else { 
     def.reject("o no its not a number"); 
    } 
    return def.promise; 
} 

PS這個功能進行編碼寫意尚未經過測試 - 但這會工作。顯然嘗試抓住應該謹慎使用。

PS我更喜歡使用promise的q庫實現,而不是默認的節點承諾庫 - 它們採用了非常不同的方法。 q免除所有的包裝!

+0

是否可以用原生Promise做到這一點? – user2252655

+0

是很有可能使用相同的邏輯與不同的語法!我還沒有使用原生諾言lib一段時間,我更喜歡q,所以不能查看它,我將把它留給你:) – danday74

+0

謝謝!我想排除任何外部庫,所以我想我必須繼續糾纏它:) – user2252655

0

使用承諾庫u想...

function iReturnAPromise(num) { 


return new Promise(function(resolve, reject) { 


    if (typeof num === 'number') { 

     try { 
      var value = 100/num; 
      resolve(value); 
     } catch (e) { 
      reject("oops a division error - maybe you divided by zero"); 
     } 
    } else { 
     reject("o no its not a number"); 
    } 

}) 

} 

iReturnAPromise(7).then(
    function(response) {console.log("success", response)}, 
    function(response) {console.log("failure", response)} 
); 

// Unexpectedly this is not an error in node 5.6 because div by 0 is not an error operation anymore! 
iReturnAPromise(0).then(
    function(response) {console.log("success", response)}, 
    function(response) {console.log("failure", response)} 
); 

iReturnAPromise("fred").then(
    function(response) {console.log("success", response)}, 
    function(response) {console.log("failure", response)} 
); 

你可以看到爲什麼我喜歡將q語法:)