如何在没有使用jQuery的情况下进行AJAX调用?

927

如何使用JavaScript进行AJAX调用,而不使用jQuery?


23
请注意,虽然这里的许多答案建议监听 _readystatechange_,但现代浏览器支持 XMLHttpRequest 的 load, abort, progresserror 事件(你可能只关心 _load_)。请注意不要改变原文意思,并使翻译更加通俗易懂。 - Paul S.
9
这是一个包含许多纯JavaScript示例(包括IE8+,IE9+和IE10+的AJAX)的网站,它展示了在不使用jQuery的情况下如何完成相同的任务。 - Sanya_Zol
2
w3schools有一个不错的逐步介绍Ajax而不使用jQuery的教程:https://www.w3schools.com/js/js_ajax_intro.asp - MacMartin
您还可以使用EHTML:https://github.com/Guseyn/EHTML 使用e-json元素获取JSON并将其映射到HTML元素。 - Guseyn Ismayylov
24个回答

664

使用“原生”(纯)JavaScript:

function loadXMLDoc() {
    var xmlhttp = new XMLHttpRequest();

    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState == XMLHttpRequest.DONE) { // XMLHttpRequest.DONE == 4
           if (xmlhttp.status == 200) {
               document.getElementById("myDiv").innerHTML = xmlhttp.responseText;
           }
           else if (xmlhttp.status == 400) {
              alert('There was an error 400');
           }
           else {
               alert('something else other than 200 was returned');
           }
        }
    };

    xmlhttp.open("GET", "ajax_info.txt", true);
    xmlhttp.send();
}

使用jQuery

$.ajax({
    url: "test.html",
    context: document.body,
    success: function() {
      $(this).addClass("done");
    }
});

1
@Fractaliste 如果你只是在与xmlhttp.status相关的if块之后调用回调函数,那么就在那里调用它们,然后就完成了。 - Jay
6
@Wade,我认为Gokigooooks的意思是在阅读《使用“vanilla”JavaScript》时,他认为它是一个需要下载的JavaScript库。他可能还参考了Vanilla JS - Trisped

231

使用以下代码片段,您可以轻松地执行类似的操作,如下所示:

ajax.get('/test.php', {foo: 'bar'}, function() {});

这是代码片段:

var ajax = {};
ajax.x = function () {
    if (typeof XMLHttpRequest !== 'undefined') {
        return new XMLHttpRequest();
    }
    var versions = [
        "MSXML2.XmlHttp.6.0",
        "MSXML2.XmlHttp.5.0",
        "MSXML2.XmlHttp.4.0",
        "MSXML2.XmlHttp.3.0",
        "MSXML2.XmlHttp.2.0",
        "Microsoft.XmlHttp"
    ];

    var xhr;
    for (var i = 0; i < versions.length; i++) {
        try {
            xhr = new ActiveXObject(versions[i]);
            break;
        } catch (e) {
        }
    }
    return xhr;
};

ajax.send = function (url, callback, method, data, async) {
    if (async === undefined) {
        async = true;
    }
    var x = ajax.x();
    x.open(method, url, async);
    x.onreadystatechange = function () {
        if (x.readyState == 4) {
            callback(x.responseText)
        }
    };
    if (method == 'POST') {
        x.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    }
    x.send(data)
};

ajax.get = function (url, data, callback, async) {
    var query = [];
    for (var key in data) {
        query.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]));
    }
    ajax.send(url + (query.length ? '?' + query.join('&') : ''), callback, 'GET', null, async)
};

ajax.post = function (url, data, callback, async) {
    var query = [];
    for (var key in data) {
        query.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]));
    }
    ajax.send(url, callback, 'POST', query.join('&'), async)
};

1
这是一个非常好的起步,但我认为您错过了@3nigma答案中的某些特性。也就是说,我不确定在没有返回服务器响应的情况下进行某些请求(所有get和一些post)是否有多大意义。我在send方法的末尾添加了另一行--return x.responseText;--然后返回每个ajax.send调用。 - Sam
3
@Sam,通常情况下由于请求是异步的,你无法返回结果。你需要在回调函数中处理响应。 - Petah
不错的代码片段。不过,应该改成query.join('&').replace(/%20/g, '+'),对吧? - afsantos
@afsantos https://dev59.com/I3I-5IYBdhLWcg3w3crS - Petah
3
请在选项中包含CORS请求,也包括此行:'xhr.withCredentials = true;'。 - Akam
显示剩余6条评论

223

现在在现代浏览器中原生支持一个更好的Fetch APIfetch()方法允许你发起网络请求。 例如,要从/get-data请求一些JSON数据:

let options = {
  method: 'GET',      
  headers: {}
};

fetch('/get-data', options)
.then(response => response.json())
.then(body => {
  // Do something with body
});

