有没有办法短路异步/等待流程?

2024-01-12

所有四个函数均在下面调用update回报承诺。

async function update() {
   var urls = await getCdnUrls();
   var metadata = await fetchMetaData(urls);
   var content = await fetchContent(metadata);
   await render(content);
   return;
}

如果我们想在任何给定时间从外部中止序列怎么办?

例如,虽然fetchMetaData正在执行时,我们意识到我们不再需要渲染组件,并且我们想要取消剩余的操作(fetchContent and render)。有没有办法从外部中止/取消这些操作update功能?

我们可以在每个之后检查一个条件await,但这似乎是一个不优雅的解决方案,即使如此,我们也必须等待当前操作完成。


现在执行此操作的标准方法是通过 AbortSignals

async function update({ signal } = {}) {
   // pass these to methods to cancel them internally in turn
   // this is implemented throughout Node.js and most of the web platform
   try {
     var urls = await getCdnUrls({ signal });
     var metadata = await fetchMetaData(urls);
     var content = await fetchContent(metadata);
     await render(content);
   } catch (e) {
      if(e.name !== 'AbortError') throw e;
   }
   return;
}
// usage
const ac = new AbortController();
update({ signal: ac.signal });
ac.abort(); // cancel the update

以下是 2016 年旧内容,小心龙

我刚刚对此进行了一次演讲 - 这是一个可爱的话题,但遗憾的是您不会真正喜欢我将提出的解决方案,因为它们是网关解决方案。

该规范对您有什么作用

“恰到好处”地取消取消实际上非常困难。人们已经为此工作了一段时间,并决定不阻止其上的异步函数。

ECMAScript 核心有两个提案试图解决这个问题:

  • 取消标记 https://github.com/zenparsing/es-cancel-token- 添加了旨在解决此问题的取消令牌。
  • 可取消的承诺 https://github.com/domenic/cancelable-promise- 这增加了catch cancel (e) { 语法和throw.cancel旨在解决这个问题的语法。

两项提案均发生了重大变化过去一周所以我不指望他们能在明年左右到达。这些建议有些互补,并不矛盾。

您可以采取什么措施来解决这个问题

