• 中断promise


    https://blog.csdn.net/qq_24147051/article/details/108049705

    中断或取消 Promise 链

    Promise 已经成为了 JavaScript 管理异步操作的重要工具之一. 然而, 有的时候还是会很头痛:

    Promise
        // 等价于 `Promise.resolve(undefined).then`.
        .then(() => {
            // 开始.
        })
        .then(() => {
            if (wantToBreakHere) {
                // 怎样在这里终止这个 Promise 链?
            }
        })
        .then(() => {
            // 一定条件下不想被执行的代码.
        });
    

    当然我们可以嵌套后面的 then, 但如果整条链很长很厚, 也必然很痛苦.

    不过很多 Promise 实现都有一个 catch 方法, 我们可以做一点点小动作:

    /** 用于中断的信号 */
    class BreakSignal { }
     
    Promise
        .then(() => {
            // 开始.
        })
        .then(() => {
            if (wantToBreakHere) {
                // 抛出中断信号.
                throw new BreakSignal();
            }
        })
        .then(() => {
            // 需要跳过的部分.
        })
        // 接住中断信号.
        .catch(BreakSignal, () => { });
    

    其实个人觉得这么干还是比较优雅的, 但如果中间还有其他的 onrejected handler, 则需要手动传递 BreakSignal (再次抛出).

    现在考虑另一种不同于 break 的情形:

    page.on('load', () => {
        Promise
            .then(() => asyncMethodA())
            .then(result => asyncMethodB(result))
            .then(result => {
                // 更新一些东西...
            });
    });
    

    如果 load 事件在短时间内触发了两次, 我们则需要取消前一个 Promise 链, 或者至少要防止它执行完成后做一些不该做的事情 (比如更新数据或者 UI).

    那我们可以考虑这么处理:

    class BreakSignal { }
    
    let context;
    
    /** 创建包含上下文信息的 wrapper */
    function createWrapper() {
       let currentContext = context;
    
       return function (handler) {
           return function () {
               if (context !== currentContext) {
                   throw new BreakSignal();
               }
    
               return handler.apply(undefined, arguments);
           };
       };
    }
    
    page.on('unload', () => {
       context = undefined;
    });
    
    page.on('load', () => {
       context = {};
       let wrap = createWrapper();
    
       Promise
           // 包起来~
           .then(wrap(asyncMethodA))
           .then(wrap(asyncMethodB))
           .then(result => {
               // 更新一些东西...
           })
           .catch(BreakSignal, () => { });
    });
    

    ThenFail

    因为平时用的是自己的 Promise 实现 - ThenFail - 所以自己有需求一定要满足自己. 我愉快地添加了伪 break 语句.

    import { Promise } from 'thenfail';
    
    Promise
       .then(() => {
           // 开始.
       })
       .then(() => {
           if (wantToBreakHere) {
               // 就是这么任性.
               Promise.break;
           }
    
           return Promise
               .then(() => {
                   Promise.break;
               })
               .then(() => {
                   // 这里永远也不会执行.
               });
               // 嵌套的情况不需要最下面的 `enclose()`.
       })
       .then(() => {
           // 需要跳过的部分.
       })
       // 结束当前的 Promise 链的上下文 (context), 避免 `break` 掉太多.
       // 如果这个 Promise 链会被返回, 交给不在你控制范围内的代码, 那么 enclose 操作非常重要~
       .enclose();
    

    其实还能 break ThenFail 的 each helper:

    Promise
        .each([1, 2, 3], value => {
            if (value > 1) {
                Promise.break;
     
                // 或者异步地 `break`:
                return Promise
                    .then(() => {
                        // 做一些事情.
                    })
                    .break;
            }
        })
        .then(completed => {
            if (completed) {
                // 一些代码...
            }
        });
    

    当然有的同学可能看出来了, Promise.break 这个伪语句实际上是一个会抛出异常的 getter, 抛出的异常则是类似于 BreakSignal 的这么个东西 (虽然实现上一个是 object1 === object2, 一个是 object instanceof Class).

    前面有提到 ThenFail 中上下文的概念, 如果需要取消相同上下文的整个 Promise 链, 只需要释放对应的 context 即可.

    let context;
     
    page.on('unload', () => {
        context.dispose();
    });
     
    page.on('load', () => {
        let promise = Promise
            .then(() => asyncMethodA())
            .then(result => asyncMethodB(result))
            .then(result => {
                // 更新一些东西...
            });
     
        context = promise.context;
    });
     

    另外, 释放上下文也会释放嵌套的上下文.

  • 相关阅读:
    js实现将字符串里包含手机号的中间四位替换为****
    草稿for套for
    js实现将时间戳转换成2017-05-06 09:03:02
    时间日期校验接口
    JS延迟导航nav
    nav导航
    鼠标滚动请求加载
    常用开源Jabber(XMPP) IM服务器介绍(转)
    01.base-v1.js
    Haproxy安装及配置(转)
  • 原文地址:https://www.cnblogs.com/sunupo/p/15892861.html
Copyright © 2020-2023  润新知