用于进行 API 调用的 JavaScript

举报
Q神 发表于 2023/06/23 11:36:23 2023/06/23
【摘要】 使用 JavaScript 发出 API 请求的方法有很多种,从纯 JavaScript 到 jQuery,再到可大大简化流程的其他工具。在本文中,我们将使用标准 JavaScript 技术。我们将在以下课程中更改代码,以多种方式发出 API 请求。我们还将了解在此过程中使用异步编程的几种工具。毕竟,API 是异步的。虽然我们将在本部分中仅使用异步工具进行 API 调用,但我们将学习的异步工...

使用 JavaScript 发出 API 请求的方法有很多种,从纯 JavaScript 到 jQuery,再到可大大简化流程的其他工具。在本文中,我们将使用标准 JavaScript 技术。我们将在以下课程中更改代码,以多种方式发出 API 请求。我们还将了解在此过程中使用异步编程的几种工具。毕竟,API 是异步的。虽然我们将在本部分中仅使用异步工具进行 API 调用,但我们将学习的异步工具也可用于其他异步 JavaScript 任务。

我们将在此会话中以老式方式发出 API 请求,仅使用普通 JavaScript。jQuery 用于执行 API 请求的所有工具都使用这种老式方法。然而,我们不会在本节中介绍 jQuery 技术,因为 Fetch API 是一个更优越的选项。Fetch 同样基于这种历史悠久的方法。因此,虽然您可能不会在该领域的独立项目中使用此策略(尽管您当然可以!),但当我们在本节后面使用 Fetch 等技术时,您将更好地了解它们是如何发挥作用的。

出发

我们不会在接下来的部分中包含用于设置环境的所有代码。讲座结束时,可以在存储库中的功能齐全的 webpack 环境中使用下面的示例代码。如果您要从头开始创建此项目,则需要包含一个 webpack 环境,您可以自己构建该环境,也可以在课程结束时从存储库中获取该环境。我们不需要__tests__目录,因为我们没有测试任何东西。js我们现在不需要目录。在本次会议中,我们将把所有 JS 代码放入 中index.js,这与我们在 webpack 项目中使用的命名方案相同。对于下面的代码示例,我们只需要查看两个文件:index.htmlindex.js.
HTML 代码:

<html lang="en-US">
<head>
  <title>Weather</title>
</head>
<body>
  <div class="container">
    <h1>Get Weather Conditions From Anywhere!</h1>
    <label for="location">Enter a location:</label>
    <input id="location" type="text">
    <button class="btn-success" id="weatherLocation">Get Current Temperature and Humidity</button>
    <div class="showErrors"></div>
    <div class="showHumidity"></div>
    <div class="showTemp"></div>
  </div>
</body>
</html>


对于位置,我们有一个基本的表单输入。还有各种 div 用于显示错误、温度和湿度。

我们看一下API调用的代码:

import $ from 'jquery';
import 'bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css';
import './css/styles.css';

$(document).ready(function() {
  $('#weatherLocation').click(function() {
    const city = $('#location').val();
    $('#location').val("");

    let request = new XMLHttpRequest();
    const url = `http://api.openweathermap.org/data/2.5/weather?q=${city}&appid=[YOUR-API-KEY-HERE]`;

    request.onreadystatechange = function() {
      if (this.readyState === 4 && this.status === 200) {
        const response = JSON.parse(this.responseText);
        getElements(response);
      }
    };

    request.open("GET", url, true);
    request.send();

   function getElements(response) {
      $('.showHumidity').text(`The humidity in ${city} is ${response.main.humidity}%`);
      $('.showTemp').text(`The temperature in Kelvins is ${response.main.temp} degrees.`);
    }
  });
});


首先,我们将查看进口申报单。我们有一个点击处理程序,它从表单中提取城市值,将其放入名为 city 的变量中,然后删除表单字段 $('#location') 。值(“”);本节仅供回顾。

以下是新代码的第一行:
let request = new XMLHttpRequest();
我们创建一个新的XMLHttpRequest(或简称 XHR)对象并将其保存在request变量中。XMLHttpRequest是一个有点欺骗性的名字。这些对象用于与服务器交互,这正是 API 调用的用途。它们不仅仅用于 XML 查询。如前所述,XML 是 API 使用的相当广泛的数据格式。然而,JSON 变得越来越流行,XMLHttpRequest对象可以与 JSON 以及其他形式的数据一起使用,而不仅仅是 XML。

