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. [转]简单的动态修改RDLC报表页边距和列宽的方法

    本文转自:http://star704983.blog.163.com/blog/static/136661264201161604413204/ 1.修改页边距 XmlDocument XMLDoc ...

  2. 正则表达式--C#正则表达式的符号及例子

    正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符.及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑. C#中经常会遇到要查找某一个字 ...

  3. T-SQL:批GO使用实例(十四)

    批是由客户端应用程序作为一个单元发送给SQL Server 执行的一条或多条语句  如果批中出现错误就整个批都不会交给SQL SERVER 执行 PRINT '第一批';GO -- Invalid b ...

  4. 近期ASP.NET问题汇总及对应的解决办法

    1. 使用SQL统计一个字符串中指定字符的个数,示例(统计0的个数): ','')) 2. 使用Forms认证,客户端本地时间不对无法登陆系统,解决办法: FormsAuthentication.Re ...

  5. [PHP]算法-替换空格的PHP实现

    替换空格: 请实现一个函数,将一个字符串中的每个空格替换成“%20”.例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy. 思路: 1.先循环一遍,找出 ...

  6. H5调拨打电话界面

    <a href=”tel:15771791266 ”>拨打电话</a> 切记不要用js调用  直接用a标签 苹果安卓塞班都能调起来

  7. sql server:alter database name

    --step 1 : 修改数据库名称 USE master GO ALTER DATABASE GeovinDuCms SET SINGLE_USER WITH ROLLBACK IMMEDIATE ...

  8. 2018-02-27 "Literate Programming"一书摘记之一

    书到后才发现是Knuth的论文集, 第一篇就在网上: Computer programming as an art (1974). 其中"Taste and Style"(品味和风 ...

  9. linux定时任务调度定系统——opencron

    linux定时任务调度定系统——opencron https://gitee.com/terrytan/opencron/#%E8%BF%90%E8%A1%8C%E7%8E%AF%E5%A2%83 一 ...

  10. ​《数据库系统概念》1-数据抽象、模型及SQL

    ​DBMS(database-management system)包括数据库和用于存取数据的程序,DBMS的基本目标是为数据的存取提供方便.高效的方式,此外对大多数企业来说,数据是非常重要的,所以DB ...