`

javascript调试原理

 
阅读更多

我们先看一下C/C++和java的调试原理

C/C++调试原理:目前比较流行的调试工具是 GDB 和微软的 Visual Studio 自带的 debugger,在这种 debugger 中,首先,需要编译一个“ debug ”模式的程序,将调试语句编译到该程序中。其次,在调试过程中,debugger 将会深层接入程序的运行,掌握和控制运行态的一些信息,并将这些信息及时返回。

Java调试原理:Java的调试使用Java 虚拟机工具接口(Java Virtual Machine Tool Interface,JVMTI)提供的调试接口。包括进入一个函数,进入一个语句的事件,得到当前上下文的API等等,你只要注册了这些事件,调用这些API即可。

从上面可以看出,调试的方式主要有两种,一种是自己写编辑,在目标文件中加入调试代码,由调试代码来做调试工作,另一种是运行该语言的容器本身提供了调试接口。

我们再来看javascript的调试。

目前的javascript调试工具也是用的第二种调试方式,IE和firefox分别提供了javascript的调试接口。

以firefox为例,它提供的调试接口是:jsdIDebuggerService,我们可以向它注入一些调试的钩子,来实现调试,它提供的调试钩子主要有:

钩子类 说明
breakpointHook Called when the engine encounters a breakpoint.
debuggerHook Called when the engine encounters the debugger keyword.
debugHook Called when the errorHook returns false.
errorHook Called when an error or warning occurs.
functionHook Called before and after a function is called.
interruptHook Called before the next PC is executed.
scriptHook Called when a jsdIScript is created or destroyed.
throwHook Called when an exception is thrown (even if it will be caught.)
topLevelHook Called before and after a toplevel script is evaluated.

包括firebug,venkman,ATF,aptana等调试工具都是实现这些钩子类来做调试的,譬如要做错误定位,就要实现errorHook,errorHook有一个方法

onError(message, fileName, lineNo, pos, flags, errnum, exc)就给出了错误信息,错误文件,行号,位置,等信息。只要向jsdIDebuggerService上注册errorHook,firefox发生js错误时就会调用该方法。

这种调试技术目前已经成熟,但是却都是只能在单个浏览器上调试,我们要在其它浏览器上调试还是比较困难的。

开源项目Javascript Debug Toolkit用另一种原理做了跨浏览器调试javascript的工具,和C/C++的调试一样,它先把javascript编译为带调试代码的目标文件,在浏览器中运行,只要这些调试代码能够做到跨浏览器,整个调试工具就能跨浏览器了。

我们看一下Javascript Debug Toolkit是如何工作的。来看一个例子。

源代码

function test(a,b){

    var c = a + b;

    return c;

}

目标调试代码

jsdebug("test.js",1);function test(a,b){

jsdebug("test.js",2);    var c = a + b;

jsdebug("test.js",3);    return c;

jsdebug("test.js",4);}

这样在每一行代码执行前都会调用jsdebug函数,该函数可以向调试服务器发调试通知,可以把当前的context传给调试服务器,调试服务器与调试代码进行交互(通过ajax技术),包括单步执行,跟进,跟出等都会可以实现。

这种技术的最大好处就是跨浏览器,目前已经能够在ie,firefox,safari,chrome,opera以及一些掌机浏览器上调试javascript。相信这种技术也会很快被使用起来,会有更多跨浏览器的javascript调试工具出现。

 

 

javascript调试原理(一)中讲了javascript的调试原理,本单给出一个javascript调试的客户端模拟实现: 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">  
<HTML>  
<HEAD>  
<TITLE> New Document </TITLE>  
<META NAME="Generator" CONTENT="EditPlus">  
<META NAME="Author" CONTENT="">  
<META NAME="Keywords" CONTENT="">  
<META NAME="Description" CONTENT="">  
</HEAD>  
  
<BODY>  
<textarea id="jsstr" readonly style="width:400px;height:200px">  
function test(){  
    var a = test1();  
    var b = test2();  
    var c = "result is " + a + b;  
    alert(c);  
}  
function test1(){  
    return "test1-->abc";  
}  
function test2(){  
    return "test2-->abc";  
}  
test();  
</textarea>  
<div id="result">  
      
</div>  
<script>  
var debugStr = "";  
function jsdebug(resource,line,evalFunc){  
    var lines = debugStr.split("\n");  
    var jsLine = lines[line-1];  
    lines[line-1] = "当前行:--->" + jsLine;  
    var arr = [  
        "调试代码:",  
        lines.join("\n")  
    ];  
    var result = document.getElementById("result");  
    result.innerHTML = result.innerHTML + "<br>执行到第" + line + "行: -->" + jsLine;  
    alert(arr.join("\n"));  
  
}  
function debug(str){  
    var lines = str.split("\n");  
    debugStr = str;  
    var codes = [];  
    for(var i=0;i<lines.length;i++){  
        codes[i] = "jsdebug('test'," + (i+1) + ",function(text){return eval(text)});" + lines[i];  
    }  
    eval(codes.join('\n'));  
}  
debug(document.getElementById('jsstr').value);  
</script>  
</BODY>  
</HTML>  

 

 

 

只要把其中的alert换成同步的ajax请求,一可以实现每句执行时把当前的行号,context等 信息传给调试服务器。 

 

Javascript Debug Toolkit的客户端原理是在这个基础上的,下一篇将展开讲一下这种原理会遇到的问题及解决方法。

 

 

javascript调试原理(二)中给出一个模拟客户端调试的例子,在客户端有两个问题: 

1.如何获得当前的context? 

2.如何做resume,stepinto,stepreturn,stepover? 

本章围绕着这两个问题展开讨论 

1.如何获得当前的context 

我们先看一段代码: 

function test(){  
    this.a = "a";  
    var b = "b";  
}  

 

 

那么在进入test之后,如何获得a和b的值呢? 

a的值比较简单,只要把this传过去,通过for...in语句就可以获得,但是b呢?它相当于一个私有变量,在外面是不能访问的,要访问b只能通过在b所在的作用域中获得,因此我们在插入前面的每一行中要加上一个eval函数,eval函数的作用域是当前行的,所以可以获得当前行的上下文。所以在第二章中才会在每一行加上 

function(text){try{return eval(text)}catch(e){}});  

 

 

我们把a,b,c加上看一下效果 

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">  
<HTML>  
<HEAD>  
<TITLE> New Document </TITLE>  
<META NAME="Generator" CONTENT="EditPlus">  
<META NAME="Author" CONTENT="">  
<META NAME="Keywords" CONTENT="">  
<META NAME="Description" CONTENT="">  
</HEAD>  
  
<BODY>  
<textarea id="jsstr" readonly style="width:400px;height:200px">function test(){  
    var a = test1();  
    var b = test2();  
    var c = "result is " + a + b;  
    alert(c);  
}  
function test1(){  
    return "test1-->abc";  
}  
function test2(){  
    return "test2-->abc";  
}  
test();</textarea>  
<div id="result">  
      
</div>  
<script>  
var debugStr = "";  
function jsdebug(resource,line,evalFunc){  
    var lines = debugStr.split("\n");  
    var jsLine = lines[line-1];  
    lines[line-1] = "当前行:--->" + jsLine;  
    var arr = [  
        "调试代码:",  
        lines.join("\n"),  
        "==========context===========",  
        "a = " + evalFunc("a"),  
        "b = " + evalFunc("b"),  
        "c = " + evalFunc("c"),  
    ];  
    var result = document.getElementById("result");  
    result.innerHTML = result.innerHTML + "<br>执行到第" + line + "行: -->" + jsLine;  
    alert(arr.join("\n"));  
  
}  
function debug(str){  
    var lines = str.split("\n");  
    debugStr = str;  
    var codes = [];  
    for(var i=0;i<lines.length;i++){  
        codes[i] = "jsdebug('test'," + (i+1) + ",function(text){try{return eval(text)}catch(e){}});" + lines[i];  
    }  
    eval(codes.join('\n'));  
}  
debug(document.getElementById('jsstr').value);  
</script>  
</BODY>  
</HTML>  

 

 

在执行到第3,4,5行的时候可以看到a,b,c的值 

这里又有一个问题:我怎么知道函数中有哪些变量? 

这就要用到arguments.callee.caller了,把函数当成一个字条串解析,解析出函数的输入参数及定义的变量,就能拿到一个变量名的集合,然后再一个一个地取值。具体的算法这里就不给出了。 

 

再说第二个问题,如何控制stepinto,stepreturn,resume 

我们需要在客户端维护一个函数的调用栈,这个栈中记录着每一步的调用,在执行的时候根据栈中存的信息和当前的上下文比较,就能拿到当前语句究竟是stepover还是stepinto还是stepreturn。 

 

那么如何做resume呢,客户端维护一份断点列表,执行每一句的时候判断是否到了断点,不在断点就继续执行,到了断点就停止。 

 

这部分内容也不再给出详细代码,请参照Javascript Debug Toolkit的源代码

 

 

开源项目--跨浏览器的javascript调试工具Javascript Debug Toolkit(jsdt) 

http://code.google.com/p/jsdt/ 

jsdt是一个eclipse的插件,要求在eclipse3.2,jre1.5以上运行,可以进行跨浏览器的javascript调试。 

jsdt在eclipse中设置断点,在浏览器中运行,执行到断点时自行中断到调试器 

jsdt可以单步调试,可以查看当前函数的context 

jsdt可跨浏览器调试,目前的浏览器ie,firefox,safari,chrome都支持,其中,因为chrome的bug,css和image不能正常显示 

调试的效果图如下: 

 

 

 

设置断点 

 

 

 

中断 

 

stepOver 

 

stepInto 

 

stepReturn 

 

 

jsdt包含以下几个部分 

1.js引擎,基于rhino引擎,解析js,确定哪一行可以加断点,哪一行不能加断点 

2.jsdt server,是一个http服务器,接管客户端的所有请求 

3.jsdt client,客户端引擎 

4.jsdt debug implement,实现了一套eclipse插件的接口和ui,譬如设置断点等。 

 

jsdt的基本原理如下: 

1.jsdt提供一个http代理,把要访问的文件或url的地址转换成jsdt的server地址 

2.jsdt的server在送给浏览器的每一行javascript代码前加上调试的代码,该调试代码发送ajax请求到jsdt的server,将当前的上下文送给jsdt 

3.jsdt根据上下文在eclipse中中断,显示上下文等。 

4.jsdt根据用户的指令(resume,stepinto,stepover,stepreturn)等回答ajax请求 

5.jsdt的客户端引擎根据server发的指令进行下一步操作

 

  • 大小: 41.3 KB
  • 大小: 43.8 KB
  • 大小: 46.7 KB
  • 大小: 47.2 KB
  • 大小: 46.5 KB

 

 

原文转载自:http://www.iteye.com/topic/299025

 

分享到:
评论

相关推荐

    day13-javascript调试原理.md

    day13-javascript调试原理.md

    JavaScript检测是否开启了控制台(F12调试工具)

    JavaScript检测是否开启了控制台(调试工具) 测试后在chrome有效 不少人防止别人趴源码,一般采用检测按键F12之类的,但是这些基本没什么用 现在介绍一个方法,非常管用,可以检测到你是否开启了控制台程序,可以...

    JavaScript入门经典(第4版 英文版+第3版中文版 附JavaScript参考手册)

    ****JavaScript入门经典(第4版 英文版+第3版中文版 附JavaScript参考手册)****《JavaScript入门经典(第4版)》主要内容:·循序渐进介绍JavaScript基础知识,包括JavaScript的含义、原理和功能·介绍用于创建...

    javascript实战+源码

    第一部分讨论一般性的 JavaScript主题,包括 JavaScript的简史、好的编码习惯、调试技巧和工具等;第二部分是 10个具体项目,每一章都会提出一个不同的应用,分析其内在的工作原理,然后提供能够提高读者技巧的练习...

    JavaScript实战

    第一部分讨论一般性的 Javascript主题,包括 Javascript的简史、好的编码习惯、调试技巧和工具等;第二部分是 10个具体项目,每一章都会提出一个不同的应用,分析其内在的工作原理,然后提供能够提高...

    JavaScript语法约定和程序调试原理解析

    JavaScript 语法约定 1、大小写的区分 1). JavaScript的关键字,永远都是小写的; 2). 内置对象,如Math和Date是以大写字母开头的; 3). 对象的名称通常是小写;若是多个单词,驼峰(Camel)命名法。 驼峰(Camel...

    JavaScript详解(第2版)

     14.2.2 样式表的工作原理   14.3 CSS程序结构   14.3.1 注释   14.3.2 组合   14.4 常用样式表属性   14.4.1 计量单位   14.4.2 使用颜色   14.4.3 使用字体   14.4.4 使用文本   ...

    JavaScript 接口原理与用法实例详解

    本文实例讲述了JavaScript 接口原理与用法。分享给大家供大家参考,具体如下: js接口 意义: 提供一种以说明一个对象应该有哪些方法的手段。 接口是面向对象javascript程序员的工具箱中最有用的工具之一 接口的...

    javascript压缩工具

    但JS不好调试,代码多了也会严重影响速度,当你在为提高了用户体验,做出了很绚丽的效果而欣喜的时候,是否想过优化一下JS的效率,大网站的JS都做了压缩处理。JS的速度分为两种,下载速度和执行速度。要想JS的下载...

    JavaScript 代码压缩加密软件

    但JS不好调试,代码多了也会严重影响速度,当你在为提高了用户体验,做出了很绚丽的效果而欣喜的时候,是否想过优化一下JS的效率,大网站的JS都做了压缩处理。JS的速度分为两种,下载速度和执行速度。要想JS的下载...

    爬虫进阶课程(从小白到大神)

    14javascript反爬原理与调试;15爬虫模拟登录原理实践;16网络爬虫案例综合实践;17JavaScript进阶案例实践;18JavaScript逆向OB混淆学习;19基金爬虫综合实践;20文本混淆反爬虫绕过学习;21图形验证码反爬虫;22...

    基于JavaScript实现区域范围内的离线电子地图

    本设计借助Visual Studio 2010...本文通过对数字地图的构成方法与原理分析、数字地图的实现方法以及电子地图软件的调试与结果几个方面的叙述,描述了整个毕业设计工作的具体情况,并且对电子地图的发展提出了几点看法。

    客户端统一验证JavaScript函数库及示例源码

    Web应用如此广泛,其中客户端与服务端交互时所消耗的资源及响应时间,频繁的刷新页面使得人机交互体验极为不好,而对每个页面使用客户端处理技术无疑又加大项目开发周期,脚本调试及修改维护的工作量将占用大量的...

    DSBridge-IOS:现代的跨平台JavaScript桥,通过它,您可以在JavaScript和本机之间同步或异步调用彼此的功能

    English | 适用于IOS的DSBridge ...支持调试模式 支持API是否存在的测试 支持进度回叫:一个电话,多次返回 支持Java事件监听器以关闭页面 支持javascript的模式和无模式弹出框 支持适用于Android的

    资源前后端分离式分布式微服务架构项目搜索前端Nuxt.js讲义+源码+视频

    Nuxt.js工作原理 理解 理解Nuxt.js的工作原理 "理解服务端渲染和客户端渲染了解SEO理解Nuxt.js工作原理" Nuxt.js基本使用 应用 能够掌握Nuxt.js的基本使用方法 "理解目录结构理解目录别名能够测试页面布局能够...

    Ajax基础教程(扫描版)

    本书重点介绍ajax及相关的工具和技术,主要内容包括xmlhttprequest对象及其属性和方法、发送请求和处理响应、构建完备的ajax开发工具、使用jsunit测试javascript、分析javascript调试工具和技术,以及ajax开发模式和...

    React Native 开发指南_中文扫描完整版

    8.1 JavaScript 调试实践和解释 142 8.2 React Native 调试工具 147 8.3 JavaScript 之外的调试方法 152 8.4 测试代码 158 8.5 当你陷入困境 160 8.6 小结 160 第9章 学以致用 161 9.1 闪卡应用 161 9.2 ...

Global site tag (gtag.js) - Google Analytics