推荐阅读:
本文作者读行学孟宁,转载请注明出处!
同步调用和异步调用
使用同步调用意味着调用接口的一方需要阻塞等待接口任务目标达成,然后返回才能继续执行,也就是调用接口的双方是串行执行的,如图1所示。
图1 同步调用调用过程
使用异步调用是指调用接口的一方只是发出调用接口的命令,并不需要阻塞等待接口任务目标达成后才返回,而是直接返回继续执行其他任务,在之后接到任务目标达成的结果或者主动查询任务目标达成的结果。
图2所示为通过回调函数实现异步调用。
图2 通过回调函数实现异步调用
图3所示为通过主动查询任务目标达成的结果来完成异步调用。
图3 通过主动查询任务目标达成的结果来完成异步调用
异步调用的情况比较复杂,往往会借助多线程编程或异步I/O(Input/Output),甚至结合线程池、消息队列、信号传递等,这需要明确定义较为复杂的异步调用机制。
回调函数
回调函数(Callback)是一个面向过程的概念,是代码执行过程的一种特殊流程,是通过函数指针调用的函数。把函数的指针(地址)作为参数传递给另一个函数,当这个指针调用其所指向的函数时,就称这是回调函数。回调函数不是实现该函数的软件模块直接调用,而是在特定的事件或条件发生时由另外的软件模块通过函数指针的方式调用,用于对该事件或条件进行响应,是一种下级软件模块调用上级软件模块的特殊方式。回调函数典型应用场景的简要示意图如图4所示。回调函数常常被用于异步调用。
图4 回调函数典型应用场景的简要示意图
Promise对象
Promise对象可以将异步调用以同步调用的流程表达出来,避免通过嵌套回调函数实现异步调用。
ECMAScript 6.0提供了Promise对象。Promise对象代表了未来某个将要发生的事件,通常是一个异步操作。Promise对象提供了一套完整的接口,使我们可以更加容易地控制异步调用。
ECMAScript 6.0的Promise对象是一个构造函数,用来生成Promise实例。下面是Promise对象的基本用法伪代码。
// Promise对象的resolve和reject方法是回调函数
var promise = new Promise(function(resolve, reject) {
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
// .then()是Promise对象传递回调函数最为常用的方法
promise.then(function(value) { // resolve(value)
// success
}, function(value) { // reject(error)
// failure
});
// 也可以使用.then().catch()分别传递resolve和reject回调函数
promise.then(function(value) { // resolve(value)
// success
}).catch(function(value) { // reject(error)
// failure
});
Promise对象实际上是对回调函数机制的封装,也就是通过then方法定义的函数与resolve/reject函数绑定,简化了回调函数传入的接口实现,在逻辑上更加通顺,看起来像是个同步调用。
async/await
除了前述的回调函数和Promise对象可以实现异步调用,async/await是一种新的编写异步代码的方式。Promise对象是建立在回调函数之上,async/await则是建立在Promise对象之上。
async/await 是ECMAScript 2017中的一部分,在IE和一些旧的浏览器中不支持,所以使用时务必要小心。
和Promise对象一样,async/await是非阻塞的,它可以让异步代码看起来就像同步代码那样,大大提高异步代码的可读性。
async作为一个关键字放在函数的前面,表示该函数是一个异步函数,意味着该函数的执行不会阻塞后面代码的执行,异步函数的调用跟普通函数一样。async返回的是一个Promise 对象,Promise的所有用法它都可以用。
await即等待,用于等待一个Promise对象。它只能在异步函数中使用,否则会报错。await的返回值不是Promise对象而是Promise对象处理之后的结果。
async/await带给我们的最重要的好处是,与Promise对象相比,它和同步编程的风格更加一致。以下伪代码为async/await的基本用法。
async function timeout(ms){
let result = await setTimeoutPromise(ms); // setTimeoutPromise是一个Promise对象的实例
console.log(‘Done’); // ms毫秒之后出现Done
}
timeout(3000);
console.log(‘timeout’) //立即输出timeout
XMLHttpRequest 对象
XMLHttpRequest 对象用于在后台与服务器交换数据。XMLHttpRequest 对象是可以异步返回HTTP响应结果的,它能够在不重新加载页面的情况下更新网页,在页面已加载后从服务器请求数据,在页面已加载后从服务器接收数据,在后台向服务器发送数据。目前所有现代的浏览器应该都内建了 XMLHttpRequest 对象。
通过一行简单的 JavaScript 代码,我们就可以创建 XMLHttpRequest 对象。
ajax = new XMLHttpRequest();
XMLHttpRequest 对象提供了对 HTTP 协议的完全的访问,包括做出 POST 和 HEAD 请求以及普通的 GET 请求的能力。XMLHttpRequest 可以同步或异步地返回 HTTP响应结果,并且能够以文本或者一个 DOM 文档的形式返回内容。
尽管名为 XMLHttpRequest,它并不限于和 XML 文档一起使用,它可以接收任何形式的文本文档。XMLHttpRequest 对象是名为 AJAX 技术的一项关键功能。
XMLHttpRequest 对象主要的属性和事件
readyState属性是HTTP 请求的状态。当一个 XMLHttpRequest 初次创建时,这个属性的值从 0 开始,直到接收到完整的 HTTP 响应,这个值增加到 4。这5 个状态中每一个都有一个相关联的非正式的名称,下表列出了状态、名称和含义。
状态 | 名称 | 描述 |
0 | Uninitialized | 初始化状态。XMLHttpRequest 对象已创建或已被 abort() 方法重置。 |
1 | Open | open() 方法已调用,但是 send() 方法未调用。请求还没有被发送。 |
2 | Sent | Send() 方法已调用,HTTP 请求已发送到 Web 服务器。未接收到响应。 |
3 | Receiving | 所有响应头部都已经接收到。响应体开始接收但未完成。 |
4 | Loaded | HTTP 响应已经完成接收。 |
readyState属性的值一般不会递减,每次这个属性的值增加的时候,都会触发 onreadystatechange 事件。
responseText属性是目前为止为接收到的HTTP响应(不包括HTTP头),如果还没有接收到数据的话,就是空字符串。
responseXML属性是将HTTP响应解析为 XML, 并作为 Document 对象。
XMLHttpRequest 对象主要的方法
open()方法负责初始化 HTTP 请求参数,例如 URL 和 HTTP 方法,但是并不发送请求。
open(method, url, async, username, password)
其中method 参数是用于指定 HTTP请求的方法,包括 GET、POST 和 HEAD等。url 参数是请求的资源。大多数浏览器实施了一个同源安全策略,并且要求这个 URL 与包含脚本的文本具有相同的主机名和端口。async 参数指示请求使用应该异步地执行。如果这个参数是 false,请求是同步的,后续对 send() 的调用将阻塞,直到响应完全接收。如果这个参数是 true 或省略,请求是异步的,且通常需要一个 onreadystatechange 事件处理函数。username 和 password 参数是可选的,为 url 所需的授权提供认证,如果指定了username 和 password 则会覆盖 url 自己指定的任何认证方法。
send()方法负责发送 HTTP 请求,使用传递给 open() 方法的参数以及该方法的可选参数构造HTTP请求。
send(body)
如果调用 open() 方法时指定的 HTTP 方法是 POST 或 PUT,body 参数可以是一个字符串或者 Document 对象。
XMLHttpRequest 对象的同步调用方法
XMLHttpRequest 对象的同步调用使用方法举例代码如下。open()方法的第三个参数设为false即为同步调用, 即send() 方法的调用将阻塞的。
// 新建一个XMLHttpRequest对象
var ajax = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
ajax.open("GET", "your url", false);
ajax.send();
// 将HTTP响应的结果显示到页面上
document.getElementById("content").innerHTML = ajax.responseText;
XMLHttpRequest对象得到了所有现代浏览器较好的支持。唯一的浏览器依赖性涉及 XMLHttpRequest 对象的创建。在 IE 5 和 IE 6 中,必须使用特定于 IE 的 ActiveXObject() 构造函数,如上代码所示。
XMLHttpRequest 对象的异步调用方法
XMLHttpRequest 对象的异步调用使用方法举例代码如下。open()方法的第三个参数设为ftrue即为异步调用, 即send() 方法的调用将非阻塞的。
// 新建一个XMLHttpRequest对象
var ajax = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
// 设定onreadystatechange事件处理函数
ajax.onreadystatechange = readyStateChange;
ajax.open("GET", "your url", true);
ajax.send();
// onreadystatechange事件处理函数,当readystate属性改变时调用
function readyStateChange(){
switch(ajax.readyState){
case 0:
// 此时对象尚未初始化,也没有调用open方法
console.log("创建请求...");
break;
case 1:
// 此时对象已经调用了open方法,还没有调用send方法
console.log("请求创建成功,准备发送请求...");
break;
case 2:
// 此时调用了send方法,但还没有接到HTTP响应
console.log("请求发送完毕,等待接收响应...");
break;
case 3:
// 此时正在接收HTTP响应,但还没有结束
break;
case 4:
// 此时已经得到了HTTP响应的数据,可以开始处理
console.log("接收响应成功,开始处理...");
// 将HTTP响应的结果显示到页面上
document.getElementById("content").innerHTML = ajax.responseText;
break;
}
}
显然XMLHttpRequest 对象的异步调用方法是基于回调函数的方式实现的。
Axios网络请求库
Axios是基于Promise对象实现的可以用于浏览器和node.js的网络请求库。在服务端它使用原生 node.js http 模块, 而在客户端 (浏览器) 则使用 XMLHttpRequest对象。
使用Axios的基本用例
以发起HTTP GET请求为例范例代码如下,显然其中使用了Promise对象的.then().catch()分别传递resolve和reject回调函数。
const axios = require('axios');
// 发起HTTP GET请求
axios.get('your url')
.then(function (response) {
// 处理成功情况
console.log(response);
// 将HTTP响应的结果显示到页面上
document.getElementById("content").innerHTML = response;
})
.catch(function (error) {
// 处理错误情况
console.log(error);
});
Axios也支持async/await的用法,以发起HTTP GET请求为例范例代码如下。
async function getContent() {
try {
const response = await axios.get('your url');
console.log(response);
// 将HTTP响应的结果显示到页面上
document.getElementById("content").innerHTML = response;
} catch (error) {
console.error(error);
}
}
向Axios传递相关配置来创建请求
创建请求时可以用的配置选项。只有 url 是必需的。如果没有指定 method,请求将默认使用 GET 方法。
axios({
method: 'get',
url: 'your url',
responseType: 'text'
})
.then(function (response) {
document.getElementById("content").innerHTML = response;
});
更多请求配置选项参见 https://www.axios-http.cn/docs/req_config
参考资料
《代码中的软件工程》
https://www.w3school.com.cn/xml/xml_http.asp
https://www.axios-http.cn/
推荐阅读:
本文作者读行学孟宁,转载请注明出处!