替代async:false

时间:2017-10-27 17:16:16

标签: javascript ajax asynchronous promise

我需要在for循环中进行AJAX调用。我要求的是调用应该按顺序进行,因为我将响应存储在数组中,并且数组的元素应该按顺序存在。当我尝试在许多类似问题上提出多项建议时,我不得不去async: false。他们都没有工作。制作async: false是一个非常糟糕的想法我知道,但是有什么方法可以按顺序获得响应?

附加信息:我正在将数组映射到我的渲染元素,所以我尝试的方法很少给我错误,说“无法读取未定义的地图”。

以下是我目前正在做的事情:

auto_video_jobs_array = [];
        for (var i = 0; i < this.state.current_auto_video_jobs_urls.length; i++) {
            this.get_auto_video_jobs_array(i)
        }

get_auto_video_jobs_array(i) {
        var that = this;
        var settings_3 = {
            "async": false,   //this is made false to get array element in right sequence
            "crossDomain": true,
            "url": that.state.current_auto_video_jobs_urls[i],
            "method": "GET",
            "headers": {
                Authorization: "Token " + that.props.token_Reducer.token
            },
            success: function (response, textStatus, jQxhr) {
                console.log("success")
                console.log("value of i is " + i)
            },
        }

        $.ajax(settings_3).done((response) => {
            auto_video_jobs_array.push(response)
            if (i == that.state.current_auto_video_jobs_urls.length - 1) {
                console.log("i reached last value")
                that.setState({current_auto_video_jobs: auto_video_jobs_array})
                console.log("current jobs are" + that.state.current_auto_video_jobs)
            }
        });
    }

这是我试图实现的替代方案,但它不起作用并抛出错误,说无法读取未定义的地图

//initialize index counter
            var i = 0;
            var that = this;
            function next() {
                $.ajax({
                    async: true,
                    "crossDomain": true,
                    "url": that.state.current_auto_video_jobs_urls[i],
                    "method": "GET",
                    "headers": {
                        Authorization: "Token " + that.props.token_Reducer.token
                    },
                    success: function(response, textStatus, jQxhr){
                        ++i;
                        if(i >= that.state.current_auto_video_jobs_urls.length) {
                            // run function here as its the last item in array
                            console.log("i reached last value")
                            that.setState({current_auto_video_jobs: auto_video_jobs_array})
                            console.log("current jobs are" + that.state.current_auto_video_jobs)
                        } else {
                            // do the next ajax call
                            auto_video_jobs_array.push(response)
                            next();
                        }
                    }
                });
            }

            // start the first one
           next();

我需要一种方法来以一种我以递增顺序获得响应的方式进行异步调用。承诺是建议的一种选择。我是新手。如果是那样,那么如何实现呢?

2 个答案:

答案 0 :(得分:-2)

所以基本上你需要串行运行一堆异步任务。换句话说,您需要从相应的库中获得一种async.series方法。 standalone package提供了类似的功能,您可以将其(非常小)sources作为您自己的解决方案的基础。

以下是async-series源的略微修改版本,其中包含特定于node.js环境的已清理代码:

/**
 * @author Hugh Kennedy
 * @url https://github.com/hughsk/async-series
 * @license MIT
 */
function series(arr, ready, safe) {
    var length = arr.length, orig;
    var nextTick = 'undefined' !== typeof setImmediate ? setImmediate : setTimeout;

    if (!length) {
        return nextTick(ready, 1)
    }

    function handleItem(idx) {
        arr[idx](function (err) {
            if (err) return ready(err)
            if (idx < length - 1) return handleItem(idx + 1)
            return ready()
        })
    }

    if (safe) {
        orig = handleItem
        handleItem = function (idx) {
            nextTick(function () {
                orig(idx)
            }, 1)
        }
    }

    handleItem(0)
}

有了这样的功能,你可以很容易地传递任务列表来运行并填充你的数组,它们可以保证按顺序运行。

答案 1 :(得分:-2)

使用promises很简单。请注意,IE没有对promises的内置支持,但您可以使用像Bluebird这样的库在IE中支持它们:

var that = this;
var auto_video_jobs_array;

// wait for all promises
Promise.all(this.state.current_auto_video_jobs_urls.map(function (url) {
    // map each url to a promise for the result of querying that URL
    var settings_3 = {
      "crossDomain": true,
      "url": url,
      "method": "GET",
      "headers": {
        Authorization: "Token " + that.props.token_Reducer.token
      }
    };

    return $.ajax(settings_3);
  }))
  .then(function(results) {
    // results is an array of all the query results, in an order matching
    // the original array
    auto_video_jobs_array = results;  // you might not need auto_video_jobs_array 
                                      // anymore, but just in case...
    that.setState({
      current_auto_video_jobs: results
    });
  });