位置: 编程技术 - 正文

跟我学习javascript解决异步编程异常方案(java教程 视)

编辑:rootadmin

推荐整理分享跟我学习javascript解决异步编程异常方案(java教程 视),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:java script课程,教程java,java script教程,java教程,java教程,java script课程,java script,java learning,内容如对您有帮助,希望把文章链接给更多的朋友!

一、JavaScript异步编程的两个核心难点

异步I/O、事件驱动使得单线程的JavaScript得以在不阻塞UI的情况下执行网络、文件访问功能,且使之在后端实现了较高的性能。然而异步风格也引来了一些麻烦,其中比较核心的问题是:

1、函数嵌套过深

JavaScript的异步调用基于回调函数,当多个异步事务多级依赖时,回调函数会形成多级的嵌套,代码变成 金字塔型结构。这不仅使得代码变难看难懂,更使得调试、重构的过程充满风险。

2、异常处理

回调嵌套不仅仅是使代码变得杂乱,也使得错误处理更复杂。这里主要讲讲异常处理。

二、异常处理

像很多时髦的语言一样,JavaScript 也允许抛出异常,随后再用一个try/catch 语句块捕获。如果抛出的异常未被捕获,大多数JavaScript环境都会提供一个有用的堆栈轨迹。举个例子,下面这段代码由于'{'为无效JSON 对象而抛出异常。

堆栈轨迹不仅告诉我们哪里抛出了错误,而且说明了最初出错的地方:第4 行代码。遗憾的是,自顶向下地跟踪异步错误起源并不都这么直截了当。

异步编程中可能抛出错误的情况有两种:回调函数错误、异步函数错误。

1、回调函数错误

如果从异步回调中抛出错误,会发生什么事?让我们先来做个测试。

上述应用的结果是一条极其简短的堆栈轨迹。

等等,A 和B 发生了什么事?为什么它们没有出现在堆栈轨迹中?这是因为运行C 的时候,异步函数的上下文已经不存在了,A 和B 并不在内存堆栈里。这3 个函数都是从事件队列直接运行的。基于同样的理由,利用try/catch 语句块并不能捕获从异步回调中抛出的错误。另外回调函数中的return也失去了意义。

看到这里的问题了吗?这里的try/catch 语句块只捕获setTimeout函数自身内部发生的那些错误。因为setTimeout 异步地运行其回调,所以即使延时设置为0,回调抛出的错误也会直接流向应用程序。

总的来说,取用异步回调的函数即使包装上try/catch 语句块,也只是无用之举。(特例是,该异步函数确实是在同步地做某些事且容易出错。例如,Node 的fs.watch(file,callback)就是这样一个函数,它在目标文件不存在时会抛出一个错误。)正因为此,Node.js 中的回调几乎总是接受一个错误作为其首个参数,这样就允许回调自己来决定如何处理这个错误。

2、异步函数错误

由于异步函数是立刻返回的,异步事务中发生的错误是无法通过try-catch来捕捉的,只能采用由调用方提供错误处理回调的方案来解决。

例如Node中常见的function (err, ...) {...}回调函数,就是Node中处理错误的约定:即将错误作为回调函数的第一个实参返回。再比如HTML5中FileReader对象的onerror函数,会被用于处理异步读取文件过程中的错误。

举个例子,下面这个Node 应用尝试异步地读取一个文件,还负责记录下任何错误(如“文件不存在”)。

客户端JavaScript 库的一致性要稍微差些,不过最常见的模式是,针对成败这两种情形各规定一个单独的回调。jQuery 的Ajax 方法就遵循了这个模式。

不管API 形态像什么,始终要记住的是,只能在回调内部处理源于回调的异步错误。

三、未捕获异常的处理

如果是从回调中抛出异常的,则由那个调用了回调的人负责捕获该异常。但如果异常从未被捕获,又会怎么样?这时,不同的JavaScript环境有着不同的游戏规则……

1. 在浏览器环境中

现代浏览器会在开发人员控制台显示那些未捕获的异常,接着返回事件队列。要想修改这种行为,可以给window.onerror 附加一个处理器。如果windows.onerror 处理器返回true,则能阻止浏览器的默认错误处理行为。

