Promise;Promise连锁;函数科里化;async await;

疑问:

  • 什么时候用Promise连锁?什么时候用async await?什么时候用generator?

    • generator是最不常用的,async await是基于genrator+promise实现的,实际应用中在dva的model层才会使用generator生成器。
    • promisePromise连锁更接地气,控制出错中止、错误catch无需额外逻辑,但是代码较深奥,要理解promise连锁传值、抛错、中止机制。
    • async await是封装后的语法糖,代码简洁易懂,但是传值、错误处理、循环中止逻辑需要额外处理(甲之蜜糖,乙之砒霜)。

      书摘&心得:

      1 Promise基础

  • 从前的异步是依靠回调地狱实现的。

  • 所谓Promise就是Promise
  • Promise是一个有状态的对象
    • ❑ 待定(pending)
    • ❑ 兑现(fulfilled,有时候也称为“解决”, resolved)
    • ❑ 拒绝(rejected)
  • 工作原理二图胜千言
    • image.png
    • image.png
  • 非重入(non-reentrancy)
    • 当Promise进入落定状态时,与该状态相关的处理程序仅仅会被排期,而非立即执行。
    • 之前一直是按事件循环来理解的,ES5和ES6事件循环概念不同主要集中在Promise上,这里单独抽离为非重入来理解也许更好
    • image.png
  • 可以在任何地方执行promise的onResolve事件处理程序
    • image.png
  • 在Promise中抛出错误时,并不会阻止运行时继续执行同步指令

    • 因为错误实际上是从消息队列中异步抛出的。

      2 Promise连锁

      每个执行器都返回一个Promise实例。这样就可以让每个后续Promise都等待之前的Promise,也就是串行化异步任务
      .then和.catch也都返回Promise方法,所以连锁书写完全没有问题约连锁可以构建有向非循环图
      1. function delayedResolve(str) {
      2. return new Promise((resolve, reject) => {
      3. console.log(str);
      4. setTimeout(resolve, 1000);
      5. });
      6. }
      7. delayedResolve('p1 exeutor')
      8. .then(() => delayedResolve('p2 exeutor'))
      9. .then(() => delayedResolve('p3 exeutor'))
      10. .then(() => delayedResolve('p4 exeutor'));
      compose尤其适用于带有值传递的Promise连锁
  • 将分片的逻辑和数据隔离在一个个不同的函数中,是解耦的体现

  • 花里胡哨的其实用不到,框架不香吗?老老实实用redux的中间件就完事了

    1. // 关键在于每个函数都要返回值,是链式调用传值的基本要求
    2. function dealNet1(x) { return x+2; }
    3. async function dealNet2(x) {
    4. await sleep(500);
    5. return x+3;
    6. }
    7. function dealNet3(x) { return x+5; }
    8. function compose(...fns) {
    9. // 归并方法的返回值为链式的promise对象,第二个参数Promise.resolve(x)是初始值
    10. // 最终返回一个函数,该函数接收外部传入的x,返回一个promise
    11. return (x) => fns.reduce((promise, fn) => promise.then(fn), Promise.resolve(x))
    12. }
    13. let addTen = compose(dealNet1, dealNet2, dealNet3);
    14. addTen(8).then(console.log); // 18
  • Promise连锁可以构建有向非循环图

    • 所以在写复杂Promise逻辑时最好画张图先。

      3 async await

  • async关键字声明异步函数

    • 可以用在函数声明、函数表达式、箭头函数和方法上:
    • image.png
  • async函数仍然具有普通JavaScript函数的正常行为
  • async函数返回值
    • 异步函数始终返回Promise对象
    • 在异步函数中抛出错误会返回拒绝的Promise
      • image.png
    • 拒绝Promise的错误不会被异步函数捕获
      • image.png
  • await关键字可以暂停异步函数代码的执行
    • 期待(但实际上并不要求)一个实现thenable接口的对象
    • 必须在异步函数中使用
    • 即使await后面跟着一个立即可用的值,函数的其余部分也会被异步求值

      使用async await实现Promise连锁

      ```javascript async function dealNet1(x) { return x+2; } async function dealNet2(x) { return x+3; } async function dealNet3(x) { return x+5; }

async function addTen(x) { for(const fn of [dealNet1, dealNet2, dealNet3]) { x = await fn(x); } return x; } addTen(8).then(console.log); // 18

  1. 相较Promise连锁:
  2. - 缺点:出错中止、函数参数传递、出错处理都要额外书写
  3. - 优点:很符合直觉,代码可读性也很好。
  4. <a name="gseJX"></a>
  5. ## 4 拓展:异步可迭代对象
  6. - 参考资料:[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)
  7. - 可以用for await...of迭代
  8. - 使用Symbol.asyncIterator内置符号标记
  9. - 与上面写的普通async awaitfor of的差别:
  10. - 上面的迭代对象是:迭代器数组
  11. - 下面的迭代对象是:返回值为promise的迭代器对象
  12. - 自定义时,迭代器的next()和return语句需要返回一个promise对象,且用Symbol.asyncIterator标记:
  13. - ![image.png](https://cdn.nlark.com/yuque/0/2021/png/2841570/1614737634421-b2a522c9-0c9d-481f-8c70-fc9516f51060.png#height=448&id=hh9A5&margin=%5Bobject%20Object%5D&name=image.png&originHeight=547&originWidth=795&originalType=binary&ratio=1&size=45063&status=done&style=none&width=651)
  14. - 异步生成器已经实现了异步迭代器协议, 所以可以直接用 for await...of循环。
  15. ```javascript
  16. async function* asyncGenerator() {
  17. var i = 0;
  18. while (i < 3) {
  19. yield i++;
  20. }
  21. }
  22. (async function() {
  23. for await (num of asyncGenerator()) {
  24. console.log(num);
  25. }
  26. })();
  • 究极的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, ‘拿着返回值为所欲为去吧’); } })(); ```