如何在Chrome的JavaScript中重写/扩展ReferenceError? [英] How can I override/extend ReferenceError in Chrome's JavaScript?

查看:160
本文介绍了如何在Chrome的JavaScript中重写/扩展ReferenceError?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了使调试更容易,我在Chrome中捕获所有控制台日志,以便提交反馈条目的用户也将所有日志提交到我们的服务器。当有人在生产中遇到问题时,我可以首先让他们重新工作,这样我就可以坐下来更彻底地查看所有日志,以确定用户在生产中遇到的任何问题的根本原因。 p>

我用来捕获日志的技术涉及覆盖console.log,以便在第一个参数中输入的所有文本都存储在数组中,同时调用旧功能,以便我可以仍然可以看到控制台中的日志。



问题是偶尔出现未捕获的异常。这些不包含在上传的日志中,因此并不总是清楚导致问题的原因。所以我试着通过编写一个以函数作为参数的JavaScript函数来覆盖ReferenceError,然后返回一个新的函数来处理它,比如将数据存储在变量中,然后调用传统函数作为最后一步:

 函数overrideException(legacyFn){

/ **原始fn的参数** /
返回函数(){

var args = [];

args [0] =参数[0];

//将原始函数的参数传入并将结果存储到
//证明我们覆盖ReferenceError
output =>>+ legacyFn.apply(this ,args).stack;

返回legacyFn.apply(this,arguments);
}

}

为了测试overrideException函数,我在控制台上运行以下代码:

  ReferenceError = overrideException(ReferenceError); 

之后,我通过手动抛出一个ReferenceError来测试返回的函数,即新的ReferenceError:

 抛出新的ReferenceError(YES !! IT WORKS!HAHAHA!); 

在控制台上产生的输出是:

< blockquote>

ReferenceError:YES !!有用! HAHAHA!

从overrideException函数检查全局变量输出显示:它确实运行:

 输出
>> ReferenceError:YES !! IT WORKS!HAHAHA!$在<匿名><匿名>(<匿名>:18:35)b $ b at<匿名>
<匿名>
在对象
.InjectedScript._evaluateOn(< anonymous>:562:39)
at Object.InjectedScript._evaluateAndWrap(< anonymous>:521:52)
at Object.InjectedScript.evaluate(< anonymous> ;: 440:21)

现在,这里是事情开始崩溃的地方。在我们的代码中,我们不会知道何时发生未捕获的异常,所以我通过尝试运行一个不存在的函数来测试它:

  TTT(); 

结果如下:


ReferenceError:ttt未定义

然而,与我们明确抛出错误的情况不同,在这种情况下,该函数不会触发,我们只剩下遗留功能。变量 output 的内容与第一次测试相同。

我们如何重写JavaScript引擎用来引发错误的ReferenceError功能,以便在抛出ReferenceError时使用它?



<请注意,我的问题目前仅限于Chrome。我正在构建Chrome Packaged应用程序。

解决方案

我出于同样的原因做了相当多的研究:记录错误并报告它们。
$ b

覆盖一个本地类型(无论是 ReferenceError 字符串 Array )是不可能的。



运行时,重新定义 window.ReferenceError 不起作用。您可以扩展 ReferenceError 与类似于 ReferenceError.prototype.extension = function(){return 0; } ,甚至可以覆盖 toString (为了保持一致性,请在页面上尝试,而不是开发工具)。



这对你没有什么帮助。



但不用担心....



(1)使用 window.onerror 获取未捕获错误的文件名,1索引行号和0索引位置,以及错误本身。

  var errorData = []; 
onerror = function(message,file,line,position,error){
errorData.push({message:message,file:file,line:line,position:position,error:error});
};

请参阅小提琴为例。由于OP是针对Chrome的,因此只能在Chrome中进行测试。



(2)由于对(1)的改进,这已不再必要,但是为了完整性,我在这里留下了第二个技巧,因为 onerror 不保证适用于所有浏览器上的所有错误。您有时也会看到以下内容:

  var errors = []; 
function protectedFunction(f){
return function(){
try {
f.apply(this,arguments);
} catch(e){
errors.push(e);
throw e;
}
};
}
setTimeout = protectedFunction(setTimeout);
setInterval = protectedFunction(setInterval);
等...