在成品应用中, 会考虑某种JavaScript 错误处理服务, 譬如Errorception。Errorception 提供了一个现成的windows.onerror 处理器,它向应用服务器报告所有未捕获的异常,接着应用服务器发送消息通知我们。

2. 在Node.js 环境中

在Node 环境中,window.onerror 的类似物就是process 对象的uncaughtException 事件。正常情况下,Node 应用会因未捕获的异常而立即退出。但只要至少还有一个uncaughtException 事件处理 器,Node 应用就会直接返回事件队列。

但是,自Node 0.8.4 起,uncaughtException 事件就被废弃了。据其文档所言,对异常处理而言,uncaughtException 是一种非常粗暴的机制,请勿使用uncaughtException,而应使用Domain 对象。

Domain 对象又是什么?你可能会这样问。Domain 对象是事件化对象,它将throw 转化为'error'事件。下面是一个例子。

跟我学习javascript解决异步编程异常方案(java教程 视)

源于延时事件的throw 只是简单地触发了Domain 对象的错误处理器。

Error ignored!

很奇妙,是不是?Domain 对象让throw 语句生动了很多。不管在浏览器端还是服务器端,全局的异常处理器都应被视作最后一根救命稻草。请仅在调试时才使用它。

四、几种解决方案

下面对几种解决方案的讨论主要集中于上面提到的两个核心问题上,当然也会考虑其他方面的因素来评判其优缺点。

1、Async.js

首先是Node中非常著名的Async.js,这个库能够在Node中展露头角,恐怕也得归功于Node统一的错误处理约定。 而在前端,一开始并没有形成这么统一的约定,因此使用Async.js的话可能需要对现有的库进行封装。

Async.js的其实就是给回调函数的几种常见使用模式加了一层包装。比如我们需要三个前后依赖的异步操作,采用纯回调函数写法如下:

如果我们采用async库来做:

可以看到,回调函数由原来的横向发展转变为纵向发展,同时错误被统一传递到最后的处理函数中。 其原理是,将函数数组中的后一个函数包装后作为前一个函数的末参数cb传入,同时要求:

每一个函数都应当执行其cb参数;cb的第一个参数用来传递错误。我们可以自己写一个async.waterfall的实现:

Async.js还有series/parallel/whilst等多种流程控制方法,来实现常见的异步协作。

Async.js的问题:

在外在上依然没有摆脱回调函数,只是将其从横向发展变为纵向,还是需要程序员熟练异步回调风格。 错误处理上仍然没有利用上try-catch和throw,依赖于“回调函数的第一个参数用来传递错误”这样的一个约定。

2、Promise方案

ES6的Promise来源于Promise/A+。使用Promise来进行异步流程控制,有几个需要注意的问题, 把前面提到的功能用Promise来实现,需要先包装异步函数,使之能返回一个Promise:

这个函数可以把符合下述规则的异步函数转换为返回Promise的函数:

回调函数的第一个参数用于传递错误,第二个参数用于传递正常的结果。接着就可以进行操作了:

通过Promise,原来明显的异步回调函数风格显得更像同步编程风格,我们只需要使用then方法将结果传递下去即可,同时return也有了相应的意义: 在每一个then的onFullfilled函数(以及onRejected)里的return,都会为下一个then的onFullfilled函数(以及onRejected)的参数设定好值。

如此一来,return、try-catch/throw都可以使用了,但catch是以方法的形式出现,还是不尽如人意。

3、Generator方案

ES6引入的Generator可以理解为可在运行中转移控制权给其他代码,并在需要的时候返回继续执行的函数。利用Generator可以实现协程的功能。

将Generator与Promise结合,可以进一步将异步代码转化为同步风格:

然而我们还需要一个可以自动运行Generator的函数:

用这个函数来调用Generator即可:

可见try-catch和return实际上已经以其原本面貌回到了代码中,在代码形式上也已经看不到异步风格的痕迹。

类似的功能有co/task.js等库实现。

4、ES7的async/await

ES7中将会引入async function和await关键字,利用这个功能,我们可以轻松写出同步风格的代码, 同时依然可以利用原有的异步I/O机制。

