SlideShare a Scribd company logo
Wind.js
⽆无障碍调试与排错
   赵劼 - 2012.9
关于我
• 赵劼 / ⽼老赵 / Jeffrey Zhao / 赵姐夫
• ⽇日写代码三百⾏行,不辞⻓长作程序员
• 博客:http://blog.zhaojie.me/
• 微博:@⽼老赵
• F#, JavaScript, Scala, C#, Python, .NET, Mono...
• 痛恨Java语⾔言
Wind.js

• eval后的代码⽆无法调试?
• 混淆后的代码不易理解?
• 堆栈信息混乱?
eval代码调试
代码调试

• 很久很久以前:alert
• 过了⼀一段时间:console.log
• 其实从IE 5时代开始便可以调试代码
两个问题


• eval出来的代码可以调试吗?
• Node.js可以调试吗?
调试eval的代码

• 代码末尾://@	
  sourceUrl=<path>
• ⽀支持浏览器
 •   Chrome
 •   Safari
 •   Firefox (Firebug)
调试Node.js代码

• Eclipse
• Eclipse Debugger Plugin for V8
• 启动程序
 • node	
  -­‐-­‐debug[=port]	
  app.js
 • node	
  -­‐-­‐debug-­‐brk[=port]	
  app.js


                                        Using Eclipse as Node Applications Debugger
调试混淆代码
调试混淆代码
格式化以后
配合Source Map
Source Map

• 记录⺫⽬目标代码到源代码的映射
• JSON格式 + 编码后的映射数据
• Source Map V3 Spec
Source Map

  • 记录⺫⽬目标代码到源代码的映射
  • JSON格式 + 编码后的映射数据
  • Source Map V3 Spec
脚本末尾加上://@	
  sourceMappingURL=<path>,或
脚本请求头加上:X-­‐SourceMap:	
  <path>
深⼊入Source Map
Source Map V3
{
	
  	
  	
  	
  "version":	
  3,
	
  	
  	
  	
  "file":	
  "all.min.js",
	
  	
  	
  	
  "lineCount":	
  37,
	
  	
  	
  	
  "sources":	
  [	
  
	
  	
  	
  	
  	
  	
  	
  	
  "wind-­‐core.js",
	
  	
  	
  	
  	
  	
  	
  	
  "wind-­‐builderbase.js",
	
  	
  	
  	
  	
  	
  	
  	
  "wind-­‐async.js",
	
  	
  	
  	
  	
  	
  	
  	
  "sorting-­‐animations.aot.js"
	
  	
  	
  	
  ],
	
  	
  	
  	
  "names":	
  [	
  "Wind",	
  "_",	
  "isArray",	
  "obj",	
  ...	
  ],
	
  	
  	
  	
  "mappings":	
  "AAAC,SAAS,EAAG,CAGT,IAAIA,	
  ..."
}
解码 mappings 字段

• ⽤用分号区分“⾏行”,逗号区分“段”。
• Base64 Variable-Length Quantity 编码
• 节省空间,⽐比V2节省50%左右
确定代码⾏行号

AABBC;	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  第1⾏行
KAUYM,GAKoEF;	
  	
  //	
  第2⾏行
CCDD,	
  ...;	
  	
  	
  	
  	
  //	
  第3⾏行
...
...
Base64 VLQ解码
KAUYM,GAKoEF
Base64 VLQ解码
KAUYM,GAKoEF
        >>




[10,	
  0,	
  20,	
  24,	
  12],	
  [6,	
  0,	
  10,	
  40,	
  4,	
  5]
Base64 VLQ解码
KAUYM,GAKoEF
        >>




[10,	
  0,	
  20,	
  24,	
  12],	
  [6,	
  0,	
  10,	
  40,	
  4,	
  5]
        >>




[001010,	
  000000,	
  010100,	
  011000,	
  001100],	
  
[000110,	
  000000,	
  001010,	
  101000,	
  000100,	
  000101]
Base64 VLQ解码
KAUYM,GAKoEF
        >>




[10,	
  0,	
  20,	
  24,	
  12],	
  [6,	
  0,	
  10,	
  40,	
  4,	
  5]
        >>




                                            最低N-­‐1位为数据位
[001010,	
  000000,	
  010100,	
  011000,	
  001100],	
  
                                   01000,	
  	
  00100