查看MDN Web Docs: 使用 Fetch API以获取更多详细信息。

async/await

或者,如果使用asyncawait语法,请执行以下操作:
async function doApi(url) {
  const response = await fetch(url);
  if( response.ok ) {
    if( 200 <= response.status && response.status <= 299 ) {
      const result = await response.json();
      // do something awesome with result
    } else {
      console.log( `got a ${response.status}` );
    }
  }
}

当然,你可能想要检查响应代码等等,但文档已经详细涵盖了这些内容。

9
这里应该提到 GitHub 的 polyfill。https://github.com/github/fetch - TylerY86
10
只需添加<script src="https://cdn.rawgit.com/github/fetch/master/fetch.js"></script>,就可以像专家一样使用fetch。 - TylerY86
1
不要在移动设备上使用Fetch。在Android上存在HTTP头小写问题。在iOS上运行良好。 - Kenny Lim
1
它也不能在最流行的Safari版本上运行。 - yumaikas

109

您可以使用以下函数:

function callAjax(url, callback){
    var xmlhttp;
    // compatible with IE7+, Firefox, Chrome, Opera, Safari
    xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function(){
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200){
            callback(xmlhttp.responseText);
        }
    }
    xmlhttp.open("GET", url, true);
    xmlhttp.send();
}

你可以在以下链接中尝试类似的解决方案:


还可以为请求添加一些输入变量(将在xmlhttp.send(request);中使用)。 - Pavel Perna
2
@PavelPerna,由于这里的示例是GET,所以您可以将它们添加到请求中,但为了更通用,我同意您的想法,我真的考虑更新答案,接受请求参数作为函数的参数,并传递方法(GETPOST),但阻止我的是我希望在这里保持答案尽可能简单,让人们尽快尝试它。实际上,我讨厌其他答案太长了,因为他们试图变得完美 :) - AbdelHady

43
xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
        alert(this.responseText);
    }
};
xhttp.open("GET", "ajax_info.txt", true);
xhttp.send();

62
不要进行同步调用。使用xhReq.onload并使用回调函数。 - 19h
3
@FellowStranger oReq.onload = function () { /this.responseText/ };这段代码的意思是:定义一个函数,当一个 XMLHttpRequest 对象完成加载时执行该函数。在这个函数中,可以通过 this.responseText 来获取服务器返回的响应内容。 - 19h
1
@Andrey:就你所知,你会停止执行所有操作,直到服务器返回响应。这并没有什么特别糟糕的地方,但对于某些用途可能不完全适当。 - mrówa
2
此外,如果服务器由于某些原因实际上没有响应,则您代码的其余部分将永远不会运行。 - Random Elephant

42

这个版本使用纯 ES6/ES2015,怎么样?

function get(url) {
  return new Promise((resolve, reject) => {
    const req = new XMLHttpRequest();
    req.open('GET', url);
    req.onload = () => req.status === 200 ? resolve(req.response) : reject(Error(req.statusText));
    req.onerror = (e) => reject(Error(`Network Error: ${e}`));
    req.send();
  });
}

该函数返回一个promise。以下是如何使用该函数并处理它返回的promise的示例:
get('foo.txt')
.then((data) => {
  // Do stuff with data, if foo.txt was successfully loaded.
})
.catch((err) => {
  // Do stuff on error...
});

如果你需要加载一个json文件,你可以使用JSON.parse()将加载的数据转换成JS对象。
你也可以在函数中集成req.responseType='json',但是很遗憾它没有IE支持, 所以我建议使用JSON.parse()

2
使用 XMLHttpRequest,您可以异步尝试加载文件。这意味着您的代码执行将继续进行,而您的文件将在后台加载。为了在脚本中使用文件的内容,您需要一种机制来告诉您的脚本何时完成加载或加载失败。这就是 promises 发挥作用的地方。还有其他解决此问题的方法,但我认为 promises 最方便。 - Rotareti
@Rotareti 移动浏览器是否支持这种方法? - bodruk
只有更新的浏览器版本支持它。一种常见的做法是使用最新的ES6/7/..编写代码,并使用Babel或类似工具将其转译回ES5以获得更好的浏览器支持。 - Rotareti
2
@Rotareti,您能否解释一下为什么这比“简单”的回调更方便?这种便利性是否值得为了支持旧浏览器而额外付出努力来转译它? - lennyklb
@LennartKloppenburg 我认为这个答案解释得很好:https://dev59.com/6mYq5IYBdhLWcg3wui_F#14244950 “这种便利性是否值得为了旧浏览器支持而进行额外的转译工作?” Promise只是ES6/7带来的众多功能之一。如果你使用转译器,你可以编写最新的JS代码。这是值得的! - Rotareti

37

使用XMLHttpRequest

简单的GET请求

