Promise是一种异步编程的解决方案,相比传统回调函数更合理. promise 是什么对于一个对象,想要了解,我们可以直接从其身上的属性和方法入手,我们可以直接在浏览器中打印出来
从结果可以看出 promise 是一个构造函数,有自己的是私有方法,reject、 resolve等方法,也有原型上属于实例对象的方法 then、catch等方法 语法new Promise( function(resolve, reject) {…} / executor / );
下面看一段 promise 的示例 1
2
3
4
5
6
7
8
| let p = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve 是成功后的回调函数,通常的做法是将异步操作成功的结果作为参数传递给resolve
resolve('ok')
}, 1000)
})
p.then(res => console.log(res)) // 输出ok
|
注意: 上面的代码,只是 new 了一个 Promise 对象,并没有调用就执行了。我们一般是封装成一个函数,在需要的时候去调用这个函数 一个 Promise 有以下几种状态: - pending: 初始状态,既不是成功,也不是失败状态。
- fulfilled: 意味着操作成功完成。
- rejected: 意味着操作失败。
Promise的构造函数接受一个参数,是函数;并且传入两个参数:resolve,reject,分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数。resolve 和 reject 函数被调用时,分别将promise的状态改为fulfilled(完成)或rejected(失败) p 对象调用了 then 方法并传入了一个箭头函数,箭头函数的参数就是执行异步操作成功后的结果,then 方法可以传入两个回调函数,第一个处理执行异步成功的回调函数,第二个处理异步执行失败的回调函数 1
2
3
4
5
| p.then(res => {
// 处理 resolve
}, err => {
// 处理reject
})
| promise 链式操作使用 Promise 分装一个文件读取的方法 1
2
3
4
5
6
7
8
9
10
| const fs = require('fs')
function getFileByPath(path) {
return new Promise((resolve, reject) => {
fs.readFile(path, 'utf-8', (err, data) => {
if (err) return reject(err)
resolve(data)
})
})
}
|
有这样一个需求,当文件1读取成功的时候才能读取文件2,我们可以这样编码 1
2
3
4
5
6
7
8
| getFileByPath('/user/admin/desktop/file/1.txt').then(res => {
console.log(res) // 文件1的内容
// 继续读取文件2, 我们并不是直接在方法后面调用 then 而是使用rerturn将其返回,在外面继续调用 then 实现链式编程,并且避免了回调地狱
return getFileByPath('/user/admin/desktop/file/2.txt')
}, err => console.log('读取失败了'))
.then(res => {
console.log(res) // 文件2的内容
})
| catch 的用法Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个 catch 语句捕获。注意:因此无法知道错误是哪个Promise产生的,除非设置了不一样的错误提示。 一般,不要在 then 方法中定义 Rejected 状态的回调函数(即 then 的第二个参数),而应该总是使用 catch。 如果没有使用 catch 方法指定错误处理的回调函数,Promise 对象抛出的错误不会传递到外层代码,即不会有任何反应。 catch 方法返回的还是一个 Promise 对象,因此还可以接着调用 then 方法。 如果没有报错,则会跳过 catch 方法,继续执行后面的 then 方法(如果后面还有 then 方法的话)。 1
2
3
4
5
6
7
8
9
10
11
12
13
14
| getFileByPath('/user/admin/desktop/file/1.txt')
.then(res => {
console.log(res) // 文件1的内容
// 此处22.txt 不存在
return getFileByPath('/user/admin/desktop/file/22.txt')
})
.then(res => {
console.log(res) // 文件2的内容
return getFileByPath('/user/admin/desktop/file/3.txt')
})
.then (res => {
console.log(res) // 文件3的内容
})
.catch(err => console.log(err))
|
上面的代码因为并没有读取到文件 22.txt 所以直接跳过下面的 then ,直接调用 catch 方法所以最终的结果是输出了文件1的内容和 catch 中的错误信息 使用 es7 的 async 和 await1
2
3
4
5
6
7
| (async () => {
const [err, res] = await getFileByPath('/user/admin/desktop/file/22.txt')
if (err) {
return console.log('出错了')
}
console.log(res)
})() |
|