【问题标题】:Do something after all asynchronous, nested, $.each database calls are completed在所有异步、嵌套、$.each 数据库调用完成后做一些事情
【发布时间】:2020-02-19 18:53:24
【问题描述】:

我正在尝试在 1) 所有循环都完成并且 2) 这些循环中的所有数据库调用都完成之后运行一个函数。

我的数据库调用函数(segmentDatabaseCallstepDatabaseCall)都接受一些参数,解析一个 Promise 并在调用完成后发送数据。这是我的代码的(非常)简化版本:

let localData = {}

segmentDatabaseCall(argument) // Call the database
.then(segmentResult => { // Returns trip segments (array of objects)

  $.each(segmentResult, (segmentIndex, segmentValue) => { // For each trip segment...

    localData['something'] = segmentValue.something // Add some data to local data

    stepDatabaseCall(segmentValue.segment_id) // Call the database once per trip segment...
    .then(stepResult => { // Returns trip steps (array of objects)

      $.each(stepResult, (stepIndex, stepValue) => { // For each trip step...

        localData['something'][i]['something_else'] = stepValue.something_else // Add some data to local data

        // THIS DOESN'T WORK
        const segsDone = segmentIndex >= segmentResult.length - 1;
        const stepsDone = stepIndex >= stepResult.length - 1;
        if (segsDone && stepsDone) {
          // This if statement runs before all calls are finished 1 out of 3 times roughly
        }
      })
    })
  })
})

数据库调用:

function databaseCall (argument) {
    return new Promise((resolve, reject) => {
        $.ajax({
          url: $phpUrl,
          type: 'post',
            data: {
              'argument': argument      
            }
        })
        .done (function (data) {
            var resultJson = JSON.parse(data)
            resolve(resultJson)
        })
        .fail (function (error) {
            reject(error)
        })
    })
}

我已尝试使用答案 here,但它会在所有呼叫完成之前运行 3 次。我一定是少了个柜台吧?

我也认为有一种方法可以使用 Promise 映射来做到这一点,但我无法理解它。

【问题讨论】:

  • 如果 promisesCount 的数量与 loopsCount 的数量相同,则调用你的函数。
  • 看看jQuery的when()
  • @NawedKhan 我如何获得 promisesCount?
  • @epascarello 不确定 when() 如何处理嵌套循环中的承诺
  • 将它们推送到一个数组并与 when() 一起使用

标签: javascript jquery asynchronous promise each


【解决方案1】:

在 Rxjs 中有一个叫做 forkJoin 的东西。据我了解您的问题,您可以将其用于您的实施。

forkJoin(
      this._myService.makeRequest('Request One', 2000),
      this._myService.makeRequest('Request Two', 1000),
      this._myService.makeRequest('Request Three', 3000)
    )
    .subscribe(([res1, res2, res3]) => {
      this.propOne = res1;
      this.propTwo = res2;
      this.propThree = res3;
    });

阅读更多来自here

【讨论】:

    【解决方案2】:

    看到您已经在使用 JQuery,您可以使用 $.when 函数包装所有异步调用。

    这将允许您将所有 Promise 链接在一起,并使用单个 .done() 函数管理所有 Promise 的完成。

    https://api.jquery.com/jQuery.when/

    来自 JQuery 网站:

    $.when( $.ajax( "/page1.php" ), $.ajax( "/page2.php" ) ).done(function( a1, a2 ) {
      // a1 and a2 are arguments resolved for the page1 and page2 ajax requests, respectively.
      // Each argument is an array with the following structure: [ data, statusText, jqXHR ]
      var data = a1[ 0 ] + a2[ 0 ]; // a1[ 0 ] = "Whip", a2[ 0 ] = " It"
      if ( /Whip It/.test( data ) ) {
        alert( "We got what we came for!" );
      }
    });
    

    【讨论】:

    • $.when 将 Promise 作为其参数,对吧?我需要解决一个承诺,然后使用该解决方案中的数据来解决另一个承诺。我不太明白在这种情况下如何设置 $.when 方法
    • 使用 $.when 将需要你重构你的逻辑相当多。如果您想快速获胜,您可能需要考虑同步运行您的 ajax 请求,例如在 $.ajax 上将 async 属性设置为 false。这将强制循环中的 ajax 请求在迭代到下一个项目之前等待结果,这应该会产生您正在寻找的结果。
    • 不幸的是,有太多的呼吁。最终对数据库进行了更改,这使得这个没有实际意义,但如果有人偶然发现这一点,我认为创建一个承诺数组,然后使用 Promises.all() 检查它们将是可行的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 1970-01-01
    • 1970-01-01
    • 2014-12-14
    • 1970-01-01
    • 2018-07-24
    相关资源
    最近更新 更多