当前位置: 首页 > 知识库问答 >
问题:

javascript - 使用async await时如何在不确定时间的回调函数中退出?

子车英达
2024-07-12
const a = (): Promise<void> => {
  return new Promise((resolve) => {
    const callback = (mutations: MutationRecord[]) => {
      // 监听按钮的某个属性变化,此处退出函数
      resolve();
    };
    const observer = new MutationObserver(callback);
    observer.observe(buttonEl, {
      attributes: true,
    });

    // 调用一个Promise函数,成功后触发按钮的点击事件,然后监听按钮的属性变化
    p().then(() => {
      buttonEl.click();
    });
  });
};

const b = async (): Promise<void> => {
  const callback = (mutations: MutationRecord[]) => {
    // 监听按钮的某个属性变化,怎么在此处退出函数?
  };
  const observer = new MutationObserver(callback);
  observer.observe(buttonEl, {
    attributes: true,
  });

  // 调用一个Promise函数,成功后触发按钮的点击事件,然后监听按钮的属性变化
  await p();
  buttonEl.click();
};

如上述示例代码,a是常规的Promise写法,现在想要改成b那样的async写法,请问该怎么办?

想要这么改的原因是函数内部的逻辑逐渐复杂,会调用多个Promise函数,常规写法会陷入层层嵌套的窘境,不利于维护。

共有3个答案

严曜文
2024-07-12

只把observer相关逻辑用Promise包起来?

const b = async (): Promise<void> => {
  const promise = new Promise(resolve => {
    const callback = (mutations: MutationRecord[]) => {
      // 监听按钮的某个属性变化,怎么在此处退出函数?
      resolve();
    };
    const observer = new MutationObserver(callback);
    observer.observe(buttonEl, {
      attributes: true,
    });
  })

  // 调用一个Promise函数,成功后触发按钮的点击事件,然后监听按钮的属性变化
  await p();
  buttonEl.click();
  return promise;
};
阚英武
2024-07-12

你的需求可能需要最新的Promise.withResolvers()接口,目前还是Stage-4阶段。

const b = async (): Promise<void> => {
  const { promise, resolve } = Promise.withResolvers<void>()

  const callback = (mutations: MutationRecord[]) => {
    resolve();
  };
  const observer = new MutationObserver(callback);
  observer.observe(buttonEl, {
    attributes: true,
  });

  // 调用一个Promise函数,成功后触发按钮的点击事件,然后监听按钮的属性变化
  await p();
  buttonEl.click();

  // 下面这句也可以用 return promise,取决于你的后续逻辑
  await promise
};


这个功能才出没多久,考虑兼容旧的浏览器,你可能需要更新core-js
另外,你用了TS,如果需要通过类型检查,可能还要把TS更新到5.4或以上,然后在tsconfig.json里确保配置libESNext这一项。

尹弘壮
2024-07-12

b函数中,你无法直接在MutationObserver的回调函数callback中直接“退出”async函数,因为async函数执行的是基于Promise的异步流程,而MutationObserver的回调是一个事件监听器,它并不直接参与Promise的解析或拒绝。

然而,你可以通过其他方式来实现你的目标,比如使用一个外部标志来控制是否继续观察或者解除观察。以下是一个基于你给出的代码示例的修改版本:

const b = async (): Promise<void> => {
  let isObserved = true; // 外部标志

  const callback = (mutations: MutationRecord[]) => {
    // 监听按钮的某个属性变化,当满足条件时停止观察
    if (/* 判断条件 */) {
      if (isObserved) {
        isObserved = false;
        observer.disconnect(); // 停止观察
      }
      // 注意:这里不能直接return退出async函数,但可以通过其他方式(如Promise的resolve)通知外部
    }
  };

  const observer = new MutationObserver(callback);
  observer.observe(buttonEl, {
    attributes: true,
  });

  // 调用一个Promise函数,成功后触发按钮的点击事件,然后监听按钮的属性变化
  await p();
  buttonEl.click();

  // 如果需要等待属性变化后再继续执行后续代码,则需要额外处理
  // 可以通过另一个Promise来等待,比如使用Promise的race来监听某个信号

  // 注意:下面的代码仅用于演示,实际中你可能需要更复杂的逻辑来管理这个Promise
  // let waitForMutation = new Promise<void>((resolve) => {
  //   // 这里添加逻辑来在某些条件下resolve这个Promise
  // });

  // await Promise.race([waitForMutation, someOtherTimeoutOrSignal]);

  // 由于上面的waitForMutation并没有实际实现,所以这里直接返回
  return;
};

