如何将控制台消息和错误发送到警报中?

18

我想将错误传递给警告以警告用户,在他们的代码中犯了错误,即使他们没有打开控制台。

    var doc=(frame.contentWindow.document || obj.contentDocument|| obj.contentWindow);
    var head = doc.getElementsByTagName('head')[0];
    var scriptElement = doc.createElement('script');
    scriptElement.setAttribute('type', 'text/javascript');
    scriptElement.text = scripts;

    try{
        head.appendChild(scriptElement);
    }
     catch(e){ alert("error:"+e.message +"  linenumber:"+e.lineNumber);}

当脚本出现错误时,appendChild会抛出一个错误,并且直接显示在控制台中。但我希望它能够在警告框中显示,因为这是给孩子们用的,他们可能不会检查控制台。try catch块无法捕获该错误。 我尝试使用eval(scripts)来解决。

   try{
   eval(scripts);} catch(e){ alert("error:"+e.message +"  linenumber:"+e.lineNumber);}

这确实可以工作,但意味着代码会执行两次,在某些情况下非常不方便。

我尝试过对console.error进行猴子补丁:

       console.log=function(){alert("taking over the log");}
       console.error=function(){alert("taking over the log");}

但仅当我使用 console.error 时才有效,而不是在实际错误抛出时。如果不是 console.error,那么在发生真正的错误时,哪个函数会将错误发送到控制台?我能够访问并更改它吗?有什么想法吗?任何帮助都将不胜感激。谢谢Jenita


它对我来说真的不起作用。即使在像这个片段这样的最简形式中也是如此。 - Jenita
我已经将其粘贴在底部。 - Jenita
3个回答

25

虽然try ... catch可以捕获脚本最初运行的代码,但正如Jenita所说,它无法捕获语法错误,而且它也无法捕获稍后执行的回调函数抛出的错误(在try-catch结束后很久后)。这意味着来自setTimeoutaddEventListener传递的任何函数的错误都不会被捕获。

然而,您可以尝试另一种方法。在窗口上注册一个错误监听器。

window.addEventListener("error", handleError, true);

function handleError(evt) {
    if (evt.message) { // Chrome sometimes provides this
      alert("error: "+evt.message +" at linenumber: "+evt.lineno+" of file: "+evt.filename);
    } else {
      alert("error: "+evt.type+" from element: "+(evt.srcElement || evt.target));
    }
}

当从回调函数抛出异常时,将调用此函数。但它也会在一般的 DOM 错误(例如图像加载失败)上触发,这可能不是您感兴趣的。

它还应该在语法错误上触发,但仅当它先能运行时,因此您应该将其放在与可能包含拼写错误的另一个脚本中!(脚本后面的语法错误将导致同一脚本顶部的有效行无法运行。)

不幸的是,在 Firefox 中我从evt中找不到行号的方法。(编辑:请进行一番搜索,现在可能已经有了。)


当尝试编写FastJSLogger时,我发现了这个问题,这是我曾在浏览器开发工具相对较慢的时期使用的页面日志记录器。

为了捕获行号,我开始尝试使用 setTimeoutaddEventListener 的包装器,重新引入了 try-catch。例如:

var realAddEventListener = HTMLElement.prototype.addEventListener;

HTMLElement.prototype.addEventListener = function(type,handler,capture,other){
    var newHandler = function(evt) {
        try {
            return handler.apply(this,arguments);
        } catch (e) {
            alert("error handling "+type+" event:"+e.message +"  linenumber:"+e.lineNumber);
        }
    };

    realAddEventListener.call(this,type,newHandler,capture,other);
};

显然,这应该在注册任何事件侦听器之前完成,甚至可能在加载像jQuery这样的库之前完成,以防止它们在我们能够替换它之前抓取对真正的addEventListener的引用。


1
非常感谢,这正是我所需要的! - Jenita
我似乎无法在这里触发例如Chrome控制台中抛出的“Uncaught(in promise)TypeError:Cannot read properties of undefined”错误。我们是否也期望处理这种情况? - Cheetara
@Cheetara 我看不到你的代码。但是 Promise 的一个常见问题是 then(_) 回调是一个单独的函数,它只会在未来的一个时刻被调用,因此外部的 try-catch 无法捕获其错误。你可以选择:1. 始终添加一个尾随的 .catch() 来处理任何错误(详见此处)。2. 使用 async-await 而不是 .then(),因为 try-catch 在那里有效。3. 监听 unhandledrejection 事件 来捕获任何未捕获的 Promise 错误。 - joeytwiddle

3

好的,那么做这件事情的一种不太优雅但非常高效的方法是“重构”您内在的控制台函数。基本上,您收到的任何错误或警告都是由一个类似于熟悉的console.log()函数的JavaScript函数输出的。我所说的函数是console.warn()、console.info()和console.error()。现在让我们重新映射每个函数的作用:

//remap console to some other output
var console = (function(oldCons){
    return {
        log: function(text){
            oldCons.log(text);
            //custom code here to be using the 'text' variable
            //for example: var content = text;
            //document.getElementById(id).innerHTML = content
        },
        info: function (text) {
            oldCons.info(text);
            //custom code here to be using the 'text' variable
        },
        warn: function (text) {
            oldCons.warn(text);
            //custom code here to be using the 'text' variable
        },
        error: function (text) {
            oldCons.error(text);
           //custom code here to be using the 'text' variable
        }
    };
}(window.console));

//Then redefine the old console
window.console = console;

通常情况下,我强烈建议不要在生产环境中使用类似这样的东西,只限于调试目的。但由于您正在尝试开发一个显示控制台输出的功能,因此界限有些模糊,所以我将把决定权交给您。


1
您可以将脚本放在自己的try/catch块中,例如:
var doc=(frame.contentWindow.document || obj.contentDocument|| obj.contentWindow);
var head = doc.getElementsByTagName('head')[0];
var scriptElement = doc.createElement('script');
scriptElement.setAttribute('type', 'text/javascript');
scriptElement.text = "try{"+scripts+"}catch(e){console.error(e);alert('Found this error: ' + e +'. Check the console.')}"
head.appendChild(scriptElement);

嗨,我尝试了一下,但是没有起作用。有人知道为什么 try catch 块没有捕获 appendChild 周围的错误吗?是因为 appendChild 在其自身代码之后调用另一个函数(可能是 evals),该函数捕获错误并将错误直接发送到控制台吗?有人知道错误是如何发送到控制台的吗?这是错误类的一个方法吗? - Jenita
1
实际上,它可以用于类型错误,但不能用于语法错误。 - Jenita
它也不适用于由回调函数(例如来自setTimeout)或事件处理程序(例如来自addEventListener)抛出的错误。 - joeytwiddle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接