采用async function,我们可以将之前的代码写成这样:

和Generator & Promise方案看起来没有太大区别,只是关键字换了换。 实际上async function就是对Generator方案的一个官方认可,将之作为语言内置功能。

async function的缺点:

await只能在async function内部使用,因此一旦你写了几个async function,或者使用了依赖于async function的库,那你很可能会需要更多的async function。

目前处于提案阶段的async function还没有得到任何浏览器或Node.JS/io.js的支持。Babel转码器也需要打开实验选项,并且对于不支持Generator的浏览器来说,还需要引进一层厚厚的regenerator runtime,想在前端生产环境得到应用还需要时间。

标签: java教程 视

本文链接地址:https://www.jiuchutong.com/biancheng/385476.html 转载请保留说明!

上一篇:Bootstrap每天必学之表单(bootstrap技术教程)

下一篇:跟我学习javascript的垃圾回收机制与内存管理(java 视频教程)

  • 单位内部食堂如何做账务处理
  • 金税四期的到来意味着什么
  • 简易计征怎么开票
  • 住宿发票没有天数
  • 电子元器件可以带上飞机吗
  • 政府会计制度银行存款利息咋处理
  • 承包费收入如何入账
  • 农民为什么没有说理的地方
  • 房地产公司产品无偿提供他人使用 税
  • 建筑挂靠企业账务处理
  • 应收账款计提坏账比例
  • 冲减本年利润
  • 贷款利息进项税额
  • 资本公积转增股本个人所得税
  • 餐费开专票有什么影响
  • 没有房产证应该找谁
  • 实务操作中的税会差异有哪些?
  • 还在讨论“税务金四”上线?税务和银行要联手清查单位和个人账户了!
  • 其他应付款如何做账
  • 金税三期核心征管系统行政处罚
  • 企业停产没有收入,费用可以计入长期待摊费用吗
  • 取得进账发票没发票
  • w7com端口设置
  • PHP:oci_new_connect()的用法_Oracle函数
  • php随机ua
  • 个人投资额是什么意思
  • 工程施工广告牌
  • 工程施工和工程结算科目
  • 【强化学习探索01】Win10 下gym安装
  • vue2.0解决跨域问题
  • 水獭冬眠吗?
  • php 查找数组元素
  • 钢管租赁费如何计算
  • 涌泉的准确位置图 图解
  • 拦截器拦截html
  • 出差补贴是额外的吗
  • 对方代垫包装费怎么做分录
  • tomcat结构图
  • mysql有几种基本数据类型
  • mysql数据库常用sql语句
  • 生产型出口企业的概念
  • 开工程款发票有什么规定?
  • 货物样品出口
  • 小规模纳税人免税政策2022
  • 咨询服务业优惠政策
  • 其他权益工具投资出售时账务处理
  • 废旧物资处理的税金
  • 残疾人残保金如何计算
  • 其他应付款长期挂账几年必须转收入
  • 货代是否负责损失
  • 小规模购置金税盘抵税如何申报
  • 营业利润率高好还是低好
  • 销售返利可以计入销售费用吗
  • 装修费用是当月支付吗
  • 销售货物的价外费用如何开票
  • 新准则公允价值变动科目余额为负数
  • 其他应收账款的会计分录
  • 担保费能否抵扣增值税
  • 代收通行费不征税吗
  • 进项发票已入账进项税,但是未抵扣怎么办
  • 出资方式现金
  • 直接费用的定义
  • sql语句基础题及答案
  • freebsd怎么样
  • windows后台启动VirtualBox虚拟机让界面不在出现
  • 不能在windows7里进行设置的网络位置是
  • win8系统怎么设置
  • win10一年更新几次
  • windows7睡眠唤醒快捷键
  • win10 ie桌面图标
  • window.close(); 关闭浏览器窗口js代码的总结介绍
  • Unity AssetBundle爬坑手记
  • Python3使用requests发闪存的方法
  • 如何下载成品油库存
  • 出口退税中的留抵税额
  • 营改增对医药企业影响
  • 出租车发票密码区被撕掉了能报销吗?
  • 税务局函调情况说明
  • 报企业增值税
  • 建筑企业异地经营需要备案吗
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设