处理错误后跳过承诺链

2023-11-21

使用https://github.com/kriskowal/q图书馆,我想知道是否可以做这样的事情:

// Module A

function moduleA_exportedFunction() {
  return promiseReturningService().then(function(serviceResults) {
    if (serviceResults.areGood) {
      // We can continue with the rest of the promise chain
    }
    else {
      performVerySpecificErrorHandling();
      // We want to skip the rest of the promise chain
    }
  });
}

// Module B

moduleA_exportedFunction()
  .then(moduleB_function)
  .then(moduleB_anotherFunction)
  .fail(function(reason) {
    // Handle the reason in a general way which is ok for module B functions
  })
  .done()
;

基本上,如果服务结果不好,我想使用模块 A 内部特定的逻辑来处理模块 A 中的故障,但仍然跳过承诺链中剩余的模块 B 函数。

跳过模块 B 函数的明显解决方案是从模块 A 抛出错误/原因。但是,然后我需要在模块 B 中处理该错误。理想情况下,我希望不需要在模块 B 中添加任何额外代码即可完成此操作。那。

这很可能是不可能的:)或者违反了 Q 的某些设计原则。

在这种情况下,您会建议什么样的替代方案?

我想到了两种方法,但都有其缺点:

  1. 从模块A抛出特定错误并向模块B添加特定处理代码:

    .fail(function(reason) {
      if (reason is specificError) {
        performVerySpecificErrorHandling();
      }
      else {
        // Handle the reason in a general way which is ok for module B functions
      }
    })
    
  2. 在模块A中执行自定义错误处理,然后在处理错误后,抛出一个假的拒绝原因。在模块B中,添加一个忽略假原因的条件:

    .fail(function(reason) {
      if (reason is fakeReason) {
        // Skip handling
      }
      else {
        // Handle the reason in a general way which is ok for module B functions
      }
    })
    

解决方案1需要将模块A特定代码添加到模块B。

解决方案 2 解决了这个问题,但是整个假拒绝方法看起来非常黑客。

您能推荐其他解决方案吗?


让我们谈谈控制结构。

在 JavaScript 中,调用函数时代码以两种方式流动。

  • It can return给调用者一个值,表明它已成功完成。
  • It can throw向调用者发出错误,表明发生了异常操作。

它看起来像:

function doSomething(){ // every function ever
  if(somethingBad) throw new Error("Error operating");
  return value; // successful completion.
}

try{
  doSomething();
  console.log("Success");
} catch (e){
  console.log("Boo");
}

Promise 模拟了完全相同的行为。

在 Promises 中,当您在 Promises 中调用函数时,代码以两种方式流动:.then处理程序:

  • It can return指示其成功完成的承诺或值。
  • It can throw指示发生异常状态的错误。

它看起来像:

var doSomething = Promise.method(function(){
  if(somethingBad) throw new Error("Error operating");
  return someEventualValue(); // a direct value works here too
}); // See note, in Q you'd return Q.reject()

Promise.try(function(){ // in Q that's Q().then
  doSomething();
  console.log("Success");
}).catch(function(e){
  console.log("Boo");
});

Promise 模型控制流本身

承诺是概念的抽象排序操作本身。它描述了控制如何从一个语句传递到另一个语句。你可以考虑.then对分号的抽象。

我们来谈谈同步代码

让我们看看同步代码在您的情况下会是什么样子。

function moduleA_exportedFunction() {
  var serviceResults = someSynchronousFunction();
    if (serviceResults.areGood) {
      // We can continue with the rest of our code
    }
    else {
      performVerySpecificErrorHandling();
      // We want to skip the rest of the chain
    }
}

那么,继续我们的其余代码就很简单了returning。这在同步代码和带有 Promise 的异步代码中是相同的。执行非常具体的错误处理也是可以的。

我们如何跳过同步版本中的其余代码?

doA();
doB();
doC(); // make doD never execute and not throw an exception
doD();

好吧,即使不是立即,也有is一种相当简单的方法,通过使 doC 进入无限循环来使 doD 永远不会执行:

function doC() {
    if (!results.areGood) {
      while(true){} // an infinite loop is the synchronous analogy of not continuing
                    // a promise chain.
    }
}

So, it is可能永远不会解决承诺 - 就像其他答案所暗示的那样 - 返回一个待处理的承诺。然而,这是非常糟糕的流量控制,因为意图很难传达给消费者,并且可能很难调试。想象一下以下 API:

moduleA_exportedFunction- 此函数发出 API 请求并将服务作为ServiceData如果数据可用,则对象。否则,它让程序进入死循环.

有点令人困惑,不是吗:)?然而,它确实存在于某些地方。在非常旧的 API 中找到以下内容并不罕见。

some_bad_c_api()- 这个函数 foos a bar,失败时它终止进程.

那么,到底是什么让我们对终止该 API 中的进程感到困扰呢?

这一切都与责任有关。

  • 被调用的 API 负责传达 API 请求是否成功。
  • 呼叫者有责任决定在每种情况下做什么。

就你而言。 ModelA根本就违反了其责任限度,不应该entitled就程序的流程做出此类决定。无论谁消费它都应该做出这些决定。

Throw

更好的解决方案是抛出错误并让消费者处理它。我会用蓝鸟承诺因为它们不仅速度快了两个数量级,而且拥有更现代的 API——它们还拥有更多much更好的调试工具 - 在这种情况下 - 用于条件捕获和更好的堆栈跟踪的糖:

moduleA_exportedFunction().then(function(result){
   // this will only be reached if no error occured
   return someOtherApiCall();
}).then(function(result2){
   // this will be called if the above function returned a value that is not a 
   // rejected promise, you can keep processing here
}).catch(ApiError,function(e){
   // an error that is instanceof ApiError will reach here, you can handler all API
   // errors from the above `then`s in here. Subclass errors
}).catch(NetworkError,function(e){
   // here, let's handle network errors and not `ApiError`s, since we want to handle
   // those differently
}).then(function(){
   // here we recovered, code that went into an ApiError or NetworkError (assuming
   // those catch handlers did not throw) will reach this point.
   // Other errors will _still_ not run, we recovered successfully
}).then(function(){
   throw new Error(); // unless we explicitly add a `.catch` with no type or with 
                      // an `Error` type, no code in this chain will run anyway.
});

因此,在一行中,您将执行在同步代码中执行的操作,就像 Promise 的情况一样。

Note Promise.method is just a convenience function Bluebird has for wrapping functions, I just hate synchronous throwing in promise returning APIs as it creates major breakage.

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