httpRequest = new XMLHttpRequest()
httpRequest.open('GET', 'http://www.example.org/some.file')
httpRequest.send()

简单的POST请求

httpRequest = new XMLHttpRequest()
httpRequest.open('POST', 'http://www.example.org/some/endpoint')
httpRequest.send('some data')

我们可以使用可选的第三个参数来指定请求应该是异步(true, 默认值)还是同步(false)。

// Make a synchronous GET request
httpRequest.open('GET', 'http://www.example.org/some.file', false)

在调用httpRequest.send()之前,我们可以设置请求头信息。

httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
我们可以通过在调用httpRequest.send()之前将httpRequest.onreadystatechange设置为一个函数来处理响应。
httpRequest.onreadystatechange = function(){
  // Process the server response here.
  if (httpRequest.readyState === XMLHttpRequest.DONE) {
    if (httpRequest.status === 200) {
      alert(httpRequest.responseText);
    } else {
      alert('There was a problem with the request.');
    }
  }
}

1
请注意,除了200之外还有其他成功的状态,例如201。 - Nate Vaughan

30

您可以根据浏览器获取正确的对象,使用

function getXmlDoc() {
  var xmlDoc;

  if (window.XMLHttpRequest) {
    // code for IE7+, Firefox, Chrome, Opera, Safari
    xmlDoc = new XMLHttpRequest();
  }
  else {
    // code for IE6, IE5
    xmlDoc = new ActiveXObject("Microsoft.XMLHTTP");
  }

  return xmlDoc;
}

通过正确的对象,GET 可以被抽象为:

function myGet(url, callback) {
  var xmlDoc = getXmlDoc();

  xmlDoc.open('GET', url, true);

  xmlDoc.onreadystatechange = function() {
    if (xmlDoc.readyState === 4 && xmlDoc.status === 200) {
      callback(xmlDoc);
    }
  }

  xmlDoc.send();
}

向以下地址进行POST请求:

function myPost(url, data, callback) {
  var xmlDoc = getXmlDoc();

  xmlDoc.open('POST', url, true);
  xmlDoc.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

  xmlDoc.onreadystatechange = function() {
    if (xmlDoc.readyState === 4 && xmlDoc.status === 200) {
      callback(xmlDoc);
    }
  }

  xmlDoc.send(data);
}

18

我想找一种方法,通过ajax使用promises而不使用jQuery。在HTML5 Rocks上有一篇文章讲解ES6 promises。(你可以使用像Q这样的promise库来进行polyfill)。你可以使用我从文章中复制的代码片段。

function get(url) {
  // Return a new promise.
  return new Promise(function(resolve, reject) {
    // Do the usual XHR stuff
    var req = new XMLHttpRequest();
    req.open('GET', url);

    req.onload = function() {
      // This is called even on 404 etc
      // so check the status
      if (req.status == 200) {
        // Resolve the promise with the response text
        resolve(req.response);
      }
      else {
        // Otherwise reject with the status text
        // which will hopefully be a meaningful error
        reject(Error(req.statusText));
      }
    };

    // Handle network errors
    req.onerror = function() {
      reject(Error("Network Error"));
    };

    // Make the request
    req.send();
  });
}

注意:我还写了一篇关于此内容的 文章


17

XMLHttpRequest()

您可以使用XMLHttpRequest()构造函数创建一个新的XMLHttpRequest(XHR)对象,该对象将允许您使用标准HTTP请求方法(例如GETPOST)与服务器进行交互:

const data = JSON.stringify({
  example_1: 123,
  example_2: 'Hello, world!',
});

const request = new XMLHttpRequest();

request.addEventListener('load', function () {
  if (this.readyState === 4 && this.status === 200) {
    console.log(this.responseText);
  }
});

request.open('POST', 'example.php', true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
request.send(data);

fetch()

你也可以使用fetch()方法获取一个Promise,该Promise解析为代表响应的Response对象:

const data = JSON.stringify({
  example_1: 123,
  example_2: 'Hello, world!',
});

fetch('example.php', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
  },
  body: data,
}).then(response => {
  if (response.ok) {
    response.text().then(response => {
      console.log(response);
    });
  }
});

navigator.sendBeacon()

另一方面,如果您只是尝试 POST 数据并且不需要来自服务器的响应,则最简短的解决方法是使用 navigator.sendBeacon()
const data = JSON.stringify({
  example_1: 123,
  example_2: 'Hello, world!',
});

navigator.sendBeacon('example.php', data);

2
我非常喜欢你的答案,因为你涵盖了大多数情况,甚至包括使用XMLHttpRequest的Internet Explorer,但是我建议在那个例子(XMLHttpRequest)中将“const data = ...”更改为“var data = ...”,以便它与之完全兼容。 - Dazag

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接