https://github.com/MetaMask/safe-event-emitter

safe-event-emitter

An EventEmitter that isolates the emitter from errors in handlers. If an error is thrown in a handler it is caught and re-thrown inside of a setTimeout so as to not interupt the emitter's code flow.

是一个将emitter与处理程序handlers中的错误隔离的事件发射器。如果在处理程序中抛出错误,就会被捕获并在setTimeout中重新抛出,以便不会中断发射器的代码流

API is the same as EventEmitter.

usage

const SafeEventEmitter = require('safe-event-emitter')

const ee = new SafeEventEmitter()
ee.on('boom', () => { throw new Error() })
ee.emit('boom') // no error here // error is thrown after setTimeout

safe-event-emitter/index.js

const util = require('util')
const EventEmitter = require('events/') var R = typeof Reflect === 'object' ? Reflect : null //Reflect是对象则为R,否则R为null
var ReflectApply = R && typeof R.apply === 'function' //当R不为null且R.apply是函数时,ReflectApply为R.apply函数,否则就是定义的ReflectApply函数
? R.apply
: function ReflectApply(target, receiver, args) {
return Function.prototype.apply.call(target, receiver, args);
} module.exports = SafeEventEmitter function SafeEventEmitter() {
EventEmitter.call(this)
} util.inherits(SafeEventEmitter, EventEmitter) SafeEventEmitter.prototype.emit = function (type) {//事件触发函数
// copied from https://github.com/Gozala/events/blob/master/events.js
// modified lines are commented with "edited:"
var args = [];
for (var i = ; i < arguments.length; i++) args.push(arguments[i]); //将传入的参数push进数组args
var doError = (type === 'error'); //即事件的类型是否为“error” var events = this._events;
if (events !== undefined)//当事件被定义了时,即调用过on()进行监听
doError = (doError && events.error === undefined); //事件为error但是events.error没有定义doError才返回true
else if (!doError) //如果不是error事件则返回false
return false; // If there is no 'error' event listener then throw.
if (doError) { //如果为error事件
var er;
if (args.length > ) //且有参数传入
er = args[]; //第一个参数应该为Error
if (er instanceof Error) {//name就将错误抛出
// Note: The comments on the `throw` lines are intentional, they show
// up in Node's output if this results in an unhandled exception.
throw er; // Unhandled 'error' event
}
// At least give some kind of context to the user 否则就说明没有定义Error,那么下面就会定义相应的错误抛出
var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));
err.context = er;
throw err; // Unhandled 'error' event
} var handler = events[type];//得到on()监听时定义的回调函数 if (handler === undefined)//如果回调没定义则返回false
return false; if (typeof handler === 'function') {//如果定义了则调用下面的safeApply(回调函数,上下文环境,参数)
// edited: using safeApply
safeApply(handler, this, args);
} else { //如果回调不是一个函数,而是一个函数数组,则调用arrayClone()
var len = handler.length;
var listeners = arrayClone(handler, len);
for (var i = ; i < len; ++i)
// edited: using safeApply
safeApply(listeners[i], this, args);
} return true;
} function safeApply(handler, context, args) {//就是在context这个上下文环境中,将相应的args参数传给handler回调函数,对回调函数进行调用
try {
ReflectApply(handler, context, args)
} catch (err) { //特别之处就在于在调用回调过程中如果出错了,错误先使用setTimeout压入堆栈,在整个回调函数调用完成后才抛出
// throw error after timeout so as not to interupt the stack
setTimeout(() => {
throw err
})
}
} function arrayClone(arr, n) {
var copy = new Array(n);
for (var i = ; i < n; ++i)
copy[i] = arr[i];
return copy;
}

补充知识:

Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与处理器对象的方法相同。Reflect不是一个函数对象,因此它是不可构造的。

与大多数全局对象不同,Reflect没有构造函数。你不能将其与一个new运算符一起使用,或者将Reflect对象作为一个函数来调用。Reflect的所有属性和方法都是静态的(就像Math对象)。

可以理解为:有这么一个全局对象,上面直接挂载了对象的某些特殊方法,这些方法可以通过Reflect.apply这种形式来使用,当然所有方法都是可以在 Object 的原型链中找到的。

使用reflect的好处

引自知乎专栏:ES6 Reflect

Reflect上面的一些方法并不是专门为对象设计的,比如Reflect.apply方法,它的参数是一个函数,如果使用Object.apply(func)会让人感觉很奇怪。
用一个单一的全局对象去存储这些方法,能够保持其它的JavaScript代码的整洁、干净。不然的话,这些方法可能是全局的,或者要通过原型来调用。
将一些命令式的操作如delete,in等使用函数来替代,这样做的目的是为了让代码更加好维护,更容易向下兼容;也避免出现更多的保留字。

方法:

Reflect对象提供以下静态函数,它们具有与处理器对象方法相同的名称。这些方法中的一些与 Object 上的对应方法相同。