取消令牌很容易实现。遗憾的是你会取消这种取消really想要(又名“第三状态 https://github.com/tc39/proposal-cancelable-promises/blob/2f601ac/Third%20State.md目前,异步函数不可能实现取消(取消也不例外),因为您无法控制它们的运行方式。你可以做两件事:

  • 使用协程代替 -bluebird http://bluebirdjs.com附带使用发电机消除声音的功能,并承诺您可以使用。
  • 使用中止语义实现标记 - 这实际上非常简单,所以让我们在这里完成

取消令牌

好吧,令牌表示取消:

class Token {
   constructor(fn) {
      this.isCancellationRequested = false; 
      this.onCancelled = []; // actions to execute when cancelled
      this.onCancelled.push(() => this.isCancellationRequested = true);
      // expose a promise to the outside
      this.promise = new Promise(resolve => this.onCancelled.push(resolve));
      // let the user add handlers
      fn(f => this.onCancelled.push(f));
   }
   cancel() { this.onCancelled.forEach(x => x); }
}

这会让你做类似的事情:

async function update(token) {
   if(token.isCancellationRequested) return;
   var urls = await getCdnUrls();
   if(token.isCancellationRequested) return;
   var metadata = await fetchMetaData(urls);
   if(token.isCancellationRequested) return;
   var content = await fetchContent(metadata);
   if(token.isCancellationRequested) return;
   await render(content);
   return;
}

var token = new Token(); // don't ned any special handling here
update(token);
// ...
if(updateNotNeeded) token.cancel(); // will abort asynchronous actions

这是一种非常丑陋的工作方式,最好你希望异步函数意识到这一点,但他们没有(yet).

最理想的情况是,所有临时职能部门都会意识到这一点并会throw取消时(同样,只是因为我们不能有第三状态),如下所示:

async function update(token) {
   var urls = await getCdnUrls(token);
   var metadata = await fetchMetaData(urls, token);
   var content = await fetchContent(metadata, token);
   await render(content, token);
   return;
}

由于我们的每个函数都是取消感知的,因此它们可以执行实际的逻辑取消 -getCdnUrls可以中止请求并抛出,fetchMetaData可以中止底层请求并抛出等。

这是一个人可能会写的方式getCdnUrl(注意单数)使用XMLHttpRequest浏览器中的API:

function getCdnUrl(url, token) {
    var xhr = new XMLHttpRequest();
    xhr.open("GET", url);
    var p = new Promise((resolve, reject) => {
      xhr.onload = () => resolve(xhr);
      xhr.onerror = e => reject(new Error(e));
      token.promise.then(x => { 
        try { xhr.abort(); } catch(e) {}; // ignore abort errors
        reject(new Error("cancelled"));
      });
   });
   xhr.send();
   return p;
}

这是我们在没有协程的情况下使用异步函数所能得到的最接近的结果。它不是很漂亮,但肯定有用。

请注意,您希望避免取消被视为异常。这意味着如果你的函数throw取消时,您需要在全局错误处理程序中过滤这些错误process.on("unhandledRejection", e => ...等等。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

有没有办法短路异步/等待流程? 的相关文章

  • 在 userCodeAppPanel 中看不到我的 javascript 代码

    这是来自 Google 电子表格中包含的脚本的代码 唯一的其他代码是onOpen它创建菜单和showDialog 功能 function showDialog userInterface HtmlService createHtmlOutp
  • Jquery文件上传插件进度条

    这个插件 https github com blueimp jQuery File Upload wiki管理网页中的文件上传 并且可以在上传过程中添加很多 UI 元素 您创建一个输入文件类型元素 然后绑定 js 文件 使用实例化代码和 w
  • Javascript 无法正确排序 DECIMAL 数字

    我有一些代码可以按字母顺序对名称进行排序 我遇到的问题是它处理小数的方式 它对名称进行排序 如下所示 我宁愿它按数字递增 DOG 1 0510 DOG 1 1031 DOG 11 1792 DOG 12 0920 DOG 12 1170 D
  • 如何将节点 sqlite3 与 q (promise) 一起使用

    我正在尝试将 Promise 与 sqlite3 一起使用 这是我的源代码的一部分 this deleteTag function tag project var db this db if project return q nfcall
  • 如何将查询参数添加到守卫中的路由并将其传递给 Angular 4 中的组件?

    我在我的 Angular 4 应用程序中使用路由保护 如果条件满足并返回 true 我想向路由添加一个查询参数 这是我一直在研究的代码 Injectable export class ViewGuardService implements
  • “move(-1)”作为 AngularJS 表达式有什么问题吗?

    我收到此错误 parse ueoe Unexpected end of expression move 从这段代码来看
  • 使用 jquery 更改锚文本和图标

    我有一个隐藏或显示 div 的锚标记 但我无法更改它的文本和图标 如何更改文本和图标标签 因为目前它将图标标签解析为常规文本 锚标记 a class collapse info btn i class icon arrow up icon
  • 使用淘汰赛动态显示/隐藏元素

    我有一个表 有四列 即代码 名称 数量和价格 其中 我想动态更改数量列的内容 元素 通常 它应该显示其中显示数量的元素 当用户单击元素时 我想显示该元素 以便用户可以编辑数量 我正在尝试按照 示例2 来实现淘汰赛文档链接 http knoc
  • 如何检查侧边栏视图是否已经在主干中渲染?

    通常 用户通过主页进入网站 然后我在那里渲染侧边栏视图 接下来 用户单击链接 路由器呈现另一个视图并替换原始内容视图 侧边栏视图不会重新渲染 当用户在子页面上单击刷新时 侧边栏不会呈现 如何检查视图是否存在并且已渲染 划分责任并坚持下去 不
  • Lightbox:如何翻译“Image x of x”文本?

    我使用 Lightbox 2 作为图像集 当我的网站的访问者单击该集中的缩略图时 它将显示 图像的放大版本 下面是 描述 取自 a 标题属性 其下方 文本 Image x of x 例如 Image 1 of 12 有谁知道在哪里翻译 更改
  • Jquery 子元素发生变化

    我正在尝试使用 jquery 在子元素 在本例中为 select 更改时触发事件 这是我的 HTML div class row addForm div class col lg 2 col md 2 col sm 3 col xs 6 d
  • Firefox 上的 jquery 焦点未设置

    我想将焦点设置到我的文本区域 以下是我的代码 this textInput val show focus 但它不起作用 实际上 当我按下鼠标按钮时 它会出现 但是当我松开鼠标时 它会从文本区域中删除 因此 经过大量搜索后 我发现 setTi
  • Ajax 函数在重定向后不保存滚动位置

    正如标题所述 我编写了一个 ajax 函数 该函数应该滚动到用户在重定向之前所在的位置 我写了一个alert对于测试场景 它确实触发了 但滚动不断回到顶部 我在这里做错了什么 JavaScript ajax type GET url Adm
  • 如何使用 Node.js 解析 JSON? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我应该如何使用 Node js 解析 JSON 是否有一些模块可以安全地验证和解析 JSON 你可以简单地使用JSON parse h
  • 如何使用转义的 unicode 解码字符串?

    我不确定这叫什么 所以我在搜索时遇到了麻烦 如何使用 unicode 解码字符串http u00253A u00252F u00252Fexample com to http example com使用 JavaScript 我试过unes
  • Intern JS - 如何在链式 Command 方法中使用 Promise.all()?

    我是用 Intern JS 编写测试的新手 并且一直在遵循他们的文档来使用对象接口 https theintern github io intern interface object and 页面对象 https theintern git
  • Jquery Ajax 调用返回 403 状态

    我有一个 jquery Ajax 调用来实现会话的 keepalive 这个 keepAlive 方法将每 20 分钟调用一次 function keepAlive ajax type POST url KeepAliveDummy asp
  • 如何获取从 Express (Node.js) 中的表单传递的数据

    我想获取使用表单从页面传递的数据 并在重定向的页面中使用该数据 我的客户端有这个表格
  • 如何在react.js中将/n替换为换行符?

    我正在尝试更换每一个 n to a br tag in ReactJS In my note note对象有一个包含多个的字符串 n in it 示例注释 注释 test ntest ntest 我尝试过的ReactJS note note
  • 使用 javascript 从亚马逊 URL 中抓取 ASIN

    假设我有一个像这样的亚马逊产品 URL http www amazon com Kindle Wireless Reading Display Generation dp B0015T963C ref amb link 86123711 2

随机推荐

  • 将 git 子模块协议从 git 替换为 http

    我从 git URL 添加一个子模块 以便能够在其中进行开发 现在我想部署应用程序并将 URL 替换为 git 因此它不需要从 Capistrano 对子模块的存储库进行身份验证 编辑 gitmodules 中的 URL 是否足以完成此任务
  • TypeScript -> AST -> TypeScript

    有没有办法将 TypeScript 文件解析为 AST 修改 AST 然后将其解析回 TypeScript 作为工具Esprima http esprima org 埃斯科德根 https github com estools escode
  • setNeedsLayout 和 setNeedsDisplay

    两者之间真正的区别是什么UIView方法setNeedsLayout and setNeedsDisplay 像往常一样 文档对此模糊不清 其实文档对此说得很清楚 设置需求布局 http developer apple com librar
  • 确定锁升级的阈值

    我有一个包含大约 250 万条记录的表 将更新其中大约 70 万条记录 并且希望更新这些记录 同时仍允许其他用户查看数据 我的更新语句看起来像这样 UPDATE A WITH UPDLOCK ROWLOCK SET A field B fi
  • 使用 Cython 编译 Python 脚本是否会减少启动时间?

    众所周知 Python 程序启动速度有点慢 用cython编译整个程序可以解决这个问题吗 None
  • 如何在重定向中发送参数 - php codeigniter

    下面的代码给了我一个错误 我想调用一个函数并使用 php codeigniter 向其传递一个参数 redirect base url MainController Student Login user email 这里 MainContr
  • 无法在管道阶段定义变量

    我正在尝试创建一个声明性 Jenkins 管道脚本 但在简单变量声明方面遇到问题 这是我的脚本 pipeline agent none stages stage first def foo foo fails with WorkflowSc
  • 如何返回前一个索引之后的下一个索引?

    例如 str a b c d e f str indexOf 0 str lastIndexOf 12 如何获取第二个括号中的索引 c d int first str indexOf int next str indexOf first 1
  • 从 MVC / IIS Web 应用程序为包含子域提供服务

    我在 tumblr 上托管我的网站博客 博客 withoomph com 我已经修改了博客上的主题 并且想使用我在主网站上使用的自己的字体 我正在尝试从以下位置获取字体 beta withoomph com 但是 当页面尝试获取字体时 我收
  • aio_write() 和 O_NONBLOCK write() 之间的区别

    aio write 和 O NONBLOCK write 有什么区别 另外 我使用 O NONBLOCK 函数使用文件描述符对文本文件进行 write 操作 并通过在函数前后放置一个计时器来将性能与 aio write 进行比较 当字符串长
  • 使用iOS 9.0中的CNContactPickerViewController,如何启用/禁用单选或多选?

    委托 CNContactPickerDelegate 具有用于单选和多项选择的方法 但是当我们呈现视图控制器时 我们如何指定我们想要单选或多选呢 我想我错过了一些可能也会导致我所描述的问题的东西 CNUI 错误 设置了选择谓词 但委托未实现
  • Woocommerce 3 中的可编辑管理自定义计费字段错误问题

    我在此代码中遇到错误 在订单编辑页面中添加可编辑的自定义计费字段 add filter woocommerce admin billing fields order admin custom fields function order ad
  • WordPress 单个帖子内容不显示

    我有一个 WordPress 博客主题 它可以很好地显示索引上所有帖子的内容 但是当我点击其中一篇帖子时 该帖子的内容是空白的 我似乎不明白为什么 如果我是正确的single php控制该页面 http pastebin com afLVx
  • Service Worker 可以获取并缓存跨源资产吗?

    我正在使用一些服务人员代码Google 的渐进式 Web 应用程序教程 https developers google com web fundamentals codelabs your first pwapp 但我收到错误 Uncaug
  • 在 C++ 中声明“全局”变量时,“静态”究竟意味着什么?

    这是一个范围的扩展我之前的问题 https stackoverflow com questions 3415781 what exactly does static mean when declaring global variables
  • querySelector (GetElementByID) - 多个 ID

    我有将公历日期转换为贾拉里日期的功能 它适用于一个标签 但我在一页中有未指定数量的此标签 并且它必须转换所有主题 我知道 getElementById 一次支持一个名称 我正在尝试 querySelector 和 getElementsBy
  • 在 C 中加载 python pickled 对象

    我知道pickles可以很容易地加载到python中使用 import pickle p pickle load open file pkl 我想知道如何在 python 中的 pyx C 代码中加载相同的 pickle 文件 我没找到直接
  • Android 中的应用内计费。具体方法是?

    我一直致力于在 Android 中为我正在构建的应用程序实现应用内计费 基本应用程序将是免费的 而应用程序内的应用程序将收费 我遵循Android开发者网站中记录的实现方法 但它仍然表示 在具有测试应用程序的设备上处于未发布模式时 我可以访
  • Java 游戏编程:JOGL 与 LWJGL? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我目前正在编写一个炮塔防御风格的游戏 使用GTGE发动机 http www goldenstudios or id products GTGE
  • 有没有办法短路异步/等待流程?

    所有四个函数均在下面调用update回报承诺 async function update var urls await getCdnUrls var metadata await fetchMetaData urls var content