Contents
  1. 1. 一、回调地狱的产生
  2. 2. 二、Promise基本语法
    1. 2.0.1. 1. 创建Promise容器
    2. 2.0.2. 2. 如何获取成功和失败的数据
    3. 2.0.3. 3. 解决嵌套问题
    4. 2.0.4. 4. 封装Promise版本的readFile

一、回调地狱的产生

例如下面一段代码,分别访问三个文件,因为都是异步操作,所以无法保证执行结果的顺序]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

var fs = require('fs')

fs.readFile('./data/a.txt', 'utf8', function (err, data) {
if (err) {
throw err
}

var fs = require('fs')

fs.readFile('./data/b.txt', 'utf8', function (err, data) {
if (err) {
throw err
}

var fs = require('fs')

fs.readFile('./data/c.txt', 'utf8', function (err, data) {
if (err) {
throw err
}

如何解决保证执行结果的顺序?
可以使用回调函数进行嵌套

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

var fs = require('fs')

fs.readFile('./data/a.txt', 'utf8', function (err, data) {
if (err) {
throw err
}
console.log(data)
fs.readFile('./data/b.txt', 'utf8', function (err, data) {
if (err) {
throw err
}
console.log(data)
fs.readFile('./data/c.txt', 'utf8', function (err, data) {
if (err) {
throw err
}
console.log(data)
})
})
})

如果嵌套的次数太多就会产生回调地狱

二、Promise基本语法

为了解决以上编码方式带来的回调地狱嵌套,所以在ES6中新增了一个API:promise(一个构造函数)
promise是一个容器,容器中存放了一个异步任务,promise本身不是异步,但是内部封装了一个异步任务— pending,pending的结果只能变为两种:

  • Resolved: 被解决的(成功)
  • Rejected:被拒绝的 (失败)

1. 创建Promise容器

promise 容器一旦被创建就会执行里面的代码。
我创建了一个data目录下的a.txt文件,使用promise访问里面的数据

1
2
3
4
5
6
7
8
9
10
11
12

var fs = require('fs')

new Promise(function(){
fs.readFile('./data/a.txt', 'utf8', function(err, data){
if(err){
console.log(err)
}else{
console.log(data)
}
})
})

但是其实,promisse的访问是异步操作,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

var fs = require('fs')
console.log(1)
new Promise(function(){
console.log(2)
fs.readFile('./data/a.txt', 'utf8', function(err, data){
if(err){
console.log(err)
}else{
console.log(3)
console.log(data)
}
})
})
console.log(4)

异步结果

2. 如何获取成功和失败的数据

使用promise实例对象的then方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

var fs = require('fs')

var p1 = new Promise(function (resolve, reject) {
fs.readFile('./data/a.txt', 'utf8', function (err, data) {//异步任务
if (err) {
//失败调用
//调用的reject就相当于调用then方法的第二个参数-function err
reject(err)
} else {
//成功调用
//调用的resolve方法实际上就是then方法传递的那个function data
resolve(data)
}
})
})


p1
.then(function (data) {
console.log(data)

}, function (err) {
console.log('读取文件失败了', err)
})

3. 解决嵌套问题

当 p1 读取成功的时候,当前函数中 return 的结果就可以在后面的 then 中 function 接收到
当你 return 123 后面就接收到 123
return ‘hello’ 后面就接收到 ‘hello’
没有 return 后面收到的就是 undefined
我们可以 return 一个 Promise 对象
当 return 一个 Promise 对象的时候,后续的 then 中的 方法的第一个参数会作为 p2 的 resolve

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

var fs = require('fs')

var p1 = new Promise(function (resolve, reject) {
fs.readFile('./data/a.txt', 'utf8', function (err, data) {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})

var p2 = new Promise(function (resolve, reject) {
fs.readFile('./data/b.txt', 'utf8', function (err, data) {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})

var p3 = new Promise(function (resolve, reject) {
fs.readFile('./data/c.txt', 'utf8', function (err, data) {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})

p1
.then(function (data) {
console.log(data)
return p2
}, function (err) {
console.log('读取文件失败了', err)
})
.then(function (data) {//该方法作为p2的resolve
console.log(data)
return p3
})
.then(function (data) {//该方法作为p3的resolve
console.log(data)
console.log('end')
})

结果输出三个文件中的数据,同时读取的顺序不会错

4. 封装Promise版本的readFile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

var fs = require('fs')

function pReadFile(filePath) {
return new Promise(function (resolve, reject) {
fs.readFile(filePath, 'utf8', function (err, data) {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
}

pReadFile('./data/a.txt')
.then(function (data) {
console.log(data)
return pReadFile('./data/b.txt')
})
.then(function (data) {
console.log(data)
return pReadFile('./data/c.txt')
})
.then(function (data) {
console.log(data)
})
Contents
  1. 1. 一、回调地狱的产生
  2. 2. 二、Promise基本语法
    1. 2.0.1. 1. 创建Promise容器
    2. 2.0.2. 2. 如何获取成功和失败的数据
    3. 2.0.3. 3. 解决嵌套问题
    4. 2.0.4. 4. 封装Promise版本的readFile