JavaScript Promise 使用

Promise

1. Promise 的基本概念

  • Promise 是一个构造函数

    • 我们可以创建 Promise的实例: const p = new Promise();
    • new 出来的 Promise 实例对象,代表一个异步操作
  • Promise.prototype 上包含一个 .then()方法

    • 每一次 new Promise() 构造函数得到的实例对象
    • 都可以通过原型链的方式访问到 .then() 方法,例如 p.then();
  • .then() 方法用来预先指定成功和失败的回调函数

    • p.then(result=>{},error=>{});
    • 成功的回调函数必传,失败的回调函数可选;

2. 基于 then-fs 读取文件内容

node.js 官方提供的js 模块仅支持以回调函数的方式读取文件,不支持 Promise 的调用方式,需要安装 then-fs 以支持Promise

1
2
3
4
5
import thenFs from "then-fs";

thenFs.readFile("./test_file/1","utf-8").then(r1=>console.log(r1),err=>console.log(err));
thenFs.readFile("./test_file/2","utf-8").then(r2=>console.log(r2),err=>console.log(err));
thenFs.readFile("./test_file/3","utf-8").then(r3=>console.log(r3),err=>console.log(err));

2.1 then() 方法的特性

  • 链式调用:返回一个新的 Promise 对象

2.2 顺序读取文件-链式调用

1
2
3
4
5
6
7
8
9
10
thenFs.readFile("./test_file/1",'utf-8')
.then(r1=>{
console.log(r1);
return thenFs.readFile("./test_file/2","utf-8");
}).then(r2=>{
console.log(r2);
return thenFs.readFile("./test_file/3","utf-8")
}).then(r3=>{
console.log(r3);
})

2.3 通过 .catch 捕获错误

  • catch 写最后:中间出错,后面的.then都不执行;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
thenFs.readFile("./test_file/1111",'utf-8')  // 文件不存在,会导致读取失败;
.then(r1=>{
console.log(r1);
return thenFs.readFile("./test_file/2","utf-8");
}).then(r2=>{
console.log(r2);
return thenFs.readFile("./test_file/3","utf-8")
}).then(r3=>{
console.log(r3);
}).catch(err=>{ // 捕获第一行发生的错误,后面的3个 .then 都不执行
console.log(err);
})
/*[Error: ENOENT: no such file or directory, open 'F:\workspace_study\javascript-study\es6-study\test_file\11'] {
errno: -4058,
code: 'ENOENT',
syscall: 'open',
path: 'F:\\workspace_study\\javascript-study\\es6-study\\test_file\\11'
}*/
  • catch 提前:捕获错误后,后面的.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
thenFs.readFile("./test_file/11",'utf-8')
.catch(err=>{
console.log(err); // 由于错误已被及时处理,不影响后续 .then 的正常执行
})
.then(r1=>{
console.log(r1);
return thenFs.readFile("./test_file/2","utf-8");
}).then(r2=>{
console.log(r2);
return thenFs.readFile("./test_file/3","utf-8")
}).then(r3=>{
console.log(r3);
})
/*
[Error: ENOENT: no such file or directory, open 'F:\workspace_study\javascript-study\es6-study\test_file\11'] {
errno: -4058,
code: 'ENOENT',
syscall: 'open',
path: 'F:\\workspace_study\\javascript-study\\es6-study\\test_file\\11'
}
undefined
222
333
*/

2.4 Promise.all()方法

Promise.all() 发起并行的Promise异步操作,等所有的异步操作全部结束后才会执行下一步的.then操作(等待机制)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import thenFs from "then-fs";

const read_arr = [
thenFs.readFile("./test_file/1",'utf-8'),
thenFs.readFile("./test_file/2",'utf-8'),
thenFs.readFile("./test_file/3",'utf-8'),
]

Promise.all(read_arr)
.then(result=>{
console.log(result); // 输出:[ '111', '222', '333' ]
})
.catch(err=>{
console.log(err);
})

2.5 Promise.race() 方法

只要任何一个异步操作完成,就立即执行下一步的.then操作(赛跑机制).

3. 基于 Promise 封装读取文件的方法

封装要求:

  • 方法:getFile(file_path)
  • 返回:Promise实例对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import fs from "fs";

function getFile(file_path){
// resolve 形参:调用 getFile()方法时,通过 .then 指定的 “成功的”回调函数
// reject 形参: 调用 getFile()方法时,通过 .then 指定的 “失败的” 回调函数
return new Promise((resolve,reject)=>{
fs.readFile(file_path,'utf-8',(err,dataStr)=>{
if(err) return reject(err);
resolve(dataStr);
})
});
}

getFile("./test_file/11")
.then(res=>{
console.log(res);
})
.catch(err=>{
console.log(err);
})