2015-07-20 145 views
1

我正試圖在NodeJS中使用Bluebird或Q將某些回調轉換爲Promise,但是我沒有成功。 任何人都可以很好,給我一個例子如何將上面的代碼轉換爲承諾?NodeJS中的承諾

在此先感謝

阿德里安

function httpResponse(request, response) { 
    fs.readFile('views/main.ejs', 'utf-8', function readFile(error, file) { 
     if (error) { 
      response.writeHead(200, {"Content-Type": "text/plain"}); 
      response.write('EJS ERROR'); 
      response.end(); 
     } else { 
      // get domains data from db needed for main page 
      dbHandle.queryDB({}, "domains", function dbQueryDB(error, result) { 
       var ejsData = {name: "Cav"}; 
       if (error) { 
        response.write('DB ERROR'); 
        response.end(); 
       } else { 
        ejsData.domains = result; 
        // get machine type data from db needed for main page 
        dbHandle.queryDB({}, "type", function dbQueryDB(error, result) { 
         if (error) { 
          response.write('DB ERROR'); 
          response.end(); 
         } else { 
          ejsData.type = result; 
          //respond index.html 
          response.writeHead(200, {"Content-Type": "text/html"}); 
          response.end(ejs.render(file, ejsData)); 
         } 

        }); 
       } 


      }); 


     } 

    }); 
} 

回答

1

使用bluebird,看看在promisification section

基本上你會做這樣的事情:

var fs = require("fs"); 
Promise.promisifyAll(fs); 
Promise.promisifyAll(dbHandle); //do this globally if it is global, not every request! 

那麼你的代碼將是這樣的:

function httpResponse(request, response) { 
     fs.readFileAsync('views/main.ejs', 'utf-8') 
     //Special catch only for EJS errors. ONce past this point in the chain, will not hit again. 

     .then(function(file){ 
      return dbHandle.queryDBAsync({}, "domains"); 
     }) 
     .then(function(domains){ 
      ejsData.domains = domains; 
      return dbHandle.queryDBAsync({}, "type"); 
     }) 
     .then(function(types){ 
      ejsData.type = types; 
      response.writeHead(200, {"Content-Type": "text/html"}); 
      response.end(ejs.render(file, ejsData)); 
     }) 
     .catch(function(error){ 
      response.writeHead(200, {"Content-Type": "text/plain"}); 
      response.write('EJS ERROR'); //or DB errors, add some handling if the error message is important 
      response.end(); 
     }); 
    } 

我這些鏈接一起保持代碼更加平坦。你也可以嵌套承諾。但Promisification是與這裏建立圖書館的途徑。

編輯 要保持file在範圍內,請嘗試像這樣的Promise設置。請注意嵌套的Promise。

function httpResponse(request, response) { 
     fs.readFileAsync('views/main.ejs', 'utf-8') 
     //Special catch only for EJS errors. ONce past this point in the chain, will not hit again. 


     .then(function(file){ 
      return dbHandle.queryDBAsync({}, "domains") 
      .then(function(domains){ 
       ejsData.domains = domains; 
       return dbHandle.queryDBAsync({}, "type"); 
      }) 
      .then(function(types){ 
       ejsData.type = types; 
       response.writeHead(200, {"Content-Type": "text/html"}); 
       response.end(ejs.render(file, ejsData)); 
      }) 
     .catch(function(error){ 
      response.writeHead(200, {"Content-Type": "text/plain"}); 
      response.write('EJS ERROR'); //or DB errors, add some handling if the error message is important 
      response.end(); 
     }); 
    } 

另一種方法是追蹤Promise鏈外的file變量。當返回readFileAsync時,將result存儲爲file(您宣佈不在該獨家新聞中),然後您可以稍後使用它。

+0

感謝您的快速回答。 –

+0

順便說一下,我在「response.end(ejs.render(file,ejsData));」得到了「文件未定義」。我想這是因爲這不是一個閉包,因爲它不能看到文件變量。 –

+0

啊,這就是像這樣的鏈接承諾 - '.then()'變量超出範圍。我會爲你編輯我的答案,以展示如何減少嵌套,但保持範圍。 – clay