请注意,在上面的代码中,我添加了一个isObserved标志来控制是否继续观察。当满足某个条件时,我们设置isObservedfalse并调用observer.disconnect()来停止观察。然而,这并不意味着async函数b会“退出”——它只是停止了对DOM元素的观察。

如果你想要在属性变化后继续执行async函数中的后续代码,你可能需要创建一个新的Promise(如上面的waitForMutation)并在某个条件下解析它。然后,你可以使用await来等待这个Promise,从而暂停async函数的执行直到属性变化发生。但是,由于MutationObserver的回调是异步触发的,你不能直接在回调中解析这个Promise,你需要通过其他方式(如信号量、事件或其他同步原语)来协调。

 类似资料:
  • 问题内容: 例如我想在10.00.00.00 am调用js函数,我该怎么办? 我希望从此代码在00.30开始打开google,然后每隔1分钟就会再次打开它?该代码有什么问题? 问题答案: 您将需要setTimeout来设置计时器,并需要Date来计算计时器需要多长时间才能触发。

  • 如果我使用某种硬编码条件,例如,我会得到Typescript错误消息: 当然,我可以在这里定义来禁用任何TypeScript检查,代码将编译并运行,但我的目标是能够仅通过签名来区分函数(而不依赖于其他约定,如名称或其他标志)。

  • 问题内容: 我试图在jQuery中使用getJSON函数导入一些数据并触发回调函数。回调函数未运行。但是,如果我使用get函数尝试相同的操作,则效果很好。奇怪的是,即使我将“ json”作为类型传递,它也可以与get函数一起使用。为什么会这样呢?我在Firefox 3和IE 7中测试了以下文件: 只要我访问的URL在同一个域中,这似乎都会发生。我尝试传递一些数据,但这没有什么不同。 当然,可以像在

  • 问题内容: 我有一段使用解释器执行的JavaScript代码。 如何测量这些数据库插入操作所花费的时间?我可以计算这段代码前后的日期值之差,但是由于代码的异步特性,这将是不正确的。 问题答案: 使用Node.js 和:

  • 问题内容: 传统上,要在页面加载后调用JavaScript函数,您需要在包含一些JavaScript的正文中添加一个属性(通常只调用一个函数) 页面加载后,我想运行一些JavaScript代码以使用服务器中的数据动态填充页面的某些部分。因为我使用的是JSP片段,所以我无法使用该属性,而JSP片段没有可以添加属性的元素。 还有其他方法可以在加载时调用JavaScript函数吗?我宁愿不使用jQuer

  • 我正在使用jQuery,我有一个函数作为事件回调,所以在这个函数中,“this”代表捕获事件的对象。然而,有一个实例,我想从另一个函数显式调用函数——在这种情况下,我如何在函数中设置“this”等于什么? 例如:

  • 问题内容: 我有这样的代码: 我的问题是,节点在运行时立即终止。它显示“ Icanhasclient”,但没有调用回调内的console.log。 (本例中的mysql是node- mysql 。 有什么办法可以使node.js在退出之前等待回调完成? 问题答案: 回调未排队 节点运行直到所有事件 队列 都为空。诸如以下的调用时,回调将添加到事件 队列 中 已执行。该调用是模块开发人员编写的代码的

  • 问题内容: 我想知道Python脚本是否正确终止。为此,我正在使用,但是问题是我不知道如何区分是使用sys.exit(0)还是非零或异常调用atexit。 推理:如果程序正常结束,它将什么都不做,但是如果程序由于异常结束或返回不同于零的错误代码(退出状态)而结束,则我想触发某些操作。 如果您想知道为什么我不使用try / finally是因为我想为导入通用模块的许多脚本添加相同的行为。我不想修改所