update: promise
This commit is contained in:
parent
8dde4b856e
commit
a0dd8f9261
@ -1,4 +1,4 @@
|
|||||||
## 前言:异步和回调
|
## 前言:异步
|
||||||
|
|
||||||
### 异步
|
### 异步
|
||||||
|
|
||||||
@ -31,20 +31,17 @@ js 中常见的接口调用方式,有以下几种:
|
|||||||
|
|
||||||
- 异步调用的结果如果**存在依赖**,则需要通过回调函数进行嵌套。
|
- 异步调用的结果如果**存在依赖**,则需要通过回调函数进行嵌套。
|
||||||
|
|
||||||
### 回调地狱的举例
|
|
||||||
|
|
||||||
假设买菜、做饭、洗碗、倒厨余垃圾都是异步的。
|
|
||||||
|
|
||||||
但真实的场景中,实际的操作流程是:买菜成功之后,才能开始做饭。做饭成功后,才能开始洗碗。洗碗结束后, 再倒厨余垃圾。这里的一系列动作就涉及到了多层嵌套调用,也就是回调地狱。
|
|
||||||
|
|
||||||
在 ES5 中,当进行多层嵌套回调时,会导致代码层次过多,很难进行后续维护和二次开发;而且会导致**回调地狱**的问题。ES6 中的 Promise 就可以解决这两个问题。
|
## 为什么需要 Promise?
|
||||||
|
|
||||||
## Promise 概述
|
|
||||||
|
|
||||||
### 为什么需要 Promise?
|
|
||||||
|
|
||||||
如上一段所述,Javascript 是⼀⻔单线程语⾔。早期我们解决异步场景时,⼤部分情况都是通过回调函数来进⾏。
|
如上一段所述,Javascript 是⼀⻔单线程语⾔。早期我们解决异步场景时,⼤部分情况都是通过回调函数来进⾏。
|
||||||
|
|
||||||
|
### 回调的定义
|
||||||
|
|
||||||
|
把函数A传给另一个函数B调用,那么函数A就是回调函数。
|
||||||
|
|
||||||
例如在浏览器中发送 ajax 请求,就是常⻅的⼀个异步场景,发送请求后,需要等待一段时间,等服务端响应之后我们才能拿到结果。如果我们希望在异步结束之后执⾏某个操作,就只能通过**回调函数**这样的⽅式进⾏操作。
|
例如在浏览器中发送 ajax 请求,就是常⻅的⼀个异步场景,发送请求后,需要等待一段时间,等服务端响应之后我们才能拿到结果。如果我们希望在异步结束之后执⾏某个操作,就只能通过**回调函数**这样的⽅式进⾏操作。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@ -61,18 +58,72 @@ dynamicFunc(function () {
|
|||||||
|
|
||||||
例如上⾯这个例⼦,dynamicFunc 就是⼀个异步函数,⾥⾯ setTimeout 会在 1s 之后调⽤传⼊的 callback 函数。按照上⾯的调⽤⽅式,最终 1s 之后,会打印 qian gu 这个结果。
|
例如上⾯这个例⼦,dynamicFunc 就是⼀个异步函数,⾥⾯ setTimeout 会在 1s 之后调⽤传⼊的 callback 函数。按照上⾯的调⽤⽅式,最终 1s 之后,会打印 qian gu 这个结果。
|
||||||
|
|
||||||
同样的,如果后续还有内容需要在异步函数结束时输出,就需要多个异步函数进⾏嵌套,⾮常不利于后续的维护,而且会导致**回调地狱**的问题:
|
|
||||||
|
为了能使回调函数以更优雅的⽅式进⾏调⽤,在 ES6 语法中,新增了⼀个名为 Promise 的新规范。
|
||||||
|
|
||||||
|
### 回调的缺点
|
||||||
|
|
||||||
|
回调的写法比较直观,不需要 return,层层嵌套即可。但也存在两个问题:
|
||||||
|
|
||||||
|
- 1、如果嵌套过深,则会出现**回调地狱**的问题。
|
||||||
|
|
||||||
|
- 2、不同的函数,回调的参数,在写法上可能不一致,导致不规范、且需要**单独记忆**。
|
||||||
|
|
||||||
|
我们来具体看看这两个问题。
|
||||||
|
|
||||||
|
**1、回调地狱的问题**:
|
||||||
|
|
||||||
|
如果后续还有内容需要在异步函数结束时输出,就需要多个异步函数进⾏嵌套,⾮常不利于后续的维护,而且会导致**回调地狱**的问题:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
console.log('qiangu1');
|
console.log('qiangu1');
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
console.log('qiangu2');
|
console.log('qiangu2');
|
||||||
|
setTimeout(function () {
|
||||||
|
console.log('qiangu3');
|
||||||
|
}, 3000);
|
||||||
}, 2000);
|
}, 2000);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
```
|
```
|
||||||
|
|
||||||
为了能使回调函数以更优雅的⽅式进⾏调⽤,在 ES6 语法中,新增了⼀个名为 Promise 的新规范。
|
关于回调地狱,我们来举一个形象的例子:
|
||||||
|
|
||||||
|
假设买菜、做饭、洗碗、倒厨余垃圾都是异步的。
|
||||||
|
|
||||||
|
但真实的场景中,实际的操作流程是:买菜成功之后,才能开始做饭。做饭成功后,才能开始洗碗。洗碗完成后, 再倒厨余垃圾。这里的一系列动作就涉及到了多层嵌套调用,也就是回调地狱。
|
||||||
|
|
||||||
|
在 ES5 中,当进行多层嵌套回调时,会导致代码层次过多,很难进行后续维护和二次开发;而且会导致**回调地狱**的问题。ES6 中的 Promise 就可以解决这两个问题。
|
||||||
|
|
||||||
|
**2、回调的写法不一致问题**:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Node.js 读取文件时,成功回调和失败回调,是通过 error参数来区分
|
||||||
|
readFile('d:\\readme.text', function (error, data) {
|
||||||
|
if (error) {
|
||||||
|
console.log('文件读取失败');
|
||||||
|
} else {
|
||||||
|
console.log('文件读取成功');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// jQuery的 ajax 写法中,成功回调和失败回调,是通过两个回调函数来区分
|
||||||
|
$.ajax({
|
||||||
|
url: '/ajax.json',
|
||||||
|
success: function (response) {
|
||||||
|
console.log('文件读取成功');
|
||||||
|
},
|
||||||
|
error: function (err) {
|
||||||
|
console.log('文件读取失败');
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
我们可以看到,上面的代码中,成功回调和失败回调,写法不统一,需要单独记忆,容易出错。
|
||||||
|
|
||||||
|
|
||||||
### Promise 的介绍和优点
|
### Promise 的介绍和优点
|
||||||
|
|
||||||
@ -84,6 +135,24 @@ Promise 对象, 可以**用同步的表现形式来书写异步代码**(也就
|
|||||||
|
|
||||||
- 语法非常简洁、可读性强,便于后期维护。Promise 对象提供了简洁的 API,使得控制异步操作更加容易。
|
- 语法非常简洁、可读性强,便于后期维护。Promise 对象提供了简洁的 API,使得控制异步操作更加容易。
|
||||||
|
|
||||||
|
Promise 的伪代码结构,大概是这样的:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// 伪代码1
|
||||||
|
myPromise()
|
||||||
|
.then(function () { }, function () { })
|
||||||
|
.then(function () { }, function () { })
|
||||||
|
.then(function () { }, function () { })
|
||||||
|
|
||||||
|
// 伪代码2
|
||||||
|
是时候展现真正的厨艺了()
|
||||||
|
.然后(买菜)
|
||||||
|
.然后(做饭)
|
||||||
|
.然后(洗碗)
|
||||||
|
```
|
||||||
|
|
||||||
|
上面的伪代码可以看出,即便在业务逻辑上是层层嵌套,但是代码写法上,却十分优雅,也没有过多的嵌套。
|
||||||
|
|
||||||
## Promise 基础
|
## Promise 基础
|
||||||
|
|
||||||
### Promise 的基本用法
|
### Promise 的基本用法
|
||||||
@ -132,7 +201,7 @@ promiseA()
|
|||||||
|
|
||||||
上方代码中,当从接口返回的数据`data.retCode`的值(接口返回码)不同时,可能会走 resolve,也可能会走 reject,这个由你自己的业务决定。
|
上方代码中,当从接口返回的数据`data.retCode`的值(接口返回码)不同时,可能会走 resolve,也可能会走 reject,这个由你自己的业务决定。
|
||||||
|
|
||||||
上面的写法中,是将 promise 实例定义成了一个**函数** `PromiseA`。我们也可以将 promise 实例定义成一个**变量** `promiseB`,达到的效果是一模一样的。写法如下:(写法上略有区别)
|
上面的写法中,是将 promise 实例定义成了一个**函数** `promiseA`。我们也可以将 promise 实例定义成一个**变量** `promiseB`,达到的效果是一模一样的。写法如下:(写法上略有区别)
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// 第一步:model层的接口封装
|
// 第一步:model层的接口封装
|
||||||
|
Loading…
Reference in New Issue
Block a user