AJAX的原理和加载JSON

AJAX(Async JavaScript And XML) → 用 JS 发请求和收响应

让我们通过使用 AJAX 来加载 CSS、JavaScript、HTML、XML 和 JSON,学会 AJAX 的原理和用法。

示例代码

背景

AJAX 是浏览器上的功能

  • 浏览器可以发请求,收响应
  • 浏览器在 window 上加了一个XMLHttpRequest函数
  • 用这个构造函数(类)可以构造出一个对象
  • JS 通过它实现发请求,收响应

    小工具:node-dev

准备一个服务器

  • 使用server.js作为我们的服务器
  • node server.js 8888启动
  • 添加index.html/main.js两个路由:
if (path === "/index.html") {
  response.statusCode = 200;
  response.setHeader("Content-Type", "text/html;charset=utf-8");
  response.write(`
    <!DOCTYPE html>
    <html>
    <head><title>ajax</title></head>
    <body><h1>AJAX demo</h1>
        <script src="/main.js"></script>
    </body>
    </html>
    `);
  response.end();
} else if (path === "/main.js") {
  response.statusCode = 200;
  response.setHeader("Content-Type", "text/css;charset=utf-8");
  response.write(`console.log("I am main.js")`);
  response.end();
}

挑战 1-加载 CSS

  • 以前我们用<link rel=stylesheet href="1.css"/>
  • 今天请用 AJAX 加载 CSS

四个步骤

  1. 创建HttpRequest对象(XMLHttpRequest)
  2. 调用对象的open方法
  3. 监听对象的onload&onerror事件

    专业前端会改用onreadystatechange事件, 具体用法可以参考: XMLHttpRequest.onreadystatechange| MDN

    扩展阅读: ready state | MDN

在事件处理函数里操作 CSS 文件内容

  1. 调用对象的send方法(发送请求)

    具体可以看: XMLHttpRequest.send() | MDN

HTML:

<!DOCTYPE html>
<html>
  <head>
    <title>ajax</title>
    <!— <link rel="stylesheet" href="/style.css" />
    —>
  </head>
  <body>
    <h1>AJAX demo 1</h1>
    <p>
      <button id="getCSS">request css</button>
    </p>
    <script src="/main.js"></script>
  </body>
</html>

JavaScript:

console.log("我是main.js");

getCSS.onclick = () => {
  const request = new XMLHttpRequest();
  request.open("GET", "/style.css");
  request.onload = () => {
    console.log("request.response");
    console.log(request.response);
    console.log("成功啦");
    // 创建style标签
    const style = document.createElement("style");
    // 填写style内容
    style.innerHTML = request.response;
    // 插到头里面
    document.head.appendChild(style);
  };
  request.onerror = () => {
    console.log("失败了...");
  };
  request.send();
};

挑战 2-加载 JS

  • 以前我们用<script src="2.js"></script>
  • 今天请用 AJAX 加载 JS

四个步骤

  1. 创建HttpRequest对象(XMLHttpRequest)
  2. 调用对象的open方法
  3. 监听对象的onreadystatechange事件

    在事件处理函数里操作 JS 文件内容

  4. 调用对象的send方法(发送请求)

JavaScript:

console.log("I am main.js");
getJS.onclick = () => {
  const request = new XMLHttpRequest();
  request.open("GET", "/2.js");
  request.onload = () => {
    console.log(request.response);
    const script = document.createElement("script");
    script.innerHTML = request.response;
    document.body.appendChild(script);
  };
  request.onerror = () => {};
  request.send();
};

挑战 3-加载 HTML

  • 以前我们不会加载3.html

四个步骤

  1. 创建HttpRequest对象(XMLHttpRequest)
  2. 调用对象的open方法
  3. 监听对象的onreadystatechange事件

    在事件处理函数里操作 HTML 文件内容

  4. 调用对象的send方法(发送请求)
console.log("I am main.js");
getHTML.onclick = () => {
  const request = new XMLHttpRequest();
  request.open("GET", "/3.html");
  request.onload = () => {
    console.log(request.response);
    const div = document.createElement("div");
    div.innerHTML = request.response;
    document.body.appendChild(div);
  };
  request.onerror = () => {};
  request.send();
};

