2017-07-30 142 views
0

我發現其他人詢問這個主題,但我沒有能夠讓我的承諾鏈按順序執行。有異步操作的承諾鏈沒有按順序執行

這裏是正在發生的基本再現:

function firstMethod(){ 

    dbHelper.executeQuery(queryParameters).then(result => { 

     if (result === whatIAmExpecting) { 

      return dbHelper.doDbOperation(secondQueryParameters)} 

     else { 

      throw new Error('An error occurred') 

     }}) 

     .then(doFinalOperation()) 
     .catch(error => { 

     }) 
} 

在上面的代碼doFinalOperation()的executeQuery後則()函數被調用之前被調用。

這裏的executeQuery()的實現:

function executeQuery(parameter) { 

    return new Promise((resolve, reject) => { 

     const queryToExecute = `SELECT * FROM parameter` 

     return mySqlConnection.query(queryToExecute).then((result) => { 

      resolve(result) 

     }).catch(error => { 

      reject(error) 
     }) 
    }) 

這裏是的mySqlConnection.query方法的實現:

function query(queryString){ 

return new Promise((resolve, reject) => 
    { 

    initConnection() 

    connection.connect() 

    require('bluebird').promisifyAll(connection) 

    return connection.queryAsync(queryString).then(function(results) { 

     connection.end(); 

     resolve(results) 

     }).catch(error => { 

       reject(error) 
      }) 
     }) 

好像我錯誤地實現了的executeQuery( ) 方法。 mySqlConnection.query中的數據庫操作是不同步的,我可以看到這是承諾鏈以預期順序停止發生的地方。

我的問題簡而言之:如何使我的承諾鏈順序執行,以及在前一個Promise調用resolve()或reject()之前如何停止執行then() )?

在此先感謝。

+0

你有沒有控制哪一個請求會首先被提供,所以除非你順序地提出請求,否則你不能說它們將以什麼順序完成。我想知道爲什麼你會希望他們按特定的順序完成。只要您沒有數據依賴性,並行執行就是最省時的策略。但是,你肯定有你的理由。 –

+0

要使事情順序進行,只有在前一個承諾完成(或失敗)後,才能啓動下一個請求。這將會非常緩慢,並且首先會破壞承諾的目的(一個簡單的順序代碼將完成相同的工作)。 –

+0

感謝您的回覆。只有在其他方法成功完成時才應調用doFinalOperation()方法,以便依賴於以前的操作,因此方法必須按順序調用。爲什麼會讓他們順利擊敗承諾的目的呢? –

回答

2

then預期的功能,但是你不小心執行它,而不是傳遞。更改:

then(doFinalOperation()) 

有:

then(doFinalOperation) 

現在會調用它(在適當的時間)的承諾實現,而不是 「你」。

如果你的函數需要參數傳遞,那麼您可以

(1)使用bind

then(doFinalOperation.bind(null, parameterOne, parameterTwo, parameterThree)) 

(2)使用函數表達式

then(_ => doFinalOperation(parameterOne, parameterTwo, parameterThree)) 
+0

感謝您的回覆。你的解決方案可以解決這個問題,但是由於實際的'doFinalOperation()'需要參數,所以它必須被稱爲'doFinalOperation(parameterOne,parameterTwo,parameterThree)',所以我不能在不調用它的情況下傳遞它。但是,如果我將它實現爲:'then(_ => {doFinalOperation(parameterOne,parameterTwo,parameterThree)})'那麼它就可以工作。我已經將其他答案標記爲正確,但我提出了你的答案。此解決方案也可能更好,因爲它需要更少的嵌套 –

+1

您可以使用'bind'綁定您的參數。查看更新。 – trincot

+0

感謝您的提示。知道 –

0

無論您.then()方法被調用的第一個異步操作...
應該是這樣的:

function firstMethod(){ 
    dbHelper.executeQuery(queryParameters).then(expectedResult => { 
     if (expectedResult === whatIAmExpecting) { 
     return dbHelper.doDbOperation(secondQueryParameters)} 
      .then(doFinalOperation()) 
      .catch(error => { 
      }; 
     } 
     else { 
     throw new Error('An error occurred') 
     }}) 
     .catch(error => { 
     }); 
} 
+0

'doFinalOperation()'應該是'doFinalOperation'嗎? –

+0

我不知道,但在第一個代碼塊中它是'.then(doFinalOperation())'... –

+0

感謝您的回覆。您的解決方案可以解決問題 –