处理错误后跳过承诺链 的相关文章

  • 在节点环境中存根 jQuery.ajax (jQuery 2.x)

    我正在尝试运行一些需要存根的测试jQuery ajax 我正在使用 SinonJS 来做到这一点 它曾经与旧版本的 jQuery 1 x 一起工作得很好 var require jquery var sinon require sinon
  • JavaScript 字符串中的脚本标签[重复]

    这个问题在这里已经有答案了 我遇到一个问题 即 JavaScript 中带引号的字符串内有结束脚本标记 并且它正在杀死脚本 我认为这不是预期的行为 可以在这里看到这样的示例 http jsbin com oqepe edit http js
  • JAVASCRIPT - 为什么这个对象没有改变?

    function myFunc theObject theObject make Ford model Focus year 2006 var mycar make Honda model Accord year 1998 var x my
  • Node js 应用程序错误未响应端口 8080 上的 HTTP ping,站点启动失败。在 Azure 应用程序服务 linux 上(不是 docker)

    Nodejs 应用程序在本地运行 如果直接从 Visual Studio 部署到 Azure 应用程序服务 Linux 也可以在应用程序服务上运行 但在使用 azure devops 部署时不起作用 使用 Visual Studio 的工件
  • 如何在React Native的MapView中设置标记

    我想在React Native中的MapView上设置一个标记 但是通过官方文档找不到任何信息MapView https facebook github io react native docs mapview html content 如
  • 从选择 onChange 调用 javascript 函数 [重复]

    这个问题在这里已经有答案了 所以我有一个简单的 HTML 选择框和一个 javascript 警报功能 我希望选择框有一个 onchange 事件来调用 javascript 警报函数 这是我到目前为止所拥有的 HTML div Type
  • 将时间戳转换为一个数组

    在应用程序脚本 谷歌表中运行 我从 API 获取时间戳并返回此结果 1 6370611672429312E18 1 63706107263277082E18 我执行此代码并且工作正常 但问题不在数组中 我每次都需要它在数组中 const t
  • 在 Firebase Cloud Functions 中仅部署单个非导出函数

    我在我的 firebase 云函数文件中创建了以下函数 function whatsMyName name return your name is name 当我在命令行中运行以下命令时 该函数is部署 firebase deploy on
  • 使用 jQuery inputmask 插件范围 0-100

    如何创建 0 到 100 范围内的掩码 document ready function masked inputmask 您可以使用jquery inputmask regex extensions js为了那个原因 你可以找到带有所有扩展
  • 如何将 Angular Universal 应用程序部署到 Node.js 生产服务器?

    我有一个带有 Universal 的 Angular 8 应用程序 我想将其部署到共享 Web 主机生产服务器 我提前与网络主机核实过 他们告诉我可以在他们的共享网络托管上托管 Angular 通用网络应用程序 但是 无论我做什么 我都无法
  • Express.js 中的自定义回调 get

    我的 app js 中有一个 get app get api personnel api personnel 调用此函数作为回调以从 mongo 加载一些数据 exports personnel function req res var d
  • 如何显示接下来的三个图像单击加载更多按钮

    我需要一个加载更多按钮来显示图像 页面加载时 我显示 3 个图像 单击 加载更多 按钮后 接下来的 3 个图像将显示在屏幕上 我尝试了下面的代码 但它不起作用 你能帮我解决这个问题吗 function item slice 0 2 show
  • Angular 4 Http POST 不起作用

    我希望每个人都做得很好 我最近开始使用 Angular 4 4 我一直在尝试将数据发布到我的 api 服务器 但不幸的是它不起作用 我花了大约两天的时间 但仍然没有成功 甚至已经尝试过 6 7 篇文章角 io https angular i
  • 如何在React中动态分配属性?

    这是一个有两个参数的函数 我要创建的标签的名称 具有以下属性的对象 Using React 我创建一个组件并将该元素渲染到 DOM 问题是我想向元素添加属性 但它不允许循环在元素内设置属性 var Element function elem
  • node.js 模块/导出系统:是否可以将模块导出为函数

    我想在 Dispatch js 中做这样的事情 function handle msg exports handle 这在调用index js中 var dispatch require Dispatch dispatch data 有任何
  • 使用express.js动态加载路线

    我使用express js作为网络服务器 并且想要一种简单的方法来将所有 app get 和 app post 函数分开以分隔文件 例如 如果我想为登录页面指定 get 和 post 函数 我希望在动态加载的路由文件夹中有一个 login
  • Svelte 条件元素类报告为语法错误

    我正在做一个if块每if 块的精简指南 https svelte technology guide if blocks 这看起来很简单 但 Svelte 认为这是一个语法错误 svelte plugin ParseError Unexpec
  • onPress 方法中箭头函数与普通函数的行为

    正在学习 Native React 并学习更多关于 javascript 的知识 所以我仍然不明白它的行为的很多事情 我使用 TouchableOpacity 及其 onPress 属性创建了一个按钮组件 为了让它工作 我必须发送我想要执行
  • Vue - 调度完成后调用 store getter?

    我正在使用 Laravel 5 7 Vue2 Vuex 我在调度调用完成后让 Vue 返回存储值时遇到一些困难 我的申请流程如下 我单击一个提交按钮 该按钮调用组件上的 validate Validate 分派到我的 addLease 操作
  • JavaScript 阶乘防止无穷大

    我一直在 JavaScript 中使用这个函数来计算阶乘数 var f function factorial n if n 0 n 1 return 1 if f n gt 0 return f n return f n factorial