onreadystatechange 事件

使用原因: onerror()并没有很好的匹配 AJAX

  • onreadystatechange重做一下挑战 1
getCSS.onclick = () => {
  const request = new XMLHttpRequest();
  request.open("GET", "/style.css");
  request.onreadystatechange = () => {
    // console.log(request.readyState);
    if (request.readyState === 4) {
      // 下载完成,但不知道是成功 2xx 还是失败 4xx 5xx
      if (request.status >= 200 && request.status < 300) {
        const style = document.createElement("style");
        style.innerHTML = request.response;
        document.head.appendChild(style);
      } else {
        alert("加载css失败");
      }
    }
  };
  request.send();
};

挑战 4-加载 XML

  • 以前我们不会加载4.html

四个步骤

  1. 创建HttpRequest对象(XMLHttpRequest)
  2. 调用对象的open方法
  3. 监听对象的onreadystatechange事件

    在事件处理函数里操作responseXML

  4. 调用对象的send方法(发送请求)

XML:

<?xml version="1.0" encoding="UTF-8"?>
<message>
    <warning>
         Hello World
    </warning>
</message>

JavaScript:

getXML.onclick = () => {
  const request = new XMLHttpRequest();
  request.open("GET", "/4.xml");
  request.onreadystatechange = () => {
    if ((request.readyState === 4) & (request.status === 200)) {
      const dom = request.responseXML;
      const text = dom.getElementsByTagName("warning")[0].textContent;
      console.log(text.trim());
    }
  };
  request.send();
};

总结

HTTP 是个框,什么都能往里装

  • 可以装 HTML、CSS、JS、XML…
  • 记得设置正确的Content-Type,这是好习惯
  • 只要你知道怎么解析这些内容,就可以使用这些内容

解析方法

  • 得到 CSS 之后生成 style 标签
  • 得到 JS 之后生成 script 标签
  • 得到 HTML 之后使用 innerHTML 和 DOM API
  • 得到 XML 之后使用 responseXML 和 DOM API
  • 不同类型的数据有不同类型的解析办法

挑战 5-加载 JSON

JSON 介绍 - Douglas Crockford

支持的数据类型

  • string

    (注意)只支持双引号,不支持单引号和无引号

  • number

    支持科学计数法

  • bool

    true 和 false

  • null

    没有 undefined

  • object
  • array

    就这六种,注意跟 JS 的七种数据类型区别开来

不支持函数,不支持变量(所以也不支持引用)

加载 JSON

  • 我们需要加载5.json

四个步骤

  1. 创建 HttpRequest 对象(全称是 XMLHttpRequest)
  2. 调用对象的 open 方法
  3. 监听对象的 onreadystatechange 事件

    在事件处理函数里使用JSON.parse

  4. 调用对象的 send 方法(发送请求)

HTML:

<!DOCTYPE html>
<html>
  <head>
    <title>ajax</title>
  </head>
  <body>
    <h1>AJAX Hello <span id="myName"></span></h1>
    <p>
      <button id="getJSON">request JSON</button>
    </p>
    <script src="/main.js"></script>
  </body>
</html>

JSON:

{
  "name": "xiu",
  "age": 24,
  "xxx": null
}

JavaScript:

getJSON.onclick = () => {
  const request = new XMLHttpRequest();
  request.open("GET", "/5.json");
  request.onreadystatechange = () => {
    if (request.readyState === 4 && request.status === 200) {
      const object = JSON.parse(request.response);
      myName.textContent = object.name;
    }
  };
  request.send();
};

window.JSON

JSON.parse

  • 将符合JSON语法的字符串转换成JS对应类型的数据
  • JSON字符串 →JS数据
  • 由于JSON只有六种类型,所以转成的数据也只有 6 种
  • 如果不符合JSON语法,则直接抛出一个Error对象
  • 一般用try catch捕获错误

JSON.stringify

  • JSON.parse的逆运算
  • JS数据 → JSON字符串
  • 由于JS的数据类型比JSON多,所以不一定能成功
  • 如果失败,就抛出一个Error对象

全部 5 个挑战的完整代码

comments powered by Disqus