Promise;Promise连锁;函数科里化;async await;
疑问:
什么时候用Promise连锁?什么时候用async await?什么时候用generator?
从前的异步是依靠回调地狱实现的。
- 所谓Promise就是Promise
- Promise是一个有状态的对象
- ❑ 待定(pending)
- ❑ 兑现(fulfilled,有时候也称为“解决”, resolved)
- ❑ 拒绝(rejected)
- 工作原理二图胜千言
- 非重入(non-reentrancy)
- 当Promise进入落定状态时,与该状态相关的处理程序仅仅会被排期,而非立即执行。
- 之前一直是按事件循环来理解的,ES5和ES6事件循环概念不同主要集中在Promise上,这里单独抽离为非重入来理解也许更好
- 可以在任何地方执行promise的onResolve事件处理程序
在Promise中抛出错误时,并不会阻止运行时继续执行同步指令
- 因为错误实际上是从消息队列中异步抛出的。
2 Promise连锁
每个执行器都返回一个Promise实例。这样就可以让每个后续Promise都等待之前的Promise,也就是串行化异步任务
.then和.catch也都返回Promise方法,所以连锁书写完全没有问题约连锁可以构建有向非循环图
compose尤其适用于带有值传递的Promise连锁function delayedResolve(str) {
return new Promise((resolve, reject) => {
console.log(str);
setTimeout(resolve, 1000);
});
}
delayedResolve('p1 exeutor')
.then(() => delayedResolve('p2 exeutor'))
.then(() => delayedResolve('p3 exeutor'))
.then(() => delayedResolve('p4 exeutor'));
- 因为错误实际上是从消息队列中异步抛出的。
将分片的逻辑和数据隔离在一个个不同的函数中,是解耦的体现
花里胡哨的其实用不到,框架不香吗?老老实实用redux的中间件就完事了
// 关键在于每个函数都要返回值,是链式调用传值的基本要求
function dealNet1(x) { return x+2; }
async function dealNet2(x) {
await sleep(500);
return x+3;
}
function dealNet3(x) { return x+5; }
function compose(...fns) {
// 归并方法的返回值为链式的promise对象,第二个参数Promise.resolve(x)是初始值
// 最终返回一个函数,该函数接收外部传入的x,返回一个promise
return (x) => fns.reduce((promise, fn) => promise.then(fn), Promise.resolve(x))
}
let addTen = compose(dealNet1, dealNet2, dealNet3);
addTen(8).then(console.log); // 18
Promise连锁可以构建有向非循环图
async关键字声明异步函数
- 可以用在函数声明、函数表达式、箭头函数和方法上:
- async函数仍然具有普通JavaScript函数的正常行为
- async函数返回值
- 异步函数始终返回Promise对象
- 在异步函数中抛出错误会返回拒绝的Promise
- 拒绝Promise的错误不会被异步函数捕获
- await关键字可以暂停异步函数代码的执行
async function addTen(x) { for(const fn of [dealNet1, dealNet2, dealNet3]) { x = await fn(x); } return x; } addTen(8).then(console.log); // 18
相较Promise连锁:
- 缺点:出错中止、函数参数传递、出错处理都要额外书写
- 优点:很符合直觉,代码可读性也很好。
<a name="gseJX"></a>
## 4 拓展:异步可迭代对象
- 参考资料:[https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/for-await...of](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/for-await...of)
- 可以用for await...of迭代
- 使用Symbol.asyncIterator内置符号标记
- 与上面写的普通async await的for of的差别:
- 上面的迭代对象是:迭代器数组
- 下面的迭代对象是:返回值为promise的迭代器对象
- 自定义时,迭代器的next()和return语句需要返回一个promise对象,且用Symbol.asyncIterator标记:
- 
- 异步生成器已经实现了异步迭代器协议, 所以可以直接用 for await...of循环。
```javascript
async function* asyncGenerator() {
var i = 0;
while (i < 3) {
yield i++;
}
}
(async function() {
for await (num of asyncGenerator()) {
console.log(num);
}
})();
- 究极的Promise连锁:
- 多个async function合成一个,避免async await地狱(过多async await导致的代码同步化)
- 通过yield和return控制循环的退出与产出,全局不见promise却能达成类似的效果。(弥补了async await的弱点)
- 语义化佳(结合了async await的优点) ```javascript async function* asyncGenerator(requests) { const {onlinV, basicV} = request; // 按照顺序执行 if(basicV) { const result1 = await dispatch(); if(result1 === ‘fail’) { return ‘出错了!’; } yield result1; } if(onlinV) { const result2 = await dispatch(); yield result2; } }
(async function() { const requests = { onlinV: undefined, basicV: ‘1’ }; for await (requestResult of asyncGenerator(requests)) { console.log(requestResult, ‘拿着返回值为所欲为去吧’); } })(); ```