2014-03-31 48 views
8

如何在Bluebird中使用Promise包裝Node.js回調?這是我想出了,但想知道是否有更好的辦法:使用Bluebird在承諾中包裝Node.js回調

return new Promise(function(onFulfilled, onRejected) { 
    nodeCall(function(err, res) { 
      if (err) { 
       onRejected(err); 
      } 
      onFulfilled(res); 
     }); 
}); 

有一個更清潔的方式來做到這一點,如果只需要返回一個錯誤?

編輯 我試圖使用Promise.promisifyAll(),但結果沒有傳播到then子句。我的具體例子如下所示。我使用兩個庫:a)sequelize,它返回承諾,b)supertest(用於測試http請求),它使用節點樣式回調。以下是不使用promisifyAll的代碼。它調用sequelize來初始化數據庫,然後發出HTTP請求來創建訂單。 Bosth的console.log報表打印正確:

var request = require('supertest'); 

describe('Test', function() { 
    before(function(done) { 
     // Sync the database 
     sequelize.sync(
     ).then(function() { 
      console.log('Create an order'); 
      request(app) 
       .post('/orders') 
       .send({ 
        customer: 'John Smith' 
       }) 
       .end(function(err, res) { 
        console.log('order:', res.body); 
        done(); 
       }); 
     }); 
    }); 

    ... 
}); 

現在我嘗試使用promisifyAll,這樣我可以鏈則呼籲:

var request = require('supertest'); 
Promise.promisifyAll(request.prototype); 

describe('Test', function() { 
    before(function(done) { 
     // Sync the database 
     sequelize.sync(
     ).then(function() { 
      console.log('Create an order'); 
      request(app) 
       .post('/orders') 
       .send({ 
        customer: 'John Smith' 
       }) 
       .end(); 
     }).then(function(res) { 
      console.log('order:', res.body); 
      done(); 
     }); 
    }); 

    ... 
}); 

當我到了第二的console.log的res參數未定義。

Create an order 
Possibly unhandled TypeError: Cannot read property 'body' of undefined 

我在做什麼錯了?

+1

可能重複[?如何將現有的回調API來承諾(http://stackoverflow.com/questions/22519784/how-do-i-convert- an-existing-callback-api-promises) – Bergi

+0

請參閱我編輯的答案(評論通知) – Esailija

+0

您已將'.then'鏈接到不返回任何內容的'.then'。您的原始問題是重複的,您的編輯僅僅是正確使用'.then'處理程序。 –

回答

8

你沒有調用承諾返回版本,也沒有返回它。

試試這個:

// Add a return statement so the promise is chained 
    return request(app) 
      .post('/orders') 
      .send({ 
       customer: 'John Smith' 
      }) 
      // Call the promise returning version of .end() 
      .endAsync(); 
+0

太棒了!這解決了我的問題。有一個小故障。對'request(app)'的調用實際上返回一個Test對象(參見https://github.com/visionmedia/supertest/blob/master/index.js#L19-34)。所以我不得不將promisify調用改爲'Promise.promisifyAll(request.Test.prototype)'。幸運的是,request.Test被暴露了。如果不是,我應該怎麼做?另外,如果對象的所有方法都不打算進行回調,或者回調是可選的?在這些情況下使用promisifyAll()是否安全?謝謝你的幫助。 – Naresh

+0

@Naresh如果該類不會被暴露,你可以執行'Promise.promisifyAll(request()。constructor.prototype)'(在任何代碼之外,它只需要在應用程序的整個生命週期中進行一次) – Esailija

+0

@Naresh如果你沒有給他們打電話,那麼這種功能並不重要。如果你調用'someMethodAsync()'而someMethod不是回調函數,它只會引起奇怪的錯誤 - 但爲什麼你會調用'someMethodAsync()'知道someMethod不是回調函數? :P – Esailija