【问题标题】:Need to make multiple Async calls before executing next step JS需要在执行下一步 JS 之前进行多次 Async 调用
【发布时间】:2016-06-21 20:29:43
【问题描述】:

我有一个数组,其中可以包含未知数量的索引。每个索引用于通过ajax 调用发送数据。我正在循环使用for loop 从成功调用中收集数据并将其推送到一个空数组中。在未知数量的调用结束时,我需要在我的视图中使用新收集的数组。 newDataArray 在循环完成之前在底部执行,因此它仍然是空的。如何完成所有呼叫然后执行底部的操作?

如果有帮助,我将在 React 中使用 Flux 模式执行此操作。但同样的问题可能不会在 React 中完成。这是我正在尝试做的模拟示例:

JS

case 'execute-calls':

    //This is the new array to push to
    var newDataArray = [];
    //Url to call
    var url = 'http://dev.markitondemand.com/Api/v2/Quote/jsonp';

    for(let i = 0; i < payload.data.length; i++){

        //given array of data that needs to be sent with call
        let symb = { symbol: payload.data[i]};
        $.ajax({
          data: symb,
          url: url,
          dataType: "jsonp",
        })
          .done(function(data){
            let updatedData = {
              //...data that is stored from response
            };

            newDataArray.push(updatedData);
          })
          .fail(function(error){
            //console.log(error);
          });

      }

    //This will be updating the state object which is above the switch cases
    //However this is ran before the end of the loops so newDataArray is empty
    var updateTicker = {
        updatedTicker: true,
        updatedTickerSymbols: newDataArray
    };
    assign(stockData,updateTicker);
    getStockData.emitChange();

    break;

【问题讨论】:

    标签: javascript jquery reactjs flux


    【解决方案1】:

    您可以利用$.ajax() 实际上返回一个deferred object 的事实,并使用它来创建一个延迟数组。例如

    var symbols = [1, 2, 3, 4];
    
    var deferreds = symbols.map(function (symbol) {
      return $.ajax({
        url: 'http://dev.markitondemand.com/MODApis/Api/v2/Quote/jsonp',
        data: { symbol: symbol },
        dataType: 'jsonp'
      });
    });
    

    您可以使用$.when() 一次解决多个延迟问题。然而,有一个复杂之处,$.when() 需要一个参数列表而不是数组。我们可以使用Function#apply来解决这个问题。

    为了增加复杂性,回调函数还使用参数列表调用。由于我们不知道有多少参数,我们将使用arguments 伪数组。由于参数不是 实际 数组,我们将通过在 Array#prototype 上使用 Function#call 来循环遍历它。

    $.when.apply($, deferreds).done(function () {
      Array.prototype.forEach.call(arguments, function (response) {
        console.log(response[0].Message);
      });
    }).fail(function (jqXHR, textStatus, error) {
      console.error(error);
    });
    

    [更新以包括 fail() 调用]

    如果你使用的是 ES6,这会更优雅:

    $.when(...deferreds).done((...responses) => {
      responses.forEach((response) => {
        console.log(response[0].Message);
      });
    });
    

    【讨论】:

    • 这种方式似乎最直观。感谢您的回答。您如何查看响应中是否给出了错误?它将存储在其中一个索引中吗? $.when.apply($, deferreds).done(function (response) { 那里的控制台日志记录响应会显示错误?
    • 好点。还有一个失败回调。这将在遇到第一个错误时调用。我已经相应地更新了代码。
    【解决方案2】:

    当您处理 ajax 调用并且必须在所有异步调用结束时执行一些操作时,更好的选择是使用 Callback 函数。

    修改代码以使用回调,

     function AsyncLoopHandler(index) {
        if (index > payload.data.length) {
            // all the indexes have finished ajax calls do your next step here
    
            var updateTicker = {
                updatedTicker: true,
                updatedTickerSymbols: newDataArray
            };
            assign(stockData, updateTicker);
            getStockData.emitChange();
        }
        else {
            //given array of data that needs to be sent with call
            let symb = { symbol: payload.data[index] };
            $.ajax({
                data: symb,
                url: url,
                dataType: "jsonp",
            })
              .done(function (data) {
                  let updatedData = {
                      //...data that is stored from response
                  };
    
                  newDataArray.push(updatedData);
                  AsyncLoopHandler(index++); // call the function again with new index
              })
              .fail(function (error) {
                  //console.log(error);
              });
        }  
    }
    

    现在要启动这个递归函数,只需通过传递索引 0 来启动它。

      AsyncLoopHandler(0);
    

    因此,所有的 ajax 调用将一个接一个地执行,就好像它是一个同步请求一样,if 检查将查看所有索引是否完整,然后运行您的逻辑。让我知道这是否有帮助

    【讨论】:

      【解决方案3】:

      建议使用promise,逻辑喜欢

      var urls= [x,x,x,x];
      var results = [];
      var qs = $.map(urls,function(url){
        return function(){
          var deferred = Q.defer();
          $.ajax({
            success:function(){
              results.push(url)
              deferred.reslove();
            },error:function(){
              deferred.reslove();        
            }
          })
          return deferred;
        }
      })
      Q.all(qs).then(function(){
         console.log(results )
      });

      或在新标准中使用 yield 和 co

      https://github.com/kriskowal/q

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-11-14
        • 1970-01-01
        相关资源
        最近更新 更多