[000110,	
  000000,	
  001010,	
  101000,	
  000100,	
  000101]
                                          最⾼高位表⽰示是否“连接后续数据”
Base64 VLQ解码
KAUYM,GAKoEF
        >>




[10,	
  0,	
  20,	
  24,	
  12],	
  [6,	
  0,	
  10,	
  40,	
  4,	
  5]
        >>




                                            最低N-­‐1位为数据位
[001010,	
  000000,	
  010100,	
  011000,	
  001100],	
  
                                   01000,	
  	
  00100
[000110,	
  000000,	
  001010,	
  101000,	
  000100,	
  000101]
                                          最⾼高位表⽰示是否“连接后续数据”
        >>




[1010,	
  0,	
  10100,	
  11000,	
  1100],	
  
[110,	
  0,	
  1010,	
  10001000,	
  101]
数据解码
[1010,	
  0,	
  10100,	
  11000,	
  1100],	
  
[110,	
  0,	
  1010,	
  10001000,	
  101]
数据解码
[1010,	
  0,	
  10100,	
  11000,	
  1100],	
  
[110,	
  0,	
  1010,	
  10001000,	
  101]
            最⾼高N-­‐1位为数据位              最低位为符号位
数据解码
[1010,	
  0,	
  10100,	
  11000,	
  1100],	
  
[110,	
  0,	
  1010,	
  10001000,	
  101]
               最⾼高N-­‐1位为数据位                    最低位为符号位
     >>




[5,	
  0,	
  10,	
  12,	
  6],	
  [3,	
  0,	
  5,	
  68,	
  -­‐2]
数据解码
[1010,	
  0,	
  10100,	
  11000,	
  1100],	
  
[110,	
  0,	
  1010,	
  10001000,	
  101]
               最⾼高N-­‐1位为数据位                    最低位为符号位
     >>




[5,	
  0,	
  10,	
  12,	
  6],	
  [3,	
  0,	
  5,	
  68,	
  -­‐2]
     >>




[5,	
  0,	
  10,	
  12,	
  6],	
  [8,	
  0,	
  15,	
  80,	
  4]
含义

//	
  已确定⾏行号
[
	
  5,	
  	
  	
  //	
  列号
	
  0,	
  	
  	
  //	
  源⽂文件,从sources查找
	
  10,	
  	
  //	
  源⽂文件内⾏行号
	
  12,	
  	
  //	
  源⽂文件内列号
	
  6	
  	
  	
  	
  //	
  源⽂文件内标⽰示符,从names查找
]
⽆无需⼿手动分析

• Google Closure Compiler可以⽣生成V2版
 Source Map格式,未编码的明⽂文数据

• 使⽤用Mozilla的SourceMap项⺫⽬目读取或⽣生成
 Source Map⽂文件
堆栈定位
传统JS错误堆栈
    128:   var baz = function () {
    129:       throw new Error("Hello World");
    130:   };
    131:
    132:   var bar = function () {
    133:       baz();
    134:   };
    135:
    136:   var foo = function () {
    137:       bar();
    138:   };
    139:
    140:   foo();
传统JS错误堆栈
                                            128:   var baz = function () {
                                            129:       throw new Error("Hello World");
                                            130:   };
                                            131:
                                            132:   var bar = function () {
                                            133:       baz();
                                            134:   };
                                            135:
                                            136:   var foo = function () {
                                            137:       bar();
                                            138:   };
                                            139:
Error: Hello World
                                            140:  foo();
    at baz (.../test.js:129:11)
    at bar (.../test.js:133:5)
    at foo (.../test.js:137:5)
    at Object.<anonymous> (.../test.js:140:1)
    at Module._compile (module.js:449:26)
    at Object.Module._extensions..js (module.js:467:10)
    ...
传统JS错误堆栈
                                            128:   var baz = function () {
                                            129:       throw new Error("Hello World");
                                            130:   };
                                            131:
                                            132:   var bar = function () {
                                            133:       baz();
                                            134:   };
                                            135:
                                            136:   var foo = function () {
                                            137:       bar();
                                            138:   };
                                            139:
Error: Hello World
                                            140:  foo();
    at baz (.../test.js:129:11)
    at bar (.../test.js:133:5)
    at foo (.../test.js:137:5)
    at Object.<anonymous> (.../test.js:140:1)
    at Module._compile (module.js:449:26)
    at Object.Module._extensions..js (module.js:467:10)
    ...
Wind.js错误堆栈
 128:   var test = eval(..., function () {
 129:        var a = null;
 130:        a.b();
 131:   }));
 132:
 133:   test().on("failure", function () {
 134:       console.log(this.error.stack);
 135:   }).start();
Wind.js错误堆栈
               128:   var test = eval(..., function () {
               129:        var a = null;
               130:        a.b();
               131:   }));
               132:
               133:   test().on("failure", function () {
               134:       console.log(this.error.stack);
               135:   }).start();



TypeError: Cannot call method 'b' of null
    at eval (wind/anonymous_0.js:6:37)
    at Object.BuilderBase.Delay.next (.../wind-async.js:143:46)
    at Object.AsyncBuilder.Start [as _delegate] (.../wind-async:652:22)
    at Object.Task.start (.../wind-async.js:196:22)
    at Object.<anonymous> (.../test.js:135:4)
    ...
Wind.js错误堆栈
               128:   var test = eval(..., function () {
               129:        var a = null;
               130:        a.b();
               131:   }));
               132:
               133:   test().on("failure", function () {
               134:       console.log(this.error.stack);
               135:   }).start();



TypeError: Cannot call method 'b' of null
    at eval (wind/anonymous_0.js:6:37) ???
             wind/anonymous_0.js:6:37
    at Object.BuilderBase.Delay.next (.../wind-async.js:143:46)
    at Object.AsyncBuilder.Start [as _delegate] (.../wind-async:652:22)
    at Object.Task.start (.../wind-async.js:196:22)
    at Object.<anonymous> (.../test.js:135:4)
    ...
指向⺫⽬目标堆栈
01:   /* function () { */    (function () {
02:                              var _builder_$0 = Wind.builders["async"];
03:                              return _builder_$0.Start(this,
04:                                  _builder_$0.Delay(function () {
05:   /*      var a = null; */           var a = null;
06:   /*      a.b(); */                  a.b();
07:                                      return _builder_$0.Normal();
08:                                  })
09:                              );
10:   /* } */                })
11:   //@ sourceURL=wind/anonymous_2.js




TypeError: Cannot call method 'b' of null
    at eval (wind/anonymous_0.js:6:37)
    at Object.BuilderBase.Delay.next (.../wind-async.js:143:46)
    at Object.AsyncBuilder.Start [as _delegate] (.../wind-async:652:22)
    ...
指向⺫⽬目标堆栈
01:   /* function () { */    (function () {
02:                              var _builder_$0 = Wind.builders["async"];
03:                              return _builder_$0.Start(this,
04:                                  _builder_$0.Delay(function () {
05:   /*      var a = null; */           var a = null;
06:   /*      a.b(); */                  a.b();
07:                                      return _builder_$0.Normal();
08:                                  })
09:                              );
10:   /* } */                })
11:   //@ sourceURL=wind/anonymous_2.js




TypeError: Cannot call method 'b' of null
             wind/anonymous_0.js:6:37
    at eval (wind/anonymous_0.js:6:37)
    at Object.BuilderBase.Delay.next (.../wind-async.js:143:46)
    at Object.AsyncBuilder.Start [as _delegate] (.../wind-async:652:22)
    ...
有办法修复吗?
有办法修复吗?


当然有,编译器掌握了所有
 输⼊入和输出的对应关系。
总结

• 调试eval出的代码不是问题
• 混淆后的代码可以利⽤用Source Map直接
 定位到原始代码

• Wind.js编译器充分了解⺫⽬目标代码与原始
 代码的位置关系,可⽤用于堆栈定位
Q &A
谢谢

More Related Content

What's hot (19)

PDF
Node way
Ethan Zhang
 
PDF
lambda/closure – JavaScript、Python、Scala 到 Java SE 7
Justin Lin
 
PDF
JavaScript 教程
Bobby Zhou
 
PDF
Python learn guide
robin yang
 
PDF
Python 于 webgame 的应用
勇浩 赖
 
PDF
Standford 2015 iOS讀書會 week2: 1. Applying MVC 2. More Swift and Foundation Fra...
彼得潘 Pan
 