随机推荐

  • 快速展平[任何]数组

    Using this堆栈溢出问题我有以下代码 let numbers 1 2 3 as Any var flattened numbers flatMap 0 print flattened 1 2 3 而不是展平被设置为 1 2 3 我希
  • 我可以像使用 VS 6 一样使用 VS 2010 创建一个简单的数据库浏览器吗?

    最近安装了 VS 2010 的测试版 我很好奇是否有人知道如何让它做一些在 VS 6 中非常简单的事情 要在 VS 6 中创建一个简单的数据库浏览器 您可以使用数据库创建一个 MFC 应用程序视图 连接到 例如 ODBC 连接 然后 有趣的
  • JVM指令基于堆栈的架构的优点

    为什么Java虚拟机设计时没有寄存器来保存中间数据值 相反 每件事都在堆栈上运行 使用基于堆栈的架构而不是寄存器有什么具体的优势吗 我必须恭敬地不同意以前的答案 表达式堆栈存在的假设并不比寄存器存在更好 通常 寄存器机不能直接执行堆栈操作码
  • 如何使用 ipywidget 按钮下载文件?

    我构建了一个 ipywidget 按钮 我希望当单击按钮时 程序进行计算 并得到结果字符串 然后用户可以将该字符串下载为文件 代码是这样的 import ipywidgets as widgets download button widge
  • PHP Curl:SSL 例程:SSL23_GET_SERVER_HELLO:原因(1112)

    我正在尝试执行 HTTPS 请求 curl setopt curl CURLOPT URL https com curl setopt curl CURLOPT RETURNTRANSFER true curl setopt curl CU
  • django 将 models.DecimalField 与表单结合起来 -> 错误:量化结果对于当前上下文来说位数太多

    我想将模型十进制字段与表单选择字段结合起来 模型中的字段 sum models DecimalField max digits 2 decimal places 2 表单中的字段 sum forms ChoiceField choices
  • android 中使用animationSet() 制作动画

    好的 问题就在这里 我的活动中有一个 ImageView 这是它在 main xml 中的外观
  • less.js 在 Chrome 中不起作用

    我注意到less js在 Firefox 中可以工作 但在 Chrome 中不行 还是因为我犯了一个错误 highlight cb1e16 shade1 cb1e16 tone1 5c6f7d grad1 e6edf3 grad2 8a8d
  • 如果变量等于值 php [重复]

    这个问题在这里已经有答案了 我试图在数据插入 MySQL 查询之前进行检查 这是代码 userid vbulletin gt userinfo userid sql3 mysql query SELECT FROM table WHERE
  • Flex/actionscript 中 F5 和浏览器关闭事件的区别

    我使用下面的代码来确定浏览器窗口的关闭 它工作得很好 但是 当用户使用 F5 或单击浏览器刷新按钮刷新页面时 就会出现问题 即使在这种情况下也会调用同一段代码 我想知道是否有什么办法可以使用动作脚本区分浏览器关闭事件和刷新事件 packag
  • WCF:Net.TCP多个绑定,相同端口,不同IP地址

    我遇到了问题 我是 WCF 的新手 因此我们将不胜感激 这是我的代码 public static void StartHosts try Create a new host ServiceHost host new ServiceHost
  • 对齐多个 ggplot 图表(带或不带图例)[重复]

    这个问题在这里已经有答案了 我正在尝试使用 ggplot 绘制一个图表来比较两个变量的绝对值 并显示它们之间的比率 由于比率是无单位的 而值不是无单位的 因此我无法在同一 y 轴上显示它们 因此我想将它们垂直堆叠为两个具有对齐 x 轴的独立
  • Redis - 如何配置自定义转换

    在 spring data redis 中 我们如何需要配置可以从 Spring boot 应用程序或配置自动连接 注入的自定义转换器 我读到 ReadingConverter and WritingConverter来自 Spring D
  • iPhone NSURL 获取最后重定向的 url

    我想知道如何将 NSURL 更新为您的 url 将重定向到的最后一个 url使用 NSURL 或 NSRequest 感谢你的帮助 谢谢 zanque 的解决方案有效 但为了避免下载 无用 数据 我将 http 方法更改为 HEAD NSM
  • 如何根据文件名部分过滤MsBuild中的ItemGroup?

    我有一个ItemGroup包含一些文件 我无法控制如何生成此列表
  • 如何在 Android 中渲染 PDF 文件

    Android 的库中不支持 PDF 有没有办法在Android应用程序中渲染PDF文件 从 API Level 21 Lollipop 开始 Android 提供了Pdf渲染器类 create a new renderer PdfRend
  • 使用控制台应用程序报告关闭时的内存泄漏

    我创建了一个控制台应用程序并设置 ReportMemoryLeaksOnShutdown True 我创建了一个 TStringList 但没有释放它 当程序完成执行时 我会短暂地看到内存泄漏 但随后控制台关闭 我尝试添加 ReadLn 到
  • 当前页面的 UIPageControl 点大小[重复]

    这个问题在这里已经有答案了 我试图找出如何使所选页面的点比其他页面稍大 如下所示 Page 1 Page 2 我可以更改点的颜色 大小all点 背景等 但不适用于specific当前页面的点 如何仅更改当前页面的点大小 这可以是 Swift
  • 删除整个 PHP 类

    class foo 假设该类存在于我的代码中 然后我不再需要该类并希望将其删除 以便稍后我可以用新类替换它 是否可以从运行时删除整个类 不可以 您不能在运行时删除或大幅修改 PHP 类 或函数
  • 处理错误后跳过承诺链

    使用https github com kriskowal q图书馆 我想知道是否可以做这样的事情 Module A function moduleA exportedFunction return promiseReturningServi