2017-07-30 125 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

感谢您的回复。您的解决方案可以解决问题 –