函数莫名被Canceled

发布于 2022-09-12 23:12:50 字数 3697 浏览 19 评论 0

写了一个aop函数,当执行函数返回结果是一个Promise时,after函数存在多个时,只能触发第一个,其他会被Canceled

aop.ts

type handler = (...args: any[]) => Promise<any> | any;
type afterHandler = (res: afterCallbackResult) => any;
type beforeHandler = (...args: any[]) => any;

interface IAop extends handler {
  afterHandlers: afterHandler[];
  beforeHandlers: beforeHandler[];
  after: (afterFn: afterHandler) => IAop;
  before: (beforeFn: beforeHandler) => IAop;
}

interface IAfterSuccess {
  status: 'success';
  value: any;
}
interface IAfterFail {
  status: 'fail';
  error: Error;
}
type afterCallbackResult = IAfterSuccess | IAfterFail;


/**
 * 返回aop函数
 * @param fn 
 * @returns 
 */
function createAop(fn: handler): IAop {
  if (typeof fn !== 'function') {
    throw TypeError('[aop] fn参数应该是一个函数!');
  }

  const handler: IAop = function () {
    const args = arguments;
    const afterHandlers = handler.afterHandlers;
    const beforeHandlers = handler.beforeHandlers;

    // 执行前置函数
    if (Array.isArray(beforeHandlers) && beforeHandlers.length) {
      const isEnd = beforeHandlers.some((h) => {
        const ret = h.apply(this, args);

        // 显示的返回false则终止执行
        return ret === false;
      });

      if (isEnd) return;
    }

    // 执行当前函数
    const ret = fn.apply(this, args);

    /* 执行后置函数 */
    if (!(Array.isArray(afterHandlers) && afterHandlers.length)) {
      return ret;
    }

    const afterFn = (result: afterCallbackResult) => {
      afterHandlers.forEach((h) => {
        h.call(this, result);
      });
    };

    // 非promise类型的执行结果
    if (Object.prototype.toString.call(ret) !== '[object Promise]') {
      afterFn({
        status: 'success',
        value: ret,
      });
      return ret;
    }

    return new Promise((resolve, reject) => {
      ret
        .then((res: any) => {
          resolve(res);
          afterFn({
            status: 'success',
            value: res,
          });
        })
        .catch((err: Error) => {
          reject(err);
          afterFn({
            status: 'fail',
            error: err,
          });
        });
    });
  };

  handler.afterHandlers = [] as afterHandler[];
  handler.beforeHandlers = [] as beforeHandler[];

  handler.after = function (afterFn: afterHandler): IAop {
    if (typeof afterFn !== 'function') {
      throw TypeError('[aop.after] "afterFn" 参数应该是一个函数!');
    }
    handler.afterHandlers.push(afterFn);
    return handler;
  };

  handler.before = function (beforeFn: beforeHandler): IAop {
    if (typeof beforeFn !== 'function') {
      throw TypeError('[aop.before] "beforeFn" 参数应该是一个函数!');
    }
    handler.beforeHandlers.push(beforeFn);
    return handler;
  };

  return handler;
}

export default createAop;

测试代码

const a = aop(function (tt: number) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(tt + 1);
    }, 1000);
  });
})
  .before(function (a: number) {
    console.log('执行前1', a);
  })
  .before(function (a: number) {
    console.log('执行前2', a);
  })
  .after(function (res: any) {
    console.log('执行结果1:', res);
  })
  .after(function (res: any) {
    console.log('执行结果2:', res);
  })
  .after(function (res: any) {
    console.log('执行结果3:', res);
  });

a(33).then((res: number) => {
  console.log(res);
});

测试结果

image.png

预期的结果

执行前1 33
执行前2 33
34
执行结果1: {status: 'success', value: 34}
执行结果2: {status: 'success', value: 34}
执行结果3: {status: 'success', value: 34}

问题一:如何保证执行顺序,现在after函数在执行结果之前执行了。

问题二:为什么其他的after函数会被Canceled?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

菩提树下叶撕阳。 2022-09-19 23:12:50

我在node和浏览器环境里都测试了,没有你说的情况image.png
image.png

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文