update: ajax异步任务
This commit is contained in:
parent
07102a7261
commit
48a1ab234f
@ -22,31 +22,41 @@ JavaScript 语言和执行环境是**单线程**。即同一时间,只能处
|
||||
|
||||
- 异步任务:不进入主线程、而是进入**任务队列**(Event Queue)的任务。只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
|
||||
|
||||
代码举例:
|
||||
|
||||
```js
|
||||
console.log('同步任务');
|
||||
console.log('同步任务1');
|
||||
|
||||
setTimeout(() => {
|
||||
console.log('异步任务');
|
||||
}, 1000);
|
||||
|
||||
console.log('同步任务2');
|
||||
```
|
||||
|
||||
比如上面的代码里:第一行代码是同步任务,会**立即执行**;定时器里的回调函数是异步任务,需要等 1 秒后才会执行。
|
||||
打印结果是:
|
||||
|
||||
比如说,网络图片的请求,就是一个异步任务。前端如果同时请求多张网络网络图片,谁先请求完成就让谁先显示出来。
|
||||
```
|
||||
同步任务1
|
||||
同步任务2
|
||||
异步任务
|
||||
```
|
||||
|
||||
假如网络图片的请求做成同步任务,那就会出大问题,所有图片都得排队加载,如果第一张图片未加载完成,就得卡在那里,造成阻塞,导致其他图片都加载不出来。页面看上去也会很卡顿,这肯定是不能接受的。
|
||||
代码解释:第一行代码是同步任务,会**立即执行**;定时器里的回调函数是异步任务,需要等 1 秒后才会执行。假如定时器里的代码是同步任务,那需要等待1秒后,才能执行最后一行代码`console.log('同步任务2')`,也就是造成了主线程里的同步任务阻塞,这不是我们希望看到的。
|
||||
|
||||
比如说,网络图片的请求,就是一个异步任务。前端如果同时请求多张网络网络图片,谁先请求完成就让谁先显示出来。假如网络图片的请求做成同步任务,那就会出大问题,所有图片都得排队加载,如果第一张图片未加载完成,就得卡在那里,造成阻塞,导致其他图片都加载不出来。页面看上去也会很卡顿,这肯定是不能接受的。
|
||||
|
||||
### 前端使用异步的场景
|
||||
|
||||
什么时候需要**等待**,就什么时候用异步。
|
||||
什么时候需要**等待**,就什么时候用异步。常见的异步场景如下:
|
||||
|
||||
- 定时器:setTimeout(定时炸弹)、setInterval(循环执行)
|
||||
- 1、定时器:setTimeout(定时炸弹)、setInterval(循环执行)
|
||||
|
||||
- 事件绑定(比如说,按钮绑定点击事件之后,用户爱点不点。我们不可能卡在按钮那里,什么都不做。所以,应该用异步)
|
||||
- 2、事件绑定(比如说,按钮绑定点击事件之后,用户爱点不点。我们不可能卡在按钮那里,什么都不做。所以,应该用异步)
|
||||
|
||||
- 网络请求(含接口请求):ajax 请求、网络图片加载
|
||||
- 3、网络请求(含接口请求):ajax 请求、网络图片加载
|
||||
|
||||
- ES6 中的 Promise
|
||||
- 4、ES6 中的 Promise
|
||||
|
||||
现在的大部分软件项目,都是前后端分离的。后端生成接口,前端请求接口。前端发送 ajax 请求,向后端请求数据,然后**等待一段时间**后,才能拿到数据。这个请求过程就是异步任务。
|
||||
|
||||
@ -61,11 +71,6 @@ js 中常见的接口调用方式,有以下几种:
|
||||
|
||||
下一篇文章,我们重点讲一下接口调用里的 Ajax,然后在 ES6 语法中学习 **Promise**。在这之前,我们需要先了解同步任务、异步任务的事件循环机制。
|
||||
|
||||
### 多次异步调用的顺序
|
||||
|
||||
- 多次异步调用的结果,顺序可能不同步。
|
||||
|
||||
- 异步调用的结果如果**存在依赖**,则需要通过回调函数进行嵌套。
|
||||
|
||||
### 事件循环机制(重要)
|
||||
|
||||
@ -80,6 +85,13 @@ js 中常见的接口调用方式,有以下几种:
|
||||
- 当主线程的任务执行完毕之后,此时主线程处于空闲状态,于是会去读取 Event Queue 中的任务队列,如果有任务,则进入到主线程去执行。
|
||||
|
||||
|
||||
### 多次异步调用的顺序
|
||||
|
||||
- 多次异步调用的结果,顺序可能不同步。
|
||||
|
||||
- 异步调用的结果如果**存在依赖**,则需要通过回调函数进行嵌套。
|
||||
|
||||
|
||||
## 定时器:代码示例
|
||||
|
||||
掌握了上面的事件循环原理之后,我们来看几个例子。
|
||||
@ -162,7 +174,8 @@ setTimeout(() => {
|
||||
上面的案例中,异步任务需要等待 1004 毫秒之后,才会从 Event Table 进入到 Event Queue。这在面试中也经常被问到。
|
||||
|
||||
## 异步任务举例
|
||||
### 例1:加载图片
|
||||
|
||||
### 例 1:加载图片
|
||||
|
||||
```js
|
||||
// 加载图片的异步任务
|
||||
@ -193,8 +206,31 @@ loadImage(
|
||||
);
|
||||
```
|
||||
|
||||
### 例 2:定时器计时,移动 DOM 元素
|
||||
|
||||
### 例2:定时器计时
|
||||
```js
|
||||
// 函数封装:定义一个定时器,每间隔 delay 毫秒之后,执行 callback 函数
|
||||
function myInterval(callback, delay = 100) {
|
||||
let timeId = setInterval(() => callback(timeId), delay);
|
||||
}
|
||||
|
||||
myInterval((timeId) => {
|
||||
// 每间隔 500毫秒之后,向右移动 .box 元素
|
||||
const myBox = document.getElementsByClassName('box')[0];
|
||||
const left = parseInt(window.getComputedStyle(myBox).left);
|
||||
myBox.style.left = left + 20 + 'px';
|
||||
if (left > 300) {
|
||||
clearInterval(timeId);
|
||||
|
||||
// 每间隔 10 毫秒之后,将 .box 元素的宽度逐渐缩小,直到消失
|
||||
myInterval((timeId2) => {
|
||||
const width = parseInt(window.getComputedStyle(myBox).width);
|
||||
myBox.style.width = width - 1 + 'px';
|
||||
if (width <= 0) clearInterval(timeId2);
|
||||
}, 10);
|
||||
}
|
||||
}, 200);
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
@ -58,6 +58,76 @@ Ajax:Asynchronous Javascript And XML(异步 JavaScript 和 XML)。它并
|
||||
|
||||
(5)服务端响应,获取返回的数据。
|
||||
|
||||
## XMLHttpRequest 对象详解
|
||||
|
||||
我们在上一段讲解了使用 XMLHttpRequest 对象的五个步骤。本段,我们讲一下注意事项。
|
||||
|
||||
### 发送请求
|
||||
|
||||
发送请求的方法:
|
||||
|
||||
```javascript
|
||||
open(method, url, async);
|
||||
```
|
||||
|
||||
参数解释:
|
||||
|
||||
- method:请求的类型;GET 或 POST
|
||||
|
||||
- url:文件在服务器上的位置
|
||||
|
||||
- async:true(异步)或 false(同步)
|
||||
|
||||
另外还有个方法:(仅用于 POST 请求)
|
||||
|
||||
```javascript
|
||||
send(string);
|
||||
```
|
||||
|
||||
### POST 请求时注意
|
||||
|
||||
如果想让 像 form 表单提交数据那样使用 POST 请求,就需要使用 XMLHttpRequest 对象的 setRequestHeader()方法 来添加 HTTP 头。然后在 send() 方法中添加想要发送的数据:
|
||||
|
||||
```javascript
|
||||
xmlhttp.open('POST', 'ajax_test.php', true);
|
||||
|
||||
xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
||||
|
||||
xmlhttp.send('name=smyhvae&age=27');
|
||||
```
|
||||
|
||||
### onreadystatechange 事件
|
||||
|
||||
注册 onreadystatechange 事件后,每当 readyState 属性改变时,就会调用 onreadystatechange 函数。
|
||||
|
||||
readyState:(存有 XMLHttpRequest 的状态。从 0 到 4 发生变化)
|
||||
|
||||
- 0: 请求未初始化
|
||||
|
||||
- 1: 服务器连接已建立
|
||||
|
||||
- 2: 请求已接收
|
||||
|
||||
- 3: 请求处理中
|
||||
|
||||
- 4: 请求已完成,且响应已就绪
|
||||
|
||||
status:
|
||||
|
||||
- 200: "OK"。
|
||||
|
||||
- 404: 未找到页面。
|
||||
|
||||
在 onreadystatechange 事件中,**当 readyState 等于 4,且状态码为 200 时,表示响应已就绪**。
|
||||
|
||||
### 服务器响应的内容
|
||||
|
||||
- responseText:获得字符串形式的响应数据。
|
||||
|
||||
- responseXML:获得 XML 形式的响应数据。
|
||||
|
||||
如果响应的是普通字符串,就使用 responseText;如果响应的是 XML,使用 responseXML。
|
||||
|
||||
## 手写 Ajax
|
||||
|
||||
### 手写第一个 Ajax 请求
|
||||
@ -223,76 +293,30 @@ myAjax('a.json', (res) => {
|
||||
|
||||
![](http://img.smyhvae.com/20180228_1605.gif)
|
||||
|
||||
### Ajax 多个接口的嵌套请求(重要)
|
||||
|
||||
## XMLHttpRequest 对象详解
|
||||
我们在做异步任务的时候,经常会涉及到多个接口的嵌套请求。比如说,接口 1 请求完成后,需要根据接口 1 的数据请求接口 2;接口 2 请求完成后,需要根据接口 3 的数据请求接口 3,以此类推。
|
||||
|
||||
我们在上一段讲解了使用 XMLHttpRequest 对象的五个步骤。本段,我们讲一下注意事项。
|
||||
需求描述:
|
||||
|
||||
### 发送请求
|
||||
- 请求接口 1,根据用户名获取用户 id
|
||||
|
||||
发送请求的方法:
|
||||
- 请求接口 2,根据用户 id 获取用户的年龄、性别等信息。
|
||||
|
||||
```javascript
|
||||
open(method, url, async);
|
||||
代码实现思路:
|
||||
|
||||
```js
|
||||
myAjax('http://localhost:8888/php/user.php?name=千古', (userInfo) => {
|
||||
// 根据第一个接口返回的 userInfo.id,继续请求第二个接口
|
||||
myAjax(`http://localhost:8888/php/houdunren.php?id=${userInfo['id']}`, (res) => {
|
||||
console.log(response);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
参数解释:
|
||||
我们在实战开发中,经常会涉及到接口请求之间的**依赖**:需要上一个接口请求返回的数据,来发送本次请求。这种场景经常遇到,需要记住。
|
||||
|
||||
- method:请求的类型;GET 或 POST
|
||||
|
||||
- url:文件在服务器上的位置
|
||||
|
||||
- async:true(异步)或 false(同步)
|
||||
|
||||
另外还有个方法:(仅用于 POST 请求)
|
||||
|
||||
```javascript
|
||||
send(string);
|
||||
```
|
||||
|
||||
### POST 请求时注意
|
||||
|
||||
如果想让 像 form 表单提交数据那样使用 POST 请求,就需要使用 XMLHttpRequest 对象的 setRequestHeader()方法 来添加 HTTP 头。然后在 send() 方法中添加想要发送的数据:
|
||||
|
||||
```javascript
|
||||
xmlhttp.open('POST', 'ajax_test.php', true);
|
||||
|
||||
xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
||||
|
||||
xmlhttp.send('name=smyhvae&age=27');
|
||||
```
|
||||
|
||||
### onreadystatechange 事件
|
||||
|
||||
注册 onreadystatechange 事件后,每当 readyState 属性改变时,就会调用 onreadystatechange 函数。
|
||||
|
||||
readyState:(存有 XMLHttpRequest 的状态。从 0 到 4 发生变化)
|
||||
|
||||
- 0: 请求未初始化
|
||||
|
||||
- 1: 服务器连接已建立
|
||||
|
||||
- 2: 请求已接收
|
||||
|
||||
- 3: 请求处理中
|
||||
|
||||
- 4: 请求已完成,且响应已就绪
|
||||
|
||||
status:
|
||||
|
||||
- 200: "OK"。
|
||||
|
||||
- 404: 未找到页面。
|
||||
|
||||
在 onreadystatechange 事件中,**当 readyState 等于 4,且状态码为 200 时,表示响应已就绪**。
|
||||
|
||||
### 服务器响应的内容
|
||||
|
||||
- responseText:获得字符串形式的响应数据。
|
||||
|
||||
- responseXML:获得 XML 形式的响应数据。
|
||||
|
||||
如果响应的是普通字符串,就使用 responseText;如果响应的是 XML,使用 responseXML。
|
||||
但这种层层嵌套的代码,会导致**回调地域**的问题,也不利于维护。我们在后续的 ES6 章节中,会讲解 Promise,它是一种更优雅的异步任务解决方案。
|
||||
|
||||
## jQuery 中的 Ajax
|
||||
|
||||
@ -302,14 +326,18 @@ JQuery 作为最受欢迎的 js 框架之一,常见的 Ajax 已经帮助我们
|
||||
|
||||
```javascript
|
||||
$.ajax({
|
||||
url: '01.php', //请求地址
|
||||
data: 'name=fox&age=18', //发送的数据
|
||||
url: 'https://xxx.com/getUserInfo.php', // 接口的请求地址
|
||||
data: 'name=fox&age=18', // 请求参数
|
||||
type: 'GET', //请求的方式
|
||||
success: function (argument) {}, // 请求成功执行的方法
|
||||
success: function (argument) {
|
||||
// 接口请求成功时调用
|
||||
console.log('接口请求成功');
|
||||
},
|
||||
beforeSend: function (argument) {}, // 在发送请求之前调用,可以做一些验证之类的处理
|
||||
error: function (argument) {
|
||||
console.log(argument);
|
||||
}, //请求失败调用
|
||||
// 接口请求失败时调用
|
||||
console.log('接口请求失败');
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
@ -332,15 +360,17 @@ $.ajax({
|
||||
$(function () {
|
||||
$('#btn').click(function () {
|
||||
$.ajax({
|
||||
url: 'data.php',
|
||||
url: 'https://xxx.com/getUserInfo.php', // 接口的请求地址
|
||||
dataType: 'text',
|
||||
data: 'name=fox&age=18', // 请求参数
|
||||
type: 'get',
|
||||
success: function (data) {
|
||||
console.log('接口请求成功');
|
||||
alert(data);
|
||||
//$("#showInfo").html(data);
|
||||
// $("#showInfo").html(data);
|
||||
},
|
||||
error: function (e) {
|
||||
console.log(e);
|
||||
error: function (err) {
|
||||
console.log('接口请求失败:' + err);
|
||||
},
|
||||
});
|
||||
});
|
||||
@ -370,3 +400,7 @@ echo $text;
|
||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||||
|
||||
![](https://img.smyhvae.com/20200102.png)
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
Loading…
Reference in New Issue
Block a user