JavaScript(香草,没有jQuery) -函数与*同步* AJAX (XMLHttpRequest)调用的行为与

JavaScript (Vanilla, no jQuery) - Function with *synchronous* AJAX (XMLHttpRequest) call behaves the same as async?

本文关键字:XMLHttpRequest AJAX 调用 同步 函数 香草 没有 jQuery JavaScript      更新时间:2023-09-26

我有一个文件,tst.html,内容为:

part two

(没有标记或其他任何东西,只是为了演示)

然后加载该文件,通过同步 AJAX (XMLHttpRequest):
function someFunc() {
    var str = 'part one_';
    var x = new XMLHttpRequest();
    x.open('GET', 'tst.html', false);    // "false" for synchronous
    x.onreadystatechange = function() {
        if(x.readyState === 4) {
            switch(x.status) {
                case 200:
                    str += x.responseText.trim();
                    break;
                default:
                    return '';   // Or something
                    break;
            }
        }
    }
    x.send();
    str += '_part three';
    return str;
}

调用函数:

alert(someFunc());
// Returns "part one_part two_part three"

,这是期望的行为。

但是如果我把AJAX调用放到它自己的函数中:

function ajaxCall() {
    var x = new XMLHttpRequest();
    x.open('GET', 'tst.html', false);
    x.onreadystatechange = function() {
        if(x.readyState === 4) {
            switch(x.status) {
                case 200:
                    return x.responseText.trim();
                    break;
                default:
                    return '';
                    break;
            }
        }
    }
    x.send();
}
function someFunc() {
    var str = 'part one';
    str += ajaxCall();
    str += 'part three';
    return str;
}

然后命名为:

alert(someFunc());
// Returns "part one_undefined_part three"

该函数在AJAX有机会完成之前返回合并字符串,这与它的异步表兄弟相同。

我一直在寻找"同步AJAX函数"之类的东西,但是没有找到任何有用的东西。

AJAX调用的最终用例位于一组递归函数中,进一步的处理依赖于AJAX返回。比如:

function one(url) {
    var x = new XMLHttpRequest();
    x.open('GET', url, false);
    x.onreadystatechange = function() {
        return two(x.responseText.trim());
    }
    x.send();
}
function two(str) {
    var output;
    output += stuff;
    // ... parse through str
    // ... until match found
    if(isURL(match)) {                     // If `match` is a URL
        output += one(match);
    }else if(isFormattedString(match)) {   // if `match` is a string
        output += two(match);
    }
    output += more stuff;
    // More processing of output    
    return output;
}
var final = one(url);

在上面的例子中:

  • 系统总是以URL (one(url))启动
  • one()返回一个字符串,它本身是two(str)
  • 的开始参数。
  • two()中,解析器可能遇到

    1. 另一个URL,或

    2. 可解析字符串。

  • 两个函数中的一个被称为

  • 将输出添加到系统的最终结果

one()回调将不起作用,因为我仍然需要在two()中有一个最终的return

function one(url, callback) {
    // ... AJAX stuff
    {
        callback(two(x.responseText));
    }
}
function two(str) {
    // ... same as previous
    // The following doesn't work, because then `two()` no longer has a `return`
    // ... and any other code (i.e. for !isURL cases) will still continue to execute
    if(isURL(match)) {
        one(match, function(result) {
            output += result;
            // ... more processing
            return output;
        });
    }else if(...) {
        // ... same as previous
    }
    // ... more stuffs
}

我找到的唯一其他东西是deferred,但我不确定它将如何与此工作。

是否有一种方法可以强制JavaScript像对待其他同步函数一样对待它,其中执行代码停止直到函数完成?我不清楚为什么AJAX请求被明确地声明为异步。

我喜欢你的长而详细的问题(希望每个人都能付出同样的努力来问!),但本质上它归结为这一点:

function ajaxCall() {
    var x = new XMLHttpRequest();
    x.open('GET', 'tst.html', false);
    x.onreadystatechange = function() {
        if(x.readyState === 4) {
            switch(x.status) {
                case 200:
                    return x.responseText.trim();
                    break;
                default:
                    return '';
                    break;
            }
        }
    }
    x.send();
}

您的return语句是从onreadystatechange返回的,而不是您期望的ajaxCall。它与原始版本的唯一不同之处在于原始版本只是连接字符串。这与将它移动到自己的函数中无关。

不要使用同步ajax!了解异步函数是如何工作的,特别是如何从异步调用返回响应?

问题是你的return

return x.responseText.trim();

从处理程序返回,而不是从ajaxCall函数返回——它没有return语句,所以总是返回undefined