update: promise
This commit is contained in:
parent
4b2ef2d764
commit
b34943e616
@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
## 为什么需要 Promise?
|
## 为什么需要 Promise?
|
||||||
|
|
||||||
我们在上一篇文章《单线程和异步》中讲过,Javascript 是⼀⻔单线程语⾔。早期我们解决异步场景时,⼤部分情况都是通过回调函数来进⾏。
|
我们在上一篇文章《单线程和异步》中讲过,Javascript 是⼀⻔单线程语⾔。早期我们解决异步场景时,⼤部分情况都是通过回调函数来进⾏。
|
||||||
@ -8,7 +6,7 @@
|
|||||||
|
|
||||||
### 回调的定义
|
### 回调的定义
|
||||||
|
|
||||||
把函数A传给另一个函数B调用,那么函数A就是回调函数。
|
把函数 A 传给另一个函数 B 调用,那么函数 A 就是回调函数。
|
||||||
|
|
||||||
例如在浏览器中发送 ajax 请求,就是常⻅的⼀个异步场景,发送请求后,需要等待一段时间,等服务端响应之后我们才能拿到结果。如果我们希望在异步结束之后执⾏某个操作,就只能通过**回调函数**这样的⽅式进⾏操作。
|
例如在浏览器中发送 ajax 请求,就是常⻅的⼀个异步场景,发送请求后,需要等待一段时间,等服务端响应之后我们才能拿到结果。如果我们希望在异步结束之后执⾏某个操作,就只能通过**回调函数**这样的⽅式进⾏操作。
|
||||||
|
|
||||||
@ -26,22 +24,31 @@ dynamicFunc(function () {
|
|||||||
|
|
||||||
例如上⾯这个例⼦,dynamicFunc 就是⼀个异步函数,⾥⾯ setTimeout 会在 1s 之后调⽤传⼊的 callback 函数。按照上⾯的调⽤⽅式,最终 1s 之后,会打印 qian gu 这个结果。
|
例如上⾯这个例⼦,dynamicFunc 就是⼀个异步函数,⾥⾯ setTimeout 会在 1s 之后调⽤传⼊的 callback 函数。按照上⾯的调⽤⽅式,最终 1s 之后,会打印 qian gu 这个结果。
|
||||||
|
|
||||||
|
|
||||||
为了能使回调函数以更优雅的⽅式进⾏调⽤,在 ES6 语法中,新增了⼀个名为 Promise 的新规范。
|
为了能使回调函数以更优雅的⽅式进⾏调⽤,在 ES6 语法中,新增了⼀个名为 Promise 的新规范。
|
||||||
|
|
||||||
### 回调的缺点
|
### 回调的缺点
|
||||||
|
|
||||||
回调的写法比较直观,不需要 return,层层嵌套即可。但也存在两个问题:
|
回调的写法比较直观,不需要 return,层层嵌套即可。但也存在两个问题:
|
||||||
|
|
||||||
- 1、如果嵌套过深,则会出现**回调地狱**的问题。
|
- 1、如果嵌套过深,则会出现**回调地狱**的问题。
|
||||||
|
|
||||||
- 2、不同的函数,回调的参数,在写法上可能不一致,导致不规范、且需要**单独记忆**。
|
- 2、不同的函数,回调的参数,在写法上可能不一致,导致不规范、且需要**单独记忆**。
|
||||||
|
|
||||||
我们来具体看看这两个问题。
|
我们来具体看看这两个问题。
|
||||||
|
|
||||||
**1、回调地狱的问题**:
|
**1、回调地狱的问题**:
|
||||||
|
|
||||||
如果后续还有内容需要在异步函数结束时输出,就需要多个异步函数进⾏嵌套,⾮常不利于后续的维护,而且会导致**回调地狱**的问题:
|
如果多个异步函数存在依赖关系(比如,需要等第一个异步函数执行完成后,才能执行第二个异步函数;等第二个异步函数执行完毕后,才能执行第三个异步函数),就需要多个异步函数进⾏层层嵌套,⾮常不利于后续的维护,而且会导致**回调地狱**的问题。
|
||||||
|
|
||||||
|
关于回调地狱,我们来举一个形象的例子:
|
||||||
|
|
||||||
|
> 假设买菜、做饭、洗碗、倒厨余垃圾都是异步的。
|
||||||
|
|
||||||
|
> 但真实的场景中,实际的操作流程是:买菜成功之后,才能开始做饭。做饭成功后,才能开始洗碗。洗碗完成后, 再倒厨余垃圾。这里的一系列动作就涉及到了多层嵌套调用,也就是回调地狱。
|
||||||
|
|
||||||
|
关于回调地狱,我们来看看两段代码。
|
||||||
|
|
||||||
|
定时器的代码举例:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
@ -55,13 +62,20 @@ setTimeout(function () {
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
```
|
```
|
||||||
|
|
||||||
关于回调地狱,我们来举一个形象的例子:
|
ajax 请求的代码举例:
|
||||||
|
|
||||||
假设买菜、做饭、洗碗、倒厨余垃圾都是异步的。
|
```js
|
||||||
|
// 伪代码
|
||||||
但真实的场景中,实际的操作流程是:买菜成功之后,才能开始做饭。做饭成功后,才能开始洗碗。洗碗完成后, 再倒厨余垃圾。这里的一系列动作就涉及到了多层嵌套调用,也就是回调地狱。
|
ajax('a.json', (res1) => {
|
||||||
|
console.log(res1);
|
||||||
在 ES5 中,当进行多层嵌套回调时,会导致代码层次过多,很难进行后续维护和二次开发;而且会导致**回调地狱**的问题。ES6 中的 Promise 就可以解决这两个问题。
|
ajax('b.json', (res2) => {
|
||||||
|
console.log(res2);
|
||||||
|
ajax('c.json', (res3) => {
|
||||||
|
console.log(res3);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
**2、回调的写法不一致问题**:
|
**2、回调的写法不一致问题**:
|
||||||
|
|
||||||
@ -73,8 +87,7 @@ readFile('d:\\readme.text', function (error, data) {
|
|||||||
} else {
|
} else {
|
||||||
console.log('文件读取成功');
|
console.log('文件读取成功');
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
// jQuery的 ajax 写法中,成功回调和失败回调,是通过两个回调函数来区分
|
// jQuery的 ajax 写法中,成功回调和失败回调,是通过两个回调函数来区分
|
||||||
$.ajax({
|
$.ajax({
|
||||||
@ -84,15 +97,17 @@ $.ajax({
|
|||||||
},
|
},
|
||||||
error: function (err) {
|
error: function (err) {
|
||||||
console.log('文件读取失败');
|
console.log('文件读取失败');
|
||||||
|
},
|
||||||
}
|
});
|
||||||
})
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
我们可以看到,上面的代码中,成功回调和失败回调,写法不统一,需要单独记忆,容易出错。
|
我们可以看到,上面的代码中,成功回调和失败回调,写法不统一,需要单独记忆,容易出错。
|
||||||
|
|
||||||
|
**小结**:
|
||||||
|
|
||||||
|
在 ES5 中,当进行多层嵌套回调时,会导致代码层次过多,很难进行后续维护和二次开发;而且会导致**回调地狱**的问题。ES6 中的 Promise 就可以解决这两个问题。
|
||||||
|
|
||||||
|
当然, Promise 的更强大功能,不止于此。我们来一探究竟。
|
||||||
### Promise 的介绍和优点
|
### Promise 的介绍和优点
|
||||||
|
|
||||||
ES6 中的 Promise 是异步编程的一种方案。从语法上讲,Promise 是一个对象,它可以获取异步操作的消息。
|
ES6 中的 Promise 是异步编程的一种方案。从语法上讲,Promise 是一个对象,它可以获取异步操作的消息。
|
||||||
@ -108,15 +123,21 @@ Promise 的伪代码结构,大概是这样的:
|
|||||||
```js
|
```js
|
||||||
// 伪代码1
|
// 伪代码1
|
||||||
myPromise()
|
myPromise()
|
||||||
.then(function () { }, function () { })
|
.then(
|
||||||
.then(function () { }, function () { })
|
function () {},
|
||||||
.then(function () { }, function () { })
|
function () {}
|
||||||
|
)
|
||||||
|
.then(
|
||||||
|
function () {},
|
||||||
|
function () {}
|
||||||
|
)
|
||||||
|
.then(
|
||||||
|
function () {},
|
||||||
|
function () {}
|
||||||
|
);
|
||||||
|
|
||||||
// 伪代码2
|
// 伪代码2
|
||||||
是时候展现真正的厨艺了()
|
是时候展现真正的厨艺了().然后(买菜).然后(做饭).然后(洗碗);
|
||||||
.然后(买菜)
|
|
||||||
.然后(做饭)
|
|
||||||
.然后(洗碗)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
上面的伪代码可以看出,即便在业务逻辑上是层层嵌套,但是代码写法上,却十分优雅,也没有过多的嵌套。
|
上面的伪代码可以看出,即便在业务逻辑上是层层嵌套,但是代码写法上,却十分优雅,也没有过多的嵌套。
|
||||||
@ -131,6 +152,8 @@ myPromise()
|
|||||||
|
|
||||||
(3)通过 promise.then() 处理返回结果(这里的 `promise` 指的是 Promise 实例)。
|
(3)通过 promise.then() 处理返回结果(这里的 `promise` 指的是 Promise 实例)。
|
||||||
|
|
||||||
|
Promise的精髓在于**对异步操作的状态管理**。
|
||||||
|
|
||||||
接下来,我们来具体看看, promise 的代码是怎么写的。
|
接下来,我们来具体看看, promise 的代码是怎么写的。
|
||||||
|
|
||||||
### Promise 处理异步任务的过程
|
### Promise 处理异步任务的过程
|
||||||
@ -259,9 +282,7 @@ try-catch 主要用于捕获异常,注意,这里的异常是指**同步**函
|
|||||||
|
|
||||||
原因是:当异步函数抛出异常时,对于宏任务而言,执行函数时已经将该函数推入栈,此时并不在 try-catch 所在的栈,所以 try-catch 并不能捕获到错误。对于微任务而言(比如 promise)promise 的构造函数的异常只能被自带的 reject 也就是.catch 函数捕获到。
|
原因是:当异步函数抛出异常时,对于宏任务而言,执行函数时已经将该函数推入栈,此时并不在 try-catch 所在的栈,所以 try-catch 并不能捕获到错误。对于微任务而言(比如 promise)promise 的构造函数的异常只能被自带的 reject 也就是.catch 函数捕获到。
|
||||||
|
|
||||||
|
(2)写法 1 中,`promiseA().then().catch()`和`promiseA().catch().then()`区别在于:前者可以捕获到 `then` 里面的异常,后者不可以。
|
||||||
(2)写法1中,`promiseA().then().catch()`和`promiseA().catch().then()`区别在于:前者可以捕获到 `then` 里面的异常,后者不可以。
|
|
||||||
|
|
||||||
|
|
||||||
### 小结
|
### 小结
|
||||||
|
|
||||||
@ -273,16 +294,15 @@ try-catch 主要用于捕获异常,注意,这里的异常是指**同步**函
|
|||||||
|
|
||||||
4、失败的 promise,后续可以通过 promise 自带的 .catch ⽅法或是 .then ⽅法的第⼆个参数进⾏捕获。
|
4、失败的 promise,后续可以通过 promise 自带的 .catch ⽅法或是 .then ⽅法的第⼆个参数进⾏捕获。
|
||||||
|
|
||||||
|
|
||||||
## Promise 规范
|
## Promise 规范
|
||||||
|
|
||||||
### Promise 规范解读
|
### Promise 规范解读
|
||||||
|
|
||||||
Promise 是⼀个拥有 then ⽅法的对象或函数。任何符合 promise 规范的对象或函数都可以成为 Promise。
|
Promise 是⼀个拥有 then ⽅法的对象或函数。任何符合 promise 规范的对象或函数都可以成为 Promise。
|
||||||
|
|
||||||
关于promise 规范的详细解读,可以看下面这个链接:
|
关于 promise 规范的详细解读,可以看下面这个链接:
|
||||||
|
|
||||||
- Promises/A+ 规范:<https://promisesaplus.com/>
|
- Promises/A+ 规范:<https://promisesaplus.com/>
|
||||||
|
|
||||||
## promise 对象的 3 个状态
|
## promise 对象的 3 个状态
|
||||||
|
|
||||||
@ -483,8 +503,7 @@ request1()
|
|||||||
|
|
||||||
## 总结
|
## 总结
|
||||||
|
|
||||||
|
了解这些内容之后, 你已经对 Promise 有了基本了解。下一篇文章,我们来讲一讲 Promise 在实战开发的常见用法。
|
||||||
了解这些内容之后, 你已经对 Promise 有了基本了解。下一篇文章,我们来讲一讲 Promise在实战开发的常见用法。
|
|
||||||
|
|
||||||
## 参考链接
|
## 参考链接
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## 同步和异步
|
## 同步和异步
|
||||||
|
|
||||||
### 同步和异步的概念
|
### 同步和异步的简单理解
|
||||||
|
|
||||||
|
|
||||||
- 同步:必须等待前面的任务完成,才能继续后面的任务。
|
- 同步:必须等待前面的任务完成,才能继续后面的任务。
|
||||||
@ -19,12 +19,15 @@
|
|||||||
|
|
||||||
我们在访问一个普通的网站时,当浏览器加载完`HTML、CSS、JS`以后,网站的内容就固定了。如果想让网站内容发生更改,就必须**刷新**页面才能够看到更新的内容。
|
我们在访问一个普通的网站时,当浏览器加载完`HTML、CSS、JS`以后,网站的内容就固定了。如果想让网站内容发生更改,就必须**刷新**页面才能够看到更新的内容。
|
||||||
|
|
||||||
可如果用到**异步更新**,情况就大为改观了。比如,我们在访问新浪微博时,看到一大半了,点击底部的**加载更多**,会自动帮我们加载更多的微博,同时页面并没有刷新。
|
可如果用到**异步更新**,情况就大为改观了。比如,我们在访问新浪微博时,看到一大半了,点击底部的**加载更多**,会自动帮我们加载更多的微博,同时页面并不会整体刷新。
|
||||||
|
|
||||||
试想一下,如果没有异步刷新的话,每次点击“加载更多”,网页都要刷新,体验就太不好了。
|
试想一下,如果没有异步刷新的话,每次点击“加载更多”,网页都要重新刷新,体验就太糟糕了。
|
||||||
|
|
||||||
web前端里的异步更新,就要用到 Ajax。
|
web前端里的异步更新,就要用到 Ajax。
|
||||||
|
|
||||||
|
关于同步和异步的更详细介绍,可以参考本项目的另外一篇文章:《JavaScript基础:ES6语法/单线程和异步》
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Ajax
|
## Ajax
|
||||||
|
|
||||||
@ -49,9 +52,9 @@ Ajax:Asynchronous Javascript And XML(异步 JavaScript 和 XML)。它并
|
|||||||
|
|
||||||
发送 Ajax 请求的五个步骤:
|
发送 Ajax 请求的五个步骤:
|
||||||
|
|
||||||
(1)创建异步对象。即 XMLHttpRequest 对象。
|
(1)创建异步对象,即 XMLHttpRequest 对象。
|
||||||
|
|
||||||
(2)使用open方法设置请求的参数。open(method, url, async)。参数解释:请求的方法、请求的url、是否异步。
|
(2)使用open方法设置请求的参数。`open(method, url, async)`。参数解释:请求的方法、请求的url、是否异步。
|
||||||
|
|
||||||
(3)发送请求。
|
(3)发送请求。
|
||||||
|
|
||||||
@ -59,7 +62,7 @@ Ajax:Asynchronous Javascript And XML(异步 JavaScript 和 XML)。它并
|
|||||||
|
|
||||||
如果要在数据完整请求回来的时候才调用,我们需要手动写一些判断的逻辑。
|
如果要在数据完整请求回来的时候才调用,我们需要手动写一些判断的逻辑。
|
||||||
|
|
||||||
(5)获取返回的数据。
|
(5)服务端响应,获取返回的数据。
|
||||||
|
|
||||||
### Ajax 请求:get 请求举例
|
### Ajax 请求:get 请求举例
|
||||||
|
|
||||||
@ -644,11 +647,13 @@ echo $text;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 我的公众号
|
## 创作不易,赞赏作者
|
||||||
|
|
||||||
想学习<font color=#0000ff>**代码之外的技能**</font>?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
如果你觉得本教程对你有帮助,或者你想催更,不妨赞赏一下。
|
||||||
|
|
||||||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
你的赞赏和认可,是我最大的动力:
|
||||||
|
|
||||||
|
|
||||||
|
![](http://img.smyhvae.com/20210510_2100.jpg)
|
||||||
|
|
||||||
![](http://img.smyhvae.com/2016040102.jpg)
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user