然后,我们的 API 调用的 URL 被保存在一个变量中:

 const url = http://api.openweathermap.org/data/2.5/weather?q=${city}&appid=[Add-Your-API-Key]; 

这不是必需的,但它确实使我们的代码更易于理解。为了使代码正常运行,您需要在[YOUR-API-KEY-HERE]. 因为我们的字符串是带有嵌入表达式的模板文字($city),所以用户在表单中输入的值将通过我们的city变量直接传输到我们的 URL 字符串中。

代码的其余部分分为三个部分:

  • XMLHttpRequest'监视s任何更改的函数readyState
  • 请求被真正处理并发送。
  • 将用于在浏览器中显示结果的回调函数。让我们从监视更改的函数开始XMLHttpRequest
request.onreadystatechange = function() {
  if (this.readyState === 4 && this.status === 200) {
    const response = JSON.parse(this.responseText);
    getElements(response);
  }
};


Onreadystatechange是我们XMLHttpRequest对象的一个​​属性。该属性可以设置为执行我们想要的任何操作的函数的值。在上面的示例中,我们有一个匿名函数(未命名函数)设置为该属性的值。

我们甚至可以调整代码以仅跟踪就绪状态的变化:

request.onreadystatechange = function() {
  console.log(this.readyState);
};

如果我们这样做,控制台将显示以下内容。该评论已包含在内。

1 // Opened
2 // Headers Received
3 // Loading
4 // Done

XMLHttpRequest这些数字代表了我们的物体可能被发现的多种状态。(因为这是初始状态 - 并且readyState尚未更改 - 您不会看到0,它对应于 Unsent。)

请注意,如果您在控制台中尝试执行此操作,ESLint 将抱怨no-unused-vars. 这是因为getElements()我们稍后在代码中定义的方法不再使用。为了让 ESLint 感觉好一点,暂时注释掉它。另外,完成后,请务必将代码恢复到原始状态。在此
之前我们不想做任何事情,因为数据传输尚未完成。在工作中,这是经典的异步。一旦完成,这个 if 。如果 的话,我们将对数据做任何事情。为什么会出现这种情况?是否有必要this.readyState4this.readyState === 4this.status === 200this.status === 200包含在我们的条件中?我们在上一课中讨论了 200 响应如何表示 API 请求成功。换句话说,在我们的代码分析数据之前,API请求必须成功并且数据传输必须完成。

当条件为真时,我们执行以下代码:

const response = JSON.parse(this.responseText);

This.responseText如您所料,是对象的另一个内置属性XMLHttpRequest。一旦收到服务器答复,就会立即填写。现在应该很明显,XMLHttpRequest物体非常坚固并且为我们做了大量的工作。
JavaScript 中的内置JSON.parse方法用于解析this.responseText. 这保证了数据的格式正确为 JSON 数据。否则,我们的代码不会将数据识别为 JSON,并且当我们尝试使用点表示法从中获取数据时,我们将收到错误。使用 API 需要使用该JSON.parse()方法。正如我们在上一讲中提到的,其他编程语言也包含解析 JSON 的方法。

然后,使用变量中的数据response,我们将构建一个回调:

getElements(response);

当一个函数调用另一个函数时会发生回调。稍后我们将更详细地讨论这一点。

在此之前,让我们XMLHttpRequest更深入地讨论一下对象。通过在条件中放置断点,然后在浏览器中执行代码,我们可以准确地看到对象XMLHttpRequest具有哪些特征。

request.onreadystatechange = function() {
  if (this.readyState === 4 && this.status === 200) {
    debugger;
    ...
  }
};

更明智的做法是从“源”选项卡添加断点 - 上面的示例仅演示了应该放置断点的位置。
正如您所看到的,一个XMLHttpRequest对象具有很多功能。这些资产中的大多数目前不值得担心。然而,有一些将在本节中使用:

responseText:我们之前已经讨论过这一点。它包含响应的文本。(属性中也可以找到相同的文本response。)
状态:状态代码是 API 状态代码。200分表示成功。有多种不同的代码,例如404未找到。
statusText:如您所见,“OK”。状态代码为 200,这是标准的。这表明我们已经准备好出发了!但是,如果出现任何问题,我们可能会收到更具描述性的错误消息,例如“未找到”或“不允许”。

让我们回到我们的新代码:

let request = new XMLHttpRequest();
const url = `http://api.openweathermap.org/data/2.5/weather?q=${city}&appid=[YOUR-API-KEY-HERE]`;

