MetaMask/safe-event-emitter
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的更多相关文章
- Event Bus & Event Emitter
Event Bus & Event Emitter Event Bus https://code.luasoftware.com/tutorials/vuejs/parent-call-chi ...
- MetaMask/obs-store
https://github.com/MetaMask/obs-store ObservableStore ObservableStore is a synchronous in-memory sto ...
- metamask源码学习-controller-transaction
()metamask-extension/app/scripts/controllers/transactions Transaction Controller is an aggregate of ...
- Guide to Porting MetaMask to a New Environment
https://github.com/MetaMask/metamask-extension/blob/develop/docs/porting_to_new_environment.md MetaM ...
- metamask源码学习-controllers-network
https://github.com/MetaMask/metamask-extension/tree/master/app/scripts/controllers/network metamask- ...
- Christmas Trees, Promises和Event Emitters
今天有同事问我下面这段代码是什么意思: var MyClass = function() { events.EventEmitter.call(this); // 这行是什么意思? }; util.i ...
- UVW源码漫谈(番外篇)—— Emitter
这两天天气凉了,苏州这边连续好几天都是淅淅沥沥的下着小雨,今天天气还稍微好点.前两天早上起来突然就感冒了,当天就用了一卷纸,好在年轻扛得住,第二天就跟没事人似的.在这里提醒大家一下,天气凉了,睡凉席的 ...
- 理解Nodejs的Event Loop
Node的“event loop”主要是用来处理高输出量的.这很神奇,这也是为什么node可以在单线程的情况下同时处理很多的后台操作.本文就会集中讲述event loop是怎么运行的,这样你可以可以使 ...
- CustomEvent & Event
CustomEvent & Event js 自定义事件 const event = new CustomEvent(typeArg, customEventInit); // add an ...
- EventBus / Event Bus
EventBus / Event Bus EventEmitter / Event Emitter https://greenrobot.org/eventbus/documentation/ htt ...
随机推荐
- 《深入理解Java虚拟机》(五)JVM调优 - 工具
JVM调优 - 工具 JConsole:Java监视与管理控制台 JConsole是一个机遇JMX(Java Management Extensions,即Java管理扩展)的JVM监控与管理工具,监 ...
- .NET常用开发工具整理
版本控制和项目管理工具 VisualSVN和AnkhSVN:两款在Visual Studio中管理Subversion的插件.. NuGet和NuGetPackageExplorer:一组用于自动执行 ...
- 漫画揭秘Hadoop MapReduce | 轻松理解大数据
网址:http://www.iqiyi.com/w_19rtz04nh9.html
- [android] 手机卫士读取联系人
获取ContentResolver内容解析器对象,通过getContentResolver()方法 调用ContentResolver对象的query()方法,得到raw_contacts表里面的数据 ...
- How to Find the Standard Deviation in Minitab
Standard deviation, represented by the Greek Letter sigma σ, is a measure of dispersement in statist ...
- Nginx拦截指定国家的IP
Nginx拦截指定国家的IP 一.下载GeoIP数据库 wget http://geolite.maxmind.com/download/geoip/api/c/GeoIP.tar.gz wget h ...
- linq使用Take和Skip实现分页
;//第1页 ;//页大小 var list = list.Skip((pageIndex-1) * pageSize).Take(pageSize).ToList();
- Linux环境变量详解与应用
在bash shell中,环境变量分为: >全局变量 >局部变量 全局变量,不仅对shell可见,对其子进程也可见 查看预设的全局环境变量: ghostwu@dev:~$ printenv ...
- 使用Via浏览器+ADM下载器突破百度网盘下载限速
1.下载必要工具 via浏览器 ADM下载器 2.自定义 UA UA 是一串特殊字符,用来告诉所访问的网站,手机使用的操作系统及版本.CPU 类型.浏览器及版本等信息.UA 内容如下: Mozilla ...
- Python 练习:三级菜单选择城市(二)
优化了上一个三级菜单选择城:http://www.cnblogs.com/klvchen/p/8646466.html info = { 'GuangDong':{ 'GuangZhou': ['Ti ...