PPTX
异步编程与浏览器执行模型
keelii
 
PDF
在開始工作以前,我以為我會寫扣。
Chih-Hsuan Kuo
 
PDF
Java8 lambda
koji lin
 
PDF
nodeMCU IOT教學02 - Lua語言
吳錫修 (ShyiShiou Wu)
 
PDF
Swift 程序语言介绍
明 李
 
PDF
Ooredis
iammutex
 
PDF
JavaScript 快速複習 2017Q1
Sheng-Han Su
 
PDF
Sigreturn Oriented Programming
Angel Boy
 
PPTX
從 Singleton 談 constructor
Luba Tang
 
PPT
JAVA内存泄漏及诊断
ivannotes
 
PDF
Arduino應用系統設計 - Arduino程式快速入門
吳錫修 (ShyiShiou Wu)
 
PDF
Arduino L2
mmiwwcom
 
PDF
LazyRecord: The Fast ORM for PHP
Lin Yo-An
 
Node way
Ethan Zhang
 
lambda/closure – JavaScript、Python、Scala 到 Java SE 7
Justin Lin
 
JavaScript 教程
Bobby Zhou
 
Python learn guide
robin yang
 
Python 于 webgame 的应用
勇浩 赖
 
Standford 2015 iOS讀書會 week2: 1. Applying MVC 2. More Swift and Foundation Fra...
彼得潘 Pan
 
异步编程与浏览器执行模型
keelii
 
在開始工作以前,我以為我會寫扣。
Chih-Hsuan Kuo
 
Java8 lambda
koji lin
 
nodeMCU IOT教學02 - Lua語言
吳錫修 (ShyiShiou Wu)
 
Swift 程序语言介绍
明 李
 
Ooredis
iammutex
 
JavaScript 快速複習 2017Q1
Sheng-Han Su
 
Sigreturn Oriented Programming
Angel Boy
 
從 Singleton 談 constructor
Luba Tang
 
JAVA内存泄漏及诊断
ivannotes
 
Arduino應用系統設計 - Arduino程式快速入門
吳錫修 (ShyiShiou Wu)
 
Arduino L2
mmiwwcom
 
LazyRecord: The Fast ORM for PHP
Lin Yo-An
 

Similar to Wind.js无障碍调试与排错 (20)

PDF
Node.js开发体验
QLeelulu
 
PPTX
Ian 20151002 es2015
LearningTech
 
PDF
Erlang Practice
litaocheng
 
PDF
學好 node.js 不可不知的事
Ben Lue
 
PDF
Node getting-started
lylijincheng
 
PDF
Arduino程式快速入門
吳錫修 (ShyiShiou Wu)
 
PPT
Html5移动web应用开发(PhoneGap)
amd6400
 
PPT
Html5移动web应用开发(PhoneGap)
amd6400
 
ODP
Ruby程式語言入門導覽
Mu-Fan Teng
 
PDF
Talking about exploit writing
sbha0909
 
PDF
Arduino程式快速入門
吳錫修 (ShyiShiou Wu)
 
PDF
twMVC#44 讓我們用 k6 來進行壓測吧
twMVC
 
PPTX
181201_CoAP_coding365
Peter Yi
 
PDF
JCConf2015: groovy to gradle
Ching Yi Chan
 
PPT
Mongodb
bj
 
PDF
D2_node在淘宝的应用实践_pdf版
Jackson Tian
 
PPT
Node.js在淘宝的应用实践
taobao.com
 
PPT
NodeJS快速服务端开发 朝沐金风 Shanghai
Jackson Tian
 
PPT
HTML5移动应用开发分享会(PhoneGap)
amd6400
 
PPT
HTML5移动WEB应用程序开发(PhoneGap)
amd6400
 
Node.js开发体验
QLeelulu
 
Ian 20151002 es2015
LearningTech
 
Erlang Practice
litaocheng
 
學好 node.js 不可不知的事
Ben Lue
 
Node getting-started
lylijincheng
 
Arduino程式快速入門
吳錫修 (ShyiShiou Wu)
 
Html5移动web应用开发(PhoneGap)
amd6400
 
Html5移动web应用开发(PhoneGap)
amd6400
 
Ruby程式語言入門導覽
Mu-Fan Teng
 