request.onreadystatechange = function() {
  if (this.readyState === 4 && this.status === 200) {
    const response = JSON.parse(this.responseText);
    getElements(response);
  }
};

// We've covered everything except for the two lines below!
request.open("GET", url, true);
request.send();

除了最后两行(在评论中突出显示)之外,我们已经涵盖了所有内容。

我们已经创建了一个新XMLHttpRequest对象,并为属性设置了一个方法onreadystatechange,以在代码中监听对象就绪状态的变化,但我们还没有对它做任何事情。请求仍必须打开并发送。

 request.open("GET", url, true);
 request.send();

请求的方法(在本例中GET)、url(我们保存在名为 url 的变量中)以及指示请求是否应该异步的布尔值都被发送到XMLHttpRequest.open(). 我们希望请求再次异步;我们不希望用户的浏览器冻结!对于我们在本节中进行的 API 调用,这三个参数几乎总是相同的;唯一的例外是,如果您提出"POST"请求或其他形式的请求,而不是"GET."
我们在打开请求后发送请求。正如我们已经解释过的,对象readyStateXMLHttpRequest会发生变化,并且我们附加到对象的函数onreadystatechange将在每次更改时触发readyState。最后,我们的getElements()当链接到该onreadystatechange属性的函数中的条件被激活时,该方法将运行。当一个函数调用另一个函数时会发生回调
。回调可能很快就会变得令人困惑,特别是当一个函数调用另一个函数,而另一个函数又调用另一个函数时,等等。因此,它们对于新手来说可能有些令人畏惧。请记住,当您在现实世界中看到看起来可怕的回调时,回调只是一个调用另一个函数的函数。在后面的课程中,当我们讨论“回调地狱”的概念时,我们将描述为什么回调可能如此可怕。
目前,了解回调是 JavaScript 编写者处理异步代码的一种方法至关重要。它曾经是处理异步代码的唯一选择。幸运的是,我们现在可以获得新技术,这将使我们的生活变得更简单。在本节后面,我们将介绍其中一些工具。

因为我们需要等到条件被触发后再使用 getElements,所以我们需要在这里使用回调 ()。请记住,JavaScript 是一种非阻塞语言。即使某些代码是异步的,它也会继续运行。

让我们看看如果不使用回调会发生什么。

// Note: This code will not work! It's meant to show why we need to structure our code to use a callback.

    let response;

    request.onreadystatechange = function() {
      if (this.readyState === 4 && this.status === 200) {
        response = JSON.parse(this.responseText);
      }
    };

    request.open("GET", url, true);
    request.send();
    getElements(response);

当我们执行request.send()上面的代码时,我们的请求被提交到服务器。请记住,这将需要一些时间。我们的请求将被服务器接受(或拒绝),并且我们将收到响应。我们必须首先等待答案加载,然后再解析它。另一方面,JavaScript 不是一种阻塞语言。这意味着它不会等到request.send()完成才继续。调用getElements(response)将立即发生,我们将收到以下错误:

Cannot read property 'main' of undefined

这是一个典型的异步问题,getElements(response)虽然是异步,但request.send()并不是异步。当getElements()调用 时,结果仍然是,undefined因为函数仍在运行。答案将在稍后指定,但我们的代码将在此之前崩溃。

这就是为什么需要回调。让我们再看看我们的原始代码:

request.onreadystatechange = function() {
      if (this.readyState === 4 && this.status === 200) {
        const response = JSON.parse(this.responseText);
        getElements(response);
      }
    };

...

    function getElements(response) {
      $('.showHumidity').text(`The humidity in ${city} is ${response.main.humidity}%`);
      $('.showTemp').text(`The temperature in Kelvins is ${response.main.temp} degrees.`);
    }

getElements(response)在条件为真之前,不会在此代码中调用。换句话说,我们确保在使用回调收到服务器的响应之前该函数不会启动。

回调的许多基本用例之一是异步代码。回调可以帮助我们确定函数的执行顺序。如果我们需要在异步函数之后执行同步函数,我们可以使用回调来确保代码按预期顺序运行。

当然,当我们需要一系列同步和异步方法按指定顺序运行时,事情可能很快就会变得奇怪。

结论

我们在本次讲座中介绍了如何构建和发送 XMLHttpRequest 对象。这样做之后,您应该更好地了解 JavaScript 如何创建 HTTP 请求。我们还讨论了如何利用回调来确保我们的代码按照我们想要的顺序运行。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。