【问题标题】:Ajax call in "for" loops skips odd/even iterations“for”循环中的 Ajax 调用跳过奇数/偶数迭代
【发布时间】:2016-04-18 18:31:33
【问题描述】:

如果我在这里问,那是因为我们被困在我们不知道如何解决的问题上。我必须承认,我们已经在 StackOverflow 和搜索引擎中搜索了解决方案。但我们没有设法实现它/解决问题。

我正在尝试创建一个 JavaScript 函数:

  • 在我的 html 页面中检测到所有出现的 html 标记:<alias>

  • 将其内容替换为 Ajax 调用的结果(发送 标签内容到Ajax.php页面)+localStorage管理

  • 最后从<alias>标签解包,留下ajax调用返回的内容

唯一的问题是在这两种情况下它都会跳过一些迭代。 我们进行了一些研究,似乎“问题”是 Ajax 是异步的,因此它不会等待响应然后继续处理。我们甚至看到“async: false”并不是一个好的解决方案。

我将脚本中感兴趣的部分留下一些简短的描述

// includes an icon in the page to display the correct change
    function multilingual(msg,i) {
         // code  
    }

    // function to make an ajax call or a "cache call" if value is in localStorage for a variable
    function sendRequest(o) {
        console.log(o.variab+': running sendRequest function');
        // check if value for that variable is stored and if stored for more than 1 hour
        if(window.localStorage && window.localStorage.getItem(o.variab) && window.localStorage.getItem(o.variab+'_exp') > +new Date - 60*60*1000) {
            console.log(o.variab+': value from localStorage');
            // replace <alias> content with cached value
            var cached = window.localStorage.getItem(o.variab);
            elements[o.counter].innerHTML = cached;

            // including icon for multilingual post
            console.log(o.variab+': calling multilingual function');
            multilingual(window.localStorage.getItem(o.variab),o.counter);

        } else {
            console.log(o.variab+': starting ajax call');
            // not stored yet or older than a month
            console.log('variable='+o.variab+'&api_key='+o.api_key+'&lang='+o.language);
            $.ajax({
                type: 'POST',
                url: my_ajax_url,
                data: 'variable='+o.variab+'&api_key='+o.api_key+'&lang='+o.language,
                success: function(msg){
                    // ajax call, storing new value and expiration + replace <alias> inner html with new value
                    window.localStorage.setItem(o.variab, msg);
                    var content = window.localStorage.getItem(o.variab);
                    window.localStorage.setItem(o.variab+'_exp', +new Date);
                    console.log(o.variab+': replacement from ajax call');
                    elements[o.counter].innerHTML = content;

                    // including icon for multilingual post
                    console.log(o.variab+': calling multilingual function');
                    multilingual(msg,o.counter);
                },
                error: function(msg){
                    console.warn('an error occured during ajax call');
                }
            });
        }
    };

    // loop for each <alias> element found
        //initial settings
            var elements = document.body.getElementsByTagName('alias'),
            elem_n = elements.length,
            counter = 0;
            var i = 0;

    for(; i < elem_n;i++) {
        var flag = 0;
        console.info('var i='+i+' - Now working on '+elements[i].innerHTML);
        sendRequest({
            variab : elements[i].innerHTML,
            api_key : settings.api_key,
            language : default_lang,
            counter : i
        });

        $(elements[i]).contents().unwrap().parent();
        console.log(elements[i].innerHTML+': wrap removed');
    }

我希望你们中的一些人可以为我提供一些有效的解决方案和/或示例,因为我们被困在这个问题上:(

根据我们的测试,当值来自缓存时,1st/3rd/5th ... 值被正确替换 当值来自 ajax 时,第 2/4 个 .. 值被替换

提前感谢您的帮助:)

【问题讨论】:

  • @RoryMcCrossan 我认为这不是问题所在。
  • 第二次阅读代码我认为你是对的。
  • 确实@Pointy 是对的。但是现在还有一个小问题(localStorage 和 ajax 的数据不同)

标签: javascript jquery ajax asynchronous callback


【解决方案1】:

你的elements 数组是一个live NodeList。当您解开这些 &lt;alias&gt; 标记中的内容时,该元素将从列表中消失。因此,您正在查看元素 0,然后执行 ajax 调用,然后删除内容周围的 &lt;alias&gt; 标记。在那一刻,element[0] 变成了 曾经 成为 element[1]。但是,您的循环增加了i,因此您跳过了新的element[0]

无论如何都没有理由使用.getElementsByTagName();您正在使用 jQuery,因此请始终使用它:

var elements = $("alias");

这将为您提供一个 jQuery 对象,该对象(大部分情况下)将像数组一样工作,因此您的其余代码无需进行太多更改(如果有的话)。

【讨论】:

  • 你真是太棒了..你应该得到一些巧克力饼干作为奖励:)确实这让我解决了第一个问题..我已经考虑过了,但我不认为这可能是问题。 顺便说一句,另一个“问题发生”:基本上..当localStorage为空时,内容不会被ajax调用的结果替换。虽然刷新后一切正常(从 localStorage 获取数据).. 知道为什么吗?
  • 哦,好的,我明白了。同样,问题在于.unwrap() 调用,但这是一个不同的问题。在调用.unwrap() 之前开始 ajax 调用,但它还没有完成。因此,您更改 DOM 以使 &lt;alias&gt; 标记不再存在。旧的 DOM 节点仍然存在于 jQuery 对象中,但是因为它不再是 DOM 的一部分,所以设置它的内容没有任何可见的效果。相比之下,本地存储访问是同步的。
  • 您可以将.unwrap() 的内容移动到从本地存储或ajax 获取内容的例程中。如果代码决定进行 ajax 调用,它应该在更新内容后在“成功”回调中执行解包。
  • 谢谢@Pointy - 你帮了我很多!
【解决方案2】:

过去为了解决类似的问题,我做了类似下面的代码,你实际上将目标与运行 AJAX 调用的函数一起发送,并且不要使用任何全局变量,因为这些变量可能会随着for 循环运行。尝试传入你将在函数参数中使用的所有内容,包括我所做的目标:

function loadContent(target, info) {
    //ajax call
    //on success replace target with new data;
}
$('alias').each(function(){
    loadContent($(this), info)
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-15
    • 2021-08-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多