【问题标题】:Array element is there but it isn't there数组元素存在但不存在
【发布时间】:2023-03-13 02:04:01
【问题描述】:
  1. 收听输入字段中的“Keyup”
  2. 将“enableSubmitButton”定义为数组
  3. 做一些事情
  4. 将数组元素添加到“enableSubmitButton”数组中
  5. 我正在从当前输入字段搜索父表单,然后循环所有输入字段
  6. 在这个循环中,我向服务器发出请求
  7. 在“onreadystatechange”函数中,我将另一个元素推送到“enableSubmitButton”数组中

问题是,我在“onreadystatechange”中推送的元素实际上并不在数组中。 当我使用console.log()查看数组时,元素是可见的,但如果我使用“array.length”函数,则数组元素不包括在内:-O

$('.checkEmail, .checkPwd, .checkPwdC').bind("keyup", function() {
    //define enableSubmitButton as an array
    var enableSubmitButton = [];

    //loop each input field in the form
    $(this).parents("form").find(":input").each(function(index,data){

        //do some "if then else" and other stuff
        ...
        enableSubmitButton.push(true);
        ...

        // Now I make a request to the server with Ajax
        var xmlhttp = new XMLHttpRequest();                                
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                if(xmlhttp.responseText == "doesntExist"){
                    enableSubmitButton.push(true);
                }else{
                    enableSubmitButton.push(false);
                }
            }
        };

        //Request
        xmlhttp.open("GET", "ajax.php?ajaxCase=cuna&userName="+$('#fNewAccount input.checkAvailability').val(), true);
        xmlhttp.send();
    });

    // PROBLEM
    // and here we have the problem. To debugg, i use the console.log() function as follow
    var okForSubmit = true;

    console.log(enableSubmitButton);
    console.log("array length: "+enableSubmitButton.length);

    for(var i = 0 ; i < enableSubmitButton.length ; i++){
        if(enableSubmitButton[i] == false){
            okForSubmit = false;
        }
        var newTime = Math.floor(Math.random() * (100 - 1 + 1)) + 1;
        console.log(i+" - "+enableSubmitButton[i]+" - "+newTime+" - "+okForSubmit);
    }
});

这是 console.log() 的输出:

(4) [true, true, true, true]
0: true
1: true
2: true
3: true
4: false
length: 5
__proto__: Array(0)

array length: 4
0 - true - 54 - true
1 - true - 19 - true
2 - true - 51 - true
3 - true - 94 - true

有什么想法吗?

【问题讨论】:

  • 只是一个小问题,你能解释一下为什么你在 URL 中使用$('#fNewAccount input.checkAvailability') 提出请求吗?它不依赖于您正在迭代的input 元素,因此该URL 在each 循环的每次迭代中都是相同的URL。这不应该是$(this) 或类似的吗?
  • 请注意,onreadystatechange 在您记录之前不会在此代码中运行。那是一个事件处理程序,因此它第一次可以运行是在整个事件处理程序(keyup)完成之后。 JavaScript 一次处理一个事件,没有重叠。考虑评论整个 XHR 部分进行测试,false 来自其他地方。

标签: javascript arrays


【解决方案1】:

这只是 JavaScript 控制台本身:它记录活动对象和文本的混合:

stuff=[true];
console.log(stuff);
stuff.push(false);

如果您在 JavaScript 控制台中执行此操作,您会看到类似

> (1) [true]

在推送之前来自日志。但是如果你打开“>”部分,它会显示对象的当前状态,包括推送的结果:

(1) [true]
 0: true
 1: false
 length: 2

所以(1) [true] 部分只是文本,它不会被更新,但是当你“打开”它的细节(使用小箭头)时,对象会被评估。如果你再推一些东西,什么都不会改变(当然是在屏幕上),但是关闭-重新打开细节可以用来再次评估对象,等等。

【讨论】:

  • 不能依赖console.log 输出。在创建 console.log 时,尚未进行 Ajax 回调,因此这些值此时不在数组中,即使控制台显示了它们。但这是因为console.log 只记录数组引用同步,内容是异步检索的,因此可能会产生误导。
  • AJAX 调用实在是太神奇了:是的,对象的“下拉”版本实际上是一个调试器输出。这种推动会产生与 OP 所要求的相同的效果。
【解决方案2】:

这是一个典型的异步问题:只有在所有其他代码运行完毕后,HTTP 请求才会伴随响应(调用回调)。

控制台显示数组中的元素是一种误导,但那是因为控制台只接收到数组的引用,而一旦你查看它,HTTP响应已经被处理了,所以你会看到控制台中的内容。

真的看看数组内容是什么此刻console.log调用被执行,像这样序列化数组:

console.log(JSON.stringify(enableSubmitButton));

现在你会看到它实际上是空的。

为了解决基本问题,您可以利用 jQuery 为它公开的 Ajax 方法返回的承诺(无论如何,这些方法比 httpRequest 更容易使用)。然后,您首先将所有这些 Promise 收集到一个数组中,然后对它们调用 $.when。这个$.when 调用的回调只有在你收到所有的Ajax 响应后才会执行,只有这样你才能安全地创建你的enableSubmitButton 数组。

这是一个简化的概念证明:

$('button').click(function f(e) {
    e.preventDefault();
    var $inputs = $(this).parents("form").find(":input");
    var promises = $inputs.map(function(index, data){
        // Make your request with jQuery, which returns a promise
        // I use a test URL here; replace with your own
        var url = "https://jsonplaceholder.typicode.com/posts/" + (index+1);
        return $.get(url).then(function(response) {
            return response == "doesntExist"; // a boolean
        });
    }).get(); // array of promises
    // When all promises have resolved, only then get your array
    $.when.apply($, promises).then(function () {
        // Get the arguments -- which are the values returned by the `then` callbacks:
        var enableSubmitButton = [].slice.call(arguments);
        console.log('result', enableSubmitButton);
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
    <input value="100"><input value="abc">
    <button>Click me</button>
</form>

【讨论】:

  • 整个 mumbo-jumbo 完全没有意义(加上 sn-p 对我不起作用),原始内容已经被记录:“(4) [true, true, true, true]”部分永远不会改变,只是 OP 未能在日志的活动部分中发现“长度:5”。
  • sn-p 对我有用。 console log 输出具有误导性,因为 that 也是异步发生的。确实存在异步问题。在console.log(enableSubmitButton); 的时刻,数组确实 not 包含在 Ajax 响应中添加的值。如果它被记录为console.log(enableSubmitButton.join());,这将是显而易见的。这不仅仅是length 的问题。
  • 好的,sn-p 在最近的桌面浏览器(Chrome、Firefox)中运行良好,但在 iOS Safari 上对我不起作用。
  • Console.log 确实同步工作,它在调用时将对象的状态字符串化并打印出来。事后检查对象的可能性与控制台本身无关,而与调试器有关。并且这两种输出分别是一致的,即使在问题中也是如此。第一个输出表明该数组有 4 个元素并列出了 4 个 true-s。然后OP“再次”检查了对象,它打印了5个元素,然后打印了一个“长度:5”。在那里,在 OP 的问题中,他只是得出结论,当数组中有 5 个元素时存在一种状态,但长度报告为 4。不,没有。
  • console.log 不能同步工作(尽管对此没有标准),并且它不会将结果字符串化为纯字符串。而是将调试器中显示的引用作为可折叠接口传递,其中嵌套部分被异步检索。参见例如herehere。这种情况下的数组不可能有后面添加的 4 个元素。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-25
  • 1970-01-01
  • 2021-04-23
  • 2018-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多