第十一章:期约和异步函数

js的异步行为会推入一个队列中,当前同步代码执行完毕之后,会执行队列中的异步代码,ES6之前多用回调完成异步操作。

期约

promise可以通过new操作符来进行实例化。创建期约时需要传入执行器executor函数作为参数(resolve(),rejected())。

期约状态

期约是一个有状态的对象,可能处于如下 3 种状态之一:

1、待定pending (是期约的最初始状态,可以落定2为兑现状态或者拒绝状态,但是都是不可逆的,即只能改变一次)

2、兑现fulfilled(resolved)表示期约完成

3、拒绝(rejected) 表示期约未完成

通过执行函数控制期约状态

期约的状态是私有的,所以只能在内部进行操作。内部操作在期约的执行器函数中完成,执行器函数主要有两项职责 :初始化期约的异步行为和控制状态的最终转换

其中,控制期约状态的转换是 通过调用它的两个函数参数实现的。这两个函数参数通常都命名为 resolve()和 reject()。调用 resolve()会把状态切换为兑现,调用 reject()会把状态切换为拒绝。另外,调用 reject()也会抛 出错误。执行器函数是同步执行的。无论 resolve()和 reject()中的哪个被调用,状态转换都不可撤销了。于是继续修改状态会静默 失败。

let p1 = new Promise((resolve, reject) => resolve()); 
setTimeout(console.log, 0, p1); // Promise  
let p2 = new Promise((resolve, reject) => reject()); 
setTimeout(console.log, 0, p2); // Promise 

期约的实例方法

Promise.prototype.then():为期约实例添加处理程序的主要方法,它接收最多 两个参数:onResolved 处理程序和 onRejected 处理程序。这两个参数都是可选的,如果提供的话, 则会在期约分别进入“兑现”和“拒绝”状态时执行。

function onResolved(id) { 
 setTimeout(console.log, 0, id, 'resolved');
 } 
function onRejected(id) { 
 setTimeout(console.log, 0, id, 'rejected'); 
} 
let p1 = new Promise((resolve, reject) => setTimeout(resolve, 3000)); 
let p2 = new Promise((resolve, reject) => setTimeout(reject, 3000)); 
p1.then(() => onResolved('p1'), 
 () => onRejected('p1')); 
p2.then(() => onResolved('p2'), 
 () => onRejected('p2')); 
//(3 秒后)
// p1 resolved 
// p2 rejected

Promise.prototype.catch():给期约添加拒绝处理程序。这个方法只接收一个参数: onRejected 处理程序。事实上,这个方法就是一个语法糖,调用它就相当于调用 Promise.prototype. then(null, onRejected)。

Promise.prototype.finally():给期约添加 onFinally 处理程序,这个处理程序在期 约转换为解决或拒绝状态时都会执行。

异步函数

async

async 关键字用于声明异步函数。这个关键字可以用在函数声明、函数表达式、箭头函数和方法上。使用 async 关键字可以让函数具有异步特征,但总体上其代码仍然是同步求值的。

异步函数如果使用 return 关键字返回了值(如果没有 return 则会返回 undefined),这 个值会被 Promise.resolve()包装成一个期约对象。异步函数始终返回期约对象。

await

因为异步函数主要针对不会马上完成的任务,所以自然需要一种暂停和恢复执行的能力。使用 await 关键字可以暂停异步函数代码的执行,等待期约解决。

let p = new Promise((resolve, reject) => setTimeout(resolve, 1000, 3));
p.then((x) => console.log(x)); // 3
// 如果使用async/await可以写成
async function foo() {
    let p = new Promise((resolve, reject) => setTimeout(resolve, 1000, 3));
    console.log(await p);
}
foo(); // 3