Talking about exploit writing
sbha0909
 
Arduino程式快速入門
吳錫修 (ShyiShiou Wu)
 
twMVC#44 讓我們用 k6 來進行壓測吧
twMVC
 
181201_CoAP_coding365
Peter Yi
 
JCConf2015: groovy to gradle
Ching Yi Chan
 
Mongodb
bj
 
D2_node在淘宝的应用实践_pdf版
Jackson Tian
 
Node.js在淘宝的应用实践
taobao.com
 
NodeJS快速服务端开发 朝沐金风 Shanghai
Jackson Tian
 
HTML5移动应用开发分享会(PhoneGap)
amd6400
 
HTML5移动WEB应用程序开发(PhoneGap)
amd6400
 
Ad

More from jeffz (20)

PDF
深入浅出Jscex
jeffz
 
PDF
Mono for .NET Developers
jeffz
 
PDF
Javascript Uncommon Programming
jeffz
 
PDF
Jscex: Write Sexy JavaScript (中文)
jeffz
 
PDF
Jscex: Write Sexy JavaScript
jeffz
 
PDF
单点登录解决方案的架构与实现
jeffz
 
PDF
Documentation Insight技术架构与开发历程
jeffz
 
PDF
Windows Phone应用开发心得
jeffz
 
PDF
分布式版本管理
jeffz
 
PDF
使用.NET构建轻量级分布式框架
jeffz
 
PDF
针对iPad平台的高性能网站架构
jeffz
 
PDF
企业开发领域的语言特性
jeffz
 
PDF
The Evolution of Async-Programming on .NET Platform (TUP, Full)
jeffz
 
