## Promise
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了`Promise`对象。
所谓`Promise`,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
有了`Promise`对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,`Promise`对象提供统一的接口,使得控制异步操作更加容易。
### 简单示例
```
function p (num) {
return new Promise((resolve, reject) => {
if (num >= 0) {
resolve(num)
} else {
reject(new Error('参数不能小于 0'))
}
})
}
```
这里,返回了一个 Promise 对象,如果成功将执行 resolve(num),使用的时候用 then 接收,如果失败,执行 reject() 并抛出一个错误。
成功的调用
```
console.log('-1-')
p(10).then(num => {
console.log(num)
}).catch(e => {
console.log(e)
})
console.log('-2-')
```
输出
```
-1-
-2-
10
```
失败的调用
```
console.log('-1-')
p(-1).then(num => {
console.log(num)
}).catch(e => {
console.log(e)
})
console.log('-2-')
```
输出
```
-1-
-2-
Error: 参数不能小于 0
```
### Promise 新建后就会立即执行
```
let promise = new Promise(function(resolve, reject) {
console.log('Promise');
resolve();
});
promise.then(function() {
console.log('resolved.');
});
console.log('Hi!');
```
输出
```
Promise
Hi!
resolved
```
上面代码中,Promise 新建后立即执行,所以首先输出的是Promise。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出。
### 可以在 .then 回调里返回 Promise
可以在 then 回调里返回 Promise!返回的 promise 会在接下来的 then 被自动打开(unwrapped)
示例,函数仍然使用上述 p() 函数
```
console.log('-1-')
p(10).then(num => {
console.log(num)
return p(15)
}).then(num => {
console.log(num)
return p(-5)
}).catch(e => {
console.log(e)
})
console.log('-2-')
```
输出
```
-1-
-2-
10
15
Error: 参数不能小于 0
```
### 每次调用 .then 都会产生一个新的 Promise
在链式调用 Promise 时,可以不显示声明 return 语句,then 默认会返回一个 Promise
示例,函数仍然使用上述 p() 函数
```
p(10).then(num => (num >= 10 ? 'ok' : 'no'))
.then(console.log)
p(1).then(num => (num >= 10 ? 'ok' : 'no'))
.then(console.log)
```
输出
```
ok
no
```
注意,每次调用 then 返回的都是不同的 Promise 实例,即 p() 、'ok'、'no' 返回的是三个不同的 Promise 实例,如果 p 出错,则会被 rejected,但 p().then 中返回的都是 resolve。
### 将 callback API 转换为 Promise
在 Node.js 中,推荐使用 util.promisify。用来将回调 API 转成 promise 式的:
```
const { promisify } = require('util');
const fs = require('fs');
const readFileAsync = promisify(fs.readFile);
readFileAsync('myfile.txt', 'utf-8')
.then( r => console.log(r) )
.catch( e => console.error(e));
```
### Promise.prototype.finally()
finally 方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。
```
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···})
```
不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数。