学习笔记 2020-10-30
JavaScript 高级程序设计(第4版) 阅读记录
期约与异步函数
期约
期约的实例方法
非重入期约方法
当期约进入落定状态时,与该状态相关的处理程序仅仅会被排期,而非立即执行。添加在这个处理程序的代码之后的同步代码一定会在处理程序之前先执行。在一个期约上调用 then() 会把 onResolved 处理程序推进消息队列。但这个程序程序在当前线程上的同步代码执行完成前不会执行。
邻近处理程序的执行顺序
如果给期约添加了多个处理程序,当期约状态变化时,相关处理程序会按照它们的顺序依次执行。
拒绝期约与拒绝错误处理
在期约的执行函数或处理程序中抛出错误会导致拒绝,对应的错误对象会成为拒绝的理由。
在期约中抛出错误时,错误实际上是从消息队列中异步抛出的,所以并不会阻止运行时继续执行同步指令。
期约连锁与期约合成
期约连锁
因为每个期约实例的方法都会返回一个新的期约对象,所以方法可以链式调用。
期约图
因为一个期约可以有任意多个处理程序,所以期约连锁可以构建有向非循环图的结构。
Promise.all() 和 Promise.race()
Promise 类提供两个将多个期约实例组合成一个期约的静态方法。
Promise.all()
该方法创建的期约会在一组期约全部解决之后再解决。接收一个可迭代对象。合成的期约只会在每个包含的期约都解决之后才解决。
如果至少有一个包含的期约待定,则合成的期约也会待定。如果有一个包含的期约拒绝,则合成的期约也会拒绝。
如果所有期约都成功解决,则合成期约的解决值就是所有包含期约解决值的数组,按照迭代器顺序。
如果有期约拒绝,则第一个拒绝的期约会将自己的理由作为合成期约的拒绝理由。之后再拒绝的期约不会影响最终期约的拒绝理由。
Promise.race()
该方法返回一个包装期约,是一组集合中最先解决或拒绝的期约的镜像。接收一个可迭代对象。
该方法内部第一个落定的期约,无论是解决还是拒绝,该方法都会包装其解决值或是拒绝理由并返回新期约。
串行期约合成
基于后续期约使用之前期约的返回值来串联期约是期约的基本功能。类似于函数合成。
function addTwo(x) { return x + 2; } function addThree(x) { return x + 3; } function addFive(x) { return x + 5; } function addTen(x) { return addFive(addTwo(addThree(x))); } console.log(addTen(7)); // 17
期约也可以类似合成。
function addTwo(x) { return x + 2; } function addThree(x) { return x + 3; } function addFive(x) { return x + 5; } function addTen(x) { return Promise.resolve(x).then(addTwo).then(addThree).then(addFive); } addTen(8).then(console.log); // 18 function addTwo(x) { return x + 2; } function addThree(x) { return x + 3; } function addFive(x) { return x + 5; } function addTen(x) { return [addTwo, addThree, addFive].reduce((promise, fn) => promise.then(fn), Promise.resolve(x)); } addTen(8).then(console.log); // 18 function addTwo(x) { return x + 2; } function addThree(x) { return x + 3; } function addFive(x) { return x + 5; } function compose(...fns) { return x => fns.reduce((promise, fn) => promise.then(fn), Promise.resolve(x)); } let addTen = compose(addTwo, addThree, addFive); addTen(8).then(console.log); // 18