PDF
The Evolution of Async-Programming on .NET Platform (.Net China, C#)
jeffz
 
PDF
The Evolution of Async-Programming (SD 2.0, JavaScript)
jeffz
 
PDF
大话程序员可用的算法
jeffz
 
PDF
面向对象与生活
jeffz
 
PDF
Windows内核技术介绍
jeffz
 
PDF
响应式编程及框架
jeffz
 
PDF
F#语言对异步程序设计的支持
jeffz
 
深入浅出Jscex
jeffz
 
Mono for .NET Developers
jeffz
 
Javascript Uncommon Programming
jeffz
 
Jscex: Write Sexy JavaScript (中文)
jeffz
 
Jscex: Write Sexy JavaScript
jeffz
 
单点登录解决方案的架构与实现
jeffz
 
Documentation Insight技术架构与开发历程
jeffz
 
Windows Phone应用开发心得
jeffz
 
分布式版本管理
jeffz
 
使用.NET构建轻量级分布式框架
jeffz
 
针对iPad平台的高性能网站架构
jeffz
 
企业开发领域的语言特性
jeffz
 
The Evolution of Async-Programming on .NET Platform (TUP, Full)
jeffz
 
The Evolution of Async-Programming on .NET Platform (.Net China, C#)
jeffz
 
The Evolution of Async-Programming (SD 2.0, JavaScript)
jeffz
 
大话程序员可用的算法
jeffz
 
面向对象与生活
jeffz
 
Windows内核技术介绍
jeffz
 
响应式编程及框架
jeffz
 
F#语言对异步程序设计的支持
jeffz
 
Ad

Wind.js无障碍调试与排错

  • 2. 关于我 • 赵劼 / ⽼老赵 / Jeffrey Zhao / 赵姐夫 • ⽇日写代码三百⾏行,不辞⻓长作程序员 • 博客:http://blog.zhaojie.me/ • 微博:@⽼老赵 • F#, JavaScript, Scala, C#, Python, .NET, Mono... • 痛恨Java语⾔言
  • 7. 调试eval的代码 • 代码末尾://@  sourceUrl=<path> • ⽀支持浏览器 • Chrome • Safari • Firefox (Firebug)
  • 8. 调试Node.js代码 • Eclipse • Eclipse Debugger Plugin for V8 • 启动程序 • node  -­‐-­‐debug[=port]  app.js • node  -­‐-­‐debug-­‐brk[=port]  app.js Using Eclipse as Node Applications Debugger
  • 13. Source Map • 记录⺫⽬目标代码到源代码的映射 • JSON格式 + 编码后的映射数据 • Source Map V3 Spec
  • 14. Source Map • 记录⺫⽬目标代码到源代码的映射 • JSON格式 + 编码后的映射数据 • Source Map V3 Spec 脚本末尾加上://@  sourceMappingURL=<path>,或 脚本请求头加上:X-­‐SourceMap:  <path>
  • 16. Source Map V3 {        "version":  3,        "file":  "all.min.js",        "lineCount":  37,        "sources":  [                  "wind-­‐core.js",                "wind-­‐builderbase.js",                "wind-­‐async.js",                "sorting-­‐animations.aot.js"        ],        "names":  [  "Wind",  "_",  "isArray",  "obj",  ...  ],        "mappings":  "AAAC,SAAS,EAAG,CAGT,IAAIA,  ..." }
  • 17. 解码 mappings 字段 • ⽤用分号区分“⾏行”,逗号区分“段”。 • Base64 Variable-Length Quantity 编码 • 节省空间,⽐比V2节省50%左右
  • 18. 确定代码⾏行号 AABBC;                  //  第1⾏行 KAUYM,GAKoEF;    //  第2⾏行 CCDD,  ...;          //  第3⾏行 ... ...
  • 20. Base64 VLQ解码 KAUYM,GAKoEF >> [10,  0,  20,  24,  12],  [6,  0,  10,  40,  4,  5]
  • 21. Base64 VLQ解码 KAUYM,GAKoEF >> [10,  0,  20,  24,  12],  [6,  0,  10,  40,  4,  5] >> [001010,  000000,  010100,  011000,  001100],   [000110,  000000,  001010,  101000,  000100,  000101]
  • 22. Base64 VLQ解码 KAUYM,GAKoEF >> [10,  0,  20,  24,  12],  [6,  0,  10,  40,  4,  5] >> 最低N-­‐1位为数据位 [001010,  000000,  010100,  011000,  001100],   01000,    00100 [000110,  000000,  001010,  101000,  000100,  000101] 最⾼高位表⽰示是否“连接后续数据”
  • 23. Base64 VLQ解码 KAUYM,GAKoEF >> [10,  0,  20,  24,  12],  [6,  0,  10,  40,  4,  5] >> 最低N-­‐1位为数据位 [001010,  000000,  010100,  011000,  001100],   01000,    00100 [000110,  000000,  001010,  101000,  000100,  000101] 最⾼高位表⽰示是否“连接后续数据” >> [1010,  0,  10100,  11000,  1100],   [110,  0,  1010,  10001000,  101]
  • 24. 数据解码 [1010,  0,  10100,  11000,  1100],   [110,  0,  1010,  10001000,  101]
  • 25. 数据解码 [1010,  0,  10100,  11000,  1100],   [110,  0,  1010,  10001000,  101] 最⾼高N-­‐1位为数据位 最低位为符号位
  • 26. 数据解码 [1010,  0,  10100,  11000,  1100],   [110,  0,  1010,  10001000,  101] 最⾼高N-­‐1位为数据位 最低位为符号位 >> [5,  0,  10,  12,  6],  [3,  0,  5,  68,  -­‐2]
  • 27. 数据解码 [1010,  0,  10100,  11000,  1100],   [110,  0,  1010,  10001000,  101] 最⾼高N-­‐1位为数据位 最低位为符号位 >> [5,  0,  10,  12,  6],  [3,  0,  5,  68,  -­‐2] >> [5,  0,  10,  12,  6],  [8,  0,  15,  80,  4]
  • 28. 含义 //  已确定⾏行号 [  5,      //  列号  0,      //  源⽂文件,从sources查找  10,    //  源⽂文件内⾏行号  12,    //  源⽂文件内列号  6        //  源⽂文件内标⽰示符,从names查找 ]
  • 29. ⽆无需⼿手动分析 • Google Closure Compiler可以⽣生成V2版 Source Map格式,未编码的明⽂文数据 • 使⽤用Mozilla的SourceMap项⺫⽬目读取或⽣生成 Source Map⽂文件
  • 31. 传统JS错误堆栈 128: var baz = function () { 129: throw new Error("Hello World"); 130: }; 131: 132: var bar = function () { 133: baz(); 134: }; 135: 136: var foo = function () { 137: bar(); 138: }; 139: 140: foo();
  • 32. 传统JS错误堆栈 128: var baz = function () { 129: throw new Error("Hello World"); 130: }; 131: 132: var bar = function () { 133: baz(); 134: }; 135: 136: var foo = function () { 137: bar(); 138: }; 139: Error: Hello World 140: foo(); at baz (.../test.js:129:11) at bar (.../test.js:133:5) at foo (.../test.js:137:5) at Object.<anonymous> (.../test.js:140:1) at Module._compile (module.js:449:26) at Object.Module._extensions..js (module.js:467:10) ...
  • 33. 传统JS错误堆栈 128: var baz = function () { 129: throw new Error("Hello World"); 130: }; 131: 132: var bar = function () { 133: baz(); 134: }; 135: 136: var foo = function () { 137: bar(); 138: }; 139: Error: Hello World 140: foo(); at baz (.../test.js:129:11) at bar (.../test.js:133:5) at foo (.../test.js:137:5) at Object.<anonymous> (.../test.js:140:1) at Module._compile (module.js:449:26) at Object.Module._extensions..js (module.js:467:10) ...
  • 34. Wind.js错误堆栈 128: var test = eval(..., function () { 129: var a = null; 130: a.b(); 131: })); 132: 133: test().on("failure", function () { 134: console.log(this.error.stack); 135: }).start();
  • 35. Wind.js错误堆栈 128: var test = eval(..., function () { 129: var a = null; 130: a.b(); 131: })); 132: 133: test().on("failure", function () { 134: console.log(this.error.stack); 135: }).start(); TypeError: Cannot call method 'b' of null at eval (wind/anonymous_0.js:6:37) at Object.BuilderBase.Delay.next (.../wind-async.js:143:46) at Object.AsyncBuilder.Start [as _delegate] (.../wind-async:652:22) at Object.Task.start (.../wind-async.js:196:22) at Object.<anonymous> (.../test.js:135:4) ...
  • 36. Wind.js错误堆栈 128: var test = eval(..., function () { 129: var a = null; 130: a.b(); 131: })); 132: 133: test().on("failure", function () { 134: console.log(this.error.stack); 135: }).start(); TypeError: Cannot call method 'b' of null at eval (wind/anonymous_0.js:6:37) ??? wind/anonymous_0.js:6:37 at Object.BuilderBase.Delay.next (.../wind-async.js:143:46) at Object.AsyncBuilder.Start [as _delegate] (.../wind-async:652:22) at Object.Task.start (.../wind-async.js:196:22) at Object.<anonymous> (.../test.js:135:4) ...
  • 37. 指向⺫⽬目标堆栈 01: /* function () { */ (function () { 02: var _builder_$0 = Wind.builders["async"]; 03: return _builder_$0.Start(this, 04: _builder_$0.Delay(function () { 05: /* var a = null; */ var a = null; 06: /* a.b(); */ a.b(); 07: return _builder_$0.Normal(); 08: }) 09: ); 10: /* } */ }) 11: //@ sourceURL=wind/anonymous_2.js TypeError: Cannot call method 'b' of null at eval (wind/anonymous_0.js:6:37) at Object.BuilderBase.Delay.next (.../wind-async.js:143:46) at Object.AsyncBuilder.Start [as _delegate] (.../wind-async:652:22) ...
  • 38. 指向⺫⽬目标堆栈 01: /* function () { */ (function () { 02: var _builder_$0 = Wind.builders["async"]; 03: return _builder_$0.Start(this, 04: _builder_$0.Delay(function () { 05: /* var a = null; */ var a = null; 06: /* a.b(); */ a.b(); 07: return _builder_$0.Normal(); 08: }) 09: ); 10: /* } */ }) 11: //@ sourceURL=wind/anonymous_2.js TypeError: Cannot call method 'b' of null wind/anonymous_0.js:6:37 at eval (wind/anonymous_0.js:6:37) at Object.BuilderBase.Delay.next (.../wind-async.js:143:46) at Object.AsyncBuilder.Start [as _delegate] (.../wind-async:652:22) ...
  • 41. 总结 • 调试eval出的代码不是问题 • 混淆后的代码可以利⽤用Source Map直接 定位到原始代码 • Wind.js编译器充分了解⺫⽬目标代码与原始 代码的位置关系,可⽤用于堆栈定位
  • 42. Q &A