update: promise
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
## 为什么需要 Promise?
|
||||
|
||||
我们在上一篇文章《单线程和异步》中讲过,Javascript 是⼀⻔单线程语⾔。早期我们解决异步场景时,⼤部分情况都是通过回调函数来进⾏。
|
||||
@@ -8,7 +6,7 @@
|
||||
|
||||
### 回调的定义
|
||||
|
||||
把函数A传给另一个函数B调用,那么函数A就是回调函数。
|
||||
把函数 A 传给另一个函数 B 调用,那么函数 A 就是回调函数。
|
||||
|
||||
例如在浏览器中发送 ajax 请求,就是常⻅的⼀个异步场景,发送请求后,需要等待一段时间,等服务端响应之后我们才能拿到结果。如果我们希望在异步结束之后执⾏某个操作,就只能通过**回调函数**这样的⽅式进⾏操作。
|
||||
|
||||
@@ -26,22 +24,31 @@ dynamicFunc(function () {
|
||||
|
||||
例如上⾯这个例⼦,dynamicFunc 就是⼀个异步函数,⾥⾯ setTimeout 会在 1s 之后调⽤传⼊的 callback 函数。按照上⾯的调⽤⽅式,最终 1s 之后,会打印 qian gu 这个结果。
|
||||
|
||||
|
||||
为了能使回调函数以更优雅的⽅式进⾏调⽤,在 ES6 语法中,新增了⼀个名为 Promise 的新规范。
|
||||
|
||||
### 回调的缺点
|
||||
|
||||
回调的写法比较直观,不需要 return,层层嵌套即可。但也存在两个问题:
|
||||
|
||||
- 1、如果嵌套过深,则会出现**回调地狱**的问题。
|
||||
- 1、如果嵌套过深,则会出现**回调地狱**的问题。
|
||||
|
||||
- 2、不同的函数,回调的参数,在写法上可能不一致,导致不规范、且需要**单独记忆**。
|
||||
- 2、不同的函数,回调的参数,在写法上可能不一致,导致不规范、且需要**单独记忆**。
|
||||
|
||||
我们来具体看看这两个问题。
|
||||
|
||||
**1、回调地狱的问题**:
|
||||
|
||||
如果后续还有内容需要在异步函数结束时输出,就需要多个异步函数进⾏嵌套,⾮常不利于后续的维护,而且会导致**回调地狱**的问题:
|
||||
如果多个异步函数存在依赖关系(比如,需要等第一个异步函数执行完成后,才能执行第二个异步函数;等第二个异步函数执行完毕后,才能执行第三个异步函数),就需要多个异步函数进⾏层层嵌套,⾮常不利于后续的维护,而且会导致**回调地狱**的问题。
|
||||
|
||||
关于回调地狱,我们来举一个形象的例子:
|
||||
|
||||
> 假设买菜、做饭、洗碗、倒厨余垃圾都是异步的。
|
||||
|
||||
> 但真实的场景中,实际的操作流程是:买菜成功之后,才能开始做饭。做饭成功后,才能开始洗碗。洗碗完成后, 再倒厨余垃圾。这里的一系列动作就涉及到了多层嵌套调用,也就是回调地狱。
|
||||
|
||||
关于回调地狱,我们来看看两段代码。
|
||||
|
||||
定时器的代码举例:
|
||||
|
||||
```js
|
||||
setTimeout(function () {
|
||||
@@ -55,13 +62,20 @@ setTimeout(function () {
|
||||
}, 1000);
|
||||
```
|
||||
|
||||
关于回调地狱,我们来举一个形象的例子:
|
||||
ajax 请求的代码举例:
|
||||
|
||||
假设买菜、做饭、洗碗、倒厨余垃圾都是异步的。
|
||||
|
||||
但真实的场景中,实际的操作流程是:买菜成功之后,才能开始做饭。做饭成功后,才能开始洗碗。洗碗完成后, 再倒厨余垃圾。这里的一系列动作就涉及到了多层嵌套调用,也就是回调地狱。
|
||||
|
||||
在 ES5 中,当进行多层嵌套回调时,会导致代码层次过多,很难进行后续维护和二次开发;而且会导致**回调地狱**的问题。ES6 中的 Promise 就可以解决这两个问题。
|
||||
```js
|
||||
// 伪代码
|
||||
ajax('a.json', (res1) => {
|
||||
console.log(res1);
|
||||
ajax('b.json', (res2) => {
|
||||
console.log(res2);
|
||||
ajax('c.json', (res3) => {
|
||||
console.log(res3);
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**2、回调的写法不一致问题**:
|
||||
|
||||
@@ -73,8 +87,7 @@ readFile('d:\\readme.text', function (error, data) {
|
||||
} else {
|
||||
console.log('文件读取成功');
|
||||
}
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
// jQuery的 ajax 写法中,成功回调和失败回调,是通过两个回调函数来区分
|
||||
$.ajax({
|
||||
@@ -84,15 +97,17 @@ $.ajax({
|
||||
},
|
||||
error: function (err) {
|
||||
console.log('文件读取失败');
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
我们可以看到,上面的代码中,成功回调和失败回调,写法不统一,需要单独记忆,容易出错。
|
||||
|
||||
**小结**:
|
||||
|
||||
在 ES5 中,当进行多层嵌套回调时,会导致代码层次过多,很难进行后续维护和二次开发;而且会导致**回调地狱**的问题。ES6 中的 Promise 就可以解决这两个问题。
|
||||
|
||||
当然, Promise 的更强大功能,不止于此。我们来一探究竟。
|
||||
### Promise 的介绍和优点
|
||||
|
||||
ES6 中的 Promise 是异步编程的一种方案。从语法上讲,Promise 是一个对象,它可以获取异步操作的消息。
|
||||
@@ -108,15 +123,21 @@ Promise 的伪代码结构,大概是这样的:
|
||||
```js
|
||||
// 伪代码1
|
||||
myPromise()
|
||||
.then(function () { }, function () { })
|
||||
.then(function () { }, function () { })
|
||||
.then(function () { }, function () { })
|
||||
.then(
|
||||
function () {},
|
||||
function () {}
|
||||
)
|
||||
.then(
|
||||
function () {},
|
||||
function () {}
|
||||
)
|
||||
.then(
|
||||
function () {},
|
||||
function () {}
|
||||
);
|
||||
|
||||
// 伪代码2
|
||||
是时候展现真正的厨艺了()
|
||||
.然后(买菜)
|
||||
.然后(做饭)
|
||||
.然后(洗碗)
|
||||
是时候展现真正的厨艺了().然后(买菜).然后(做饭).然后(洗碗);
|
||||
```
|
||||
|
||||
上面的伪代码可以看出,即便在业务逻辑上是层层嵌套,但是代码写法上,却十分优雅,也没有过多的嵌套。
|
||||
@@ -131,6 +152,8 @@ myPromise()
|
||||
|
||||
(3)通过 promise.then() 处理返回结果(这里的 `promise` 指的是 Promise 实例)。
|
||||
|
||||
Promise的精髓在于**对异步操作的状态管理**。
|
||||
|
||||
接下来,我们来具体看看, promise 的代码是怎么写的。
|
||||
|
||||
### Promise 处理异步任务的过程
|
||||
@@ -259,9 +282,7 @@ try-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 ⽅法的第⼆个参数进⾏捕获。
|
||||
|
||||
|
||||
## Promise 规范
|
||||
|
||||
### Promise 规范解读
|
||||
|
||||
Promise 是⼀个拥有 then ⽅法的对象或函数。任何符合 promise 规范的对象或函数都可以成为 Promise。
|
||||
|
||||
关于promise 规范的详细解读,可以看下面这个链接:
|
||||
关于 promise 规范的详细解读,可以看下面这个链接:
|
||||
|
||||
- Promises/A+ 规范:<https://promisesaplus.com/>
|
||||
- Promises/A+ 规范:<https://promisesaplus.com/>
|
||||
|
||||
## promise 对象的 3 个状态
|
||||
|
||||
@@ -483,8 +503,7 @@ request1()
|
||||
|
||||
## 总结
|
||||
|
||||
|
||||
了解这些内容之后, 你已经对 Promise 有了基本了解。下一篇文章,我们来讲一讲 Promise在实战开发的常见用法。
|
||||
了解这些内容之后, 你已经对 Promise 有了基本了解。下一篇文章,我们来讲一讲 Promise 在实战开发的常见用法。
|
||||
|
||||
## 参考链接
|
||||
|
||||
|
||||
Reference in New Issue
Block a user