Reflect.apply()                        对一个函数进行调用操作,同时可以传入一个数组作为调用参数。和 Function.prototype.apply() 功能类似。
Reflect.construct() 对构造函数进行 new 操作,相当于执行 new target(...args)。
Reflect.defineProperty() 和 Object.defineProperty() 类似。
Reflect.deleteProperty() 作为函数的delete操作符,相当于执行 delete target[name]。
Reflect.enumerate() 该方法会返回一个包含有目标对象身上所有可枚举的自身字符串属性以及继承字符串属性的迭代器,for...in 操作遍历到的正是这些属性。
Reflect.get() 获取对象身上某个属性的值,类似于 target[name]。
Reflect.getOwnPropertyDescriptor() 类似于 Object.getOwnPropertyDescriptor()。
Reflect.getPrototypeOf() 类似于 Object.getPrototypeOf()。
Reflect.has() 判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同。
Reflect.isExtensible() 类似于 Object.isExtensible().
Reflect.ownKeys() 返回一个包含所有自身属性(不包含继承属性)的数组。
Reflect.preventExtensions() 类似于 Object.preventExtensions()。返回一个Boolean。
Reflect.set() 将值分配给属性的函数。返回一个Boolean,如果更新成功,则返回true。
Reflect.setPrototypeOf() 类似于 Object.setPrototypeOf()。
 

MetaMask/safe-event-emitter的更多相关文章

  1. Event Bus & Event Emitter

    Event Bus & Event Emitter Event Bus https://code.luasoftware.com/tutorials/vuejs/parent-call-chi ...

  2. MetaMask/obs-store

    https://github.com/MetaMask/obs-store ObservableStore ObservableStore is a synchronous in-memory sto ...

  3. metamask源码学习-controller-transaction

    ()metamask-extension/app/scripts/controllers/transactions Transaction Controller is an aggregate of ...

  4. Guide to Porting MetaMask to a New Environment

    https://github.com/MetaMask/metamask-extension/blob/develop/docs/porting_to_new_environment.md MetaM ...

  5. metamask源码学习-controllers-network

    https://github.com/MetaMask/metamask-extension/tree/master/app/scripts/controllers/network metamask- ...

  6. Christmas Trees, Promises和Event Emitters

    今天有同事问我下面这段代码是什么意思: var MyClass = function() { events.EventEmitter.call(this); // 这行是什么意思? }; util.i ...

  7. UVW源码漫谈(番外篇)—— Emitter

    这两天天气凉了,苏州这边连续好几天都是淅淅沥沥的下着小雨,今天天气还稍微好点.前两天早上起来突然就感冒了,当天就用了一卷纸,好在年轻扛得住,第二天就跟没事人似的.在这里提醒大家一下,天气凉了,睡凉席的 ...

  8. 理解Nodejs的Event Loop

    Node的“event loop”主要是用来处理高输出量的.这很神奇,这也是为什么node可以在单线程的情况下同时处理很多的后台操作.本文就会集中讲述event loop是怎么运行的,这样你可以可以使 ...

  9. CustomEvent & Event

    CustomEvent & Event js 自定义事件 const event = new CustomEvent(typeArg, customEventInit); // add an ...

  10. EventBus / Event Bus

    EventBus / Event Bus EventEmitter / Event Emitter https://greenrobot.org/eventbus/documentation/ htt ...

随机推荐

  1. Yapi学习笔记

    . 下载源码:https://github.com/YMFE/yapi 2. 安装MongoDB数据库,下载地址:链接:https://pan.baidu.com/s/1bZKlcy 密码:ah3n ...

  2. mvc导出excel记录

    前言: 记录这篇使用记录,是为了方便以后学习查阅和让没有使用过的人了解一下,其中不足还请见谅.不是很全的文章,大神请绕行.在项目中我们或多或少的会遇到数据导出到excel表格以便线下查看或者记录一些需 ...

  3. C# ACtiveMQ 收发数据

    1.下载ActiveMQ 官方网站下载地址:http://activemq.apache.org/ 2.运行ActiveMQ 解压缩apache-activemq-5.10.0-bin.zip,然后双 ...

  4. [android] 手机卫士自定义组合控件

    设置中心 新建SettingActivity 设置GridView条目的点击事件 调用GridView对象的setOnItemClickListenner()方法,参数:OnItemClickList ...

  5. 数据库编程Case when

    数据库编程题 1. 姓名 日期 是否上班 张三 星期二 是 张三 星期三 是 李四 星期一 是 王五 星期二 是 张三 星期二 是 写出一条SQL语句输出下列结果 姓名 星期一 星期二 星期三 张三 ...

  6. webpack4 系列教程(十): 图片处理汇总

    多图预警!!! 此篇博文共 5 张图(托管在 GitHub),国内用户请移步>>>原文. 或者来我的小站哦 0. 课程源码和资料 本次课程的代码目录(如下图所示): >> ...

  7. SVN多项目并行版本管理解决方案

    1.背景 随着公司业务拓展,各业务部门频繁的需求变更,导致系统集成冲突的问题日益突出. 2.现状 基于SVN版本管理模式,多分支版本并行,分支合并主干交付.多分支开发存在依赖关系且有交付的先后顺序, ...

  8. Spring表单验证(Spring Validation)

    1.基本介绍 之前在项目中做的后台验证就是Spring Validation,最近闲下来了,就来整理一下. 从Spring3.0开始,Spring MVC中提供了对java校验的API支持.在Spri ...

  9. SoapUI SoapUI接口测试之编码设置

    SoapUI接口测试之编码设置 by:授客 QQ:1033553122 问题描述: 实际测试过程中发现,SoapUI提交后的数据,在数据库中查看数据值存储,发现是乱码,如下图: 查找原因,show c ...

  10. 安卓开发_浅谈WebView(转)

    ,有一个功能需要在APP中调用网站 百度了一下,发现需要用WebView来实现 实现方法很容易,我就不在这里写一遍了 ,直接转一下我学习的内容吧 原创作品,允许转载,转载时请务必以超链接形式标明文章  ...