仅供参考,所有这些与已完成的工作非常相似Google Closure Compiler库,位于 goog.debug ,这是在Gmail开发过程中创建的,其目的是为了完成此操作。特别感兴趣的是 goog.debug.ErrorHandler goog.debug.ErrorReporter


To make debugging easier, I'm capturing all of the console logs in Chrome so that users who submit a feedback entry will also submit all of the logs to our server. When someone encounters a problem in production, I can first and foremost get them back to work so that I can then sit down and more thoroughly go through all of the logs to determine the root cause of whatever issue the user encountered in production.

The technique I use to capture the logs involves overriding console.log so that all text entered in the first argument gets stored in an array while simultaneously invoking the legacy function so that I can still see the logs in the console too.

The problem is when there's the occasional uncaught exception. These aren't included in the uploaded logs, so it's not always clear what caused the problem. So I tried overriding ReferenceError by writing a JavaScript function that takes a function as an argument, then returns a new function that does stuff with it, like storing data in a variable, and then invoking the legacy function as the last step:

function overrideException(legacyFn) {  

    /** arguments for original fn **/
    return function() {

        var args = [];

        args[0] = arguments[0];

        // pass in as arguments to original function and store result to 
          // prove we overrode the ReferenceError
        output = ">> " + legacyFn.apply(this, args).stack;

        return legacyFn.apply(this, arguments);
    }           

}

To test the overrideException function, I ran the following code on the console:

ReferenceError = overrideException(ReferenceError);

Afterwards, I tested the returned function, the new ReferenceError, by manually throwing a ReferenceError:

throw new ReferenceError("YES!! IT WORKS! HAHAHA!");

The resulting output on the console is:

ReferenceError: YES!! IT WORKS! HAHAHA!

And checking the global variable output from the overrideException function shows that it did indeed run:

output
  ">> ReferenceError: YES!! IT WORKS! HAHAHA!
  at ReferenceError (<anonymous>)
  at new <anonymous> (<anonymous>:18:35)
  at <anonymous>:2:7
  at Object.InjectedScript._evaluateOn (<anonymous>:562:39)
  at Object.InjectedScript._evaluateAndWrap (<anonymous>:521:52)
  at Object.InjectedScript.evaluate (<anonymous>:440:21)"

Now, here's where things start to fall apart. In our code, we're not going to know when an uncaught exception occurs, so I tested it by attempting to run a function that doesn't exist:

ttt();

Which results in:

ReferenceError: ttt is not defined

However, unlike the case where we explicitly throw an error, in this case, the function doesn't fire, and we're left with only the legacy functionality. The contents of the variable output is the same as in the first test.

So the question seems to be this: How do we override the ReferenceError functionality that the JavaScript engine uses to throw errors so that it's the same one we use when we throw a ReferenceError?

Keep in mind that my problem is limited only to Chrome at this time; I'm building a Chrome Packaged app.

解决方案

I have done quite a bit of research for the same reason: I wanted to log errors and report them.

"Overriding" a native type (whether ReferenceError, String, or Array) is not possible.

Chrome binds these before any Javascript is run, so redefining window.ReferenceError has no effect.

You can extend ReferenceError with something like ReferenceError.prototype.extension = function() { return 0; }, or even override toString (for consistency, try it on the page, not the Dev Tools).

That doesn't help you much.

But not to worry....

(1) Use window.onerror to get file name, 1-indexed line number, and 0-indexed position of uncaught errors, as well as the error itself.

var errorData = [];
onerror = function(message, file, line, position, error) {
    errorData.push({message:message, file:file, line:line, position:position, error:error});
};

See the fiddle for an example. Since the OP was Chrome-specific, this has only been tested to work in Chrome.

(2) Because of improvements to (1), this is no longer necessary, but I leave this second technique here for completeness, and since onerror is not guaranteed to work for all errors on all browsers. You will also sometimes see the following:

var errors = [];
function protectedFunction(f) {
    return function() {
        try {
            f.apply(this, arguments);
        } catch(e) {
            errors.push(e);
            throw e;
        }
    };
}
setTimeout = protectedFunction(setTimeout);
setInterval = protectedFunction(setInterval);
etc...

FYI, all this is very similar to what has been done in the Google Closure Compiler library, in goog.debug, created during Gmail development with the intent of doing exactly this. Of particular interest is goog.debug.ErrorHandler and goog.debug.ErrorReporter.

这篇关于如何在Chrome的JavaScript中重写/扩展ReferenceError?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