前端错误监控—基础知识点

前端异常监控的重要性

软件异常监控常常直接关联到软件本身的质量,完备的异常监控体系常常能够快速定位到软件运行中发生的问题,并能帮助我们快速定位问题的源头,提升软件质量。

在服务器开发中,我们常常使用日志来记录请求的错误和服务器异常问题,但是在前端开发中,前端工程师按照需求完成页面开发,通过产品体验确认和测试,页面就可以上线了。但不幸的是,产品很快就收到了用户的投诉。用户反映页面点击按钮没反应而且能复现,我们试了一下却一切正常,于是追问用户所用的环境,最后结论是用户使用了一个非常小众的浏览器打开页面,因为该浏览器不支持某个特性,因此页面报错,整个页面停止响应。在这种情况下,用户反馈的投诉花掉了我们很多时间去定位问题,然而这并不是最可怕的,更让我们担忧的是更多的用户遇到这种场景后便会直接抛弃这个有问题的“垃圾产品”。这个问题唯一的解决办法就是在尽量少的用户遇到这样的场景时就把问题即时修复掉,保证尽量多的用户可以正常使用。

首先我们需要在少数用户使用产品出错时知道有用户出错,而且尽量定位到是什么错误。由于用户的运行环境是在浏览器端的,因此可以在前端页面脚本执行出错时将错误信息上传到服务器,然后打开服务器收集的错误信息进行分析来改进产品的质量,下面我们主要讨论下错误的捕获方案。

 

 

前端错误的分类

  • 即时运行错误(代码错误)
  • 资源加载错误,比如图片加载失败、JS加载失败、CSS加载失败等;

 

 

即时运行错误的捕获方式

window.onerror 算是一种特别暴力的容错手段,try..catch 也是如此,他们底层的实现就是利用 C/C++ 中的 goto 语句实现,一旦发现错误,不管目前的堆栈有多深,不管代码运行到了何处,直接跑到顶层或者 try..catch 捕获的那一层,这种一脚踢开错误的处理方式并不是很好。

try..catch 捕获,判断一个代码段中存在的错误

一般来说,使用try...catch可以捕捉前端JavaScript的运行时错误,同时拿到出错的信息,例如错误信息描述、堆栈、行号、列号、具体的出错文件信息等。我们也可以在这个阶段将用户浏览器信息等静态内容一起记录下来,快速地定位问题发生的原因。需要注意的是,try...catch无法捕捉到语法错误,只能在单一的作用域内有效捕获错误信息,如果是异步函数里面的内容,就需要把function函数块内容全部加入到try...catch中执行。

  • 无法捕捉到语法错误,只能捕捉运行时错误;
  • 可以拿到出错的信息,堆栈,出错的文件、行号、列号;
  • 需要借助工具把所有的function块以及文件块加入try,catch,可以在这个阶段打入更多的静态信息。
try{
    // 单一作用域try...catch可以捕获错误信息并进行处理
    console.log(obj);
}catch(e){
    console.log(e); //处理异常,ReferenceError: obj is not defined
}
try{
    // 不同作用域不能捕获到错误信息
    setTimeout(function() {
        console.log(obj); // 直接报错,不经过catch处理
    }, 200);
}catch(e){
    console.log(e);
}
// 同一个作用域下能捕获到错误信息
setTimeout(function() {
    try{
        // 当前作用域try...catch可以捕获错误信息并进行处理
        console.log(obj); 
    }catch(e){
        console.log(e); //处理异常,ReferenceError: obj is not defined
    }
}, 200);

但是在上面的这个例子中,try...catch无法获取异步函数setTimeout或其他作用域中的错误信息,这样就只能在每个函数里面添加try...catch了。

虽然使用window.onerror可以获取页面的出错信息、出错文件和行号,但是window. onerror有跨域限制,如果需要获取错误发生的具体描述、堆栈内容、行号、列号和具体的出错文件等详细日志,就必须使用try…catch,但是try…catch又不能在多个作用域中统一处理错误。

幸运的是,我们可以对前端脚本中常用的异步方法入口函数或模块引用的入口方法统一使用try…catch进行一层封装,这样就可以使用try…catch捕获每个引用模块作用域下的主要错误信息了。例如我们就可以对setTimeout函数用如下方式进行封装并捕获错误信息。另外,使用try-catch会带来一定的性能损耗,根据循环测试,平均大概会损失6%~10%的性能,但是为了提升应用的质量和稳定性,这些是可以接受的。

function wrapFunction(fn) {
    return function() {
        try {
            return fn.apply(this, arguments);
        } catch (e) {
            console.log(e);
            _errorProcess(e);
            return;
        }
    };
}

// 之后fn函数里面的代码运行出错时则是可以被捕获到的了
fn = wrapFunction(fn);

// 或者异步函数里面的回调函数中的错误也可以被捕获到
var _setTimeout = setTimeout;
setTimeout = function(fn, time){
    return _setTimeout(wrapFunction(fn), time);
}

// 模块定义函数也可以做重写定义
var _require = require;
require = function(id, deps, factory) {
    if (typeof(factory) !== 'function' || !factory) {
        return _require(id, deps);
    } else {
        return _require(id, deps, wrapFunction(factory));
    }
};

这是我们可以对常用的模块入口函数进行重定义,包括setTimeout、setInterval、define、require等,这样模块中的主要作用域中的异常都可以通过try-catch来捕获了。在之前的处理方法中,这种方法是非常有效的,直接可以拿到大多数错误栈中的异常和堆栈信息。

  我们可以对不同作用域的setTimeout参数函数的引入方式使用try…catch进行封装,让try…catch能捕获到setTimeout脚本中的错误并使用setTimeoutTry函数来代替。对于异步引入模块定义函数require或define也可以进行类似的封装,这样就可以获取到不同模块里面作用域的错误信息了。因此,这里捕获错误的方式可以根据具体的条件和场景灵活选择,在没有特别限制的情况下,使用window.onerror是比较高效、便捷的。

try {
  init();
  // code...
} catch(e){
  Reporter.send(format(e));
}

以 init 为程序的入口,代码中所有同步执行出现的错误都会被捕获,这种方式也可以很好的避免程序刚跑起来就挂。

window.onerror,捕获全局错误

当JavaScript运行时错误(包括语法错误)发生时,window会触发一个ErrorEvent接口的error事件,并执行window.onerror()

window.onerror的方法可以在任何执行上下文中执行,如果给window对象增加一个错误处理函数,便既能处理捕获错误又能保持代码的优雅性了。window.onerror一般用于捕捉脚本语法错误和运行时错误,可以获得出错的文件信息,如出错信息、出错文件、行号等,当前页面执行的所有JavaScript脚本出错都会被捕捉到。

onerror最好写在所有 JS 脚本的前面,否则有可能捕获不到错误

  • 可以捕捉语法错误,也可以捕捉运行时错误;
  • 可以拿到出错的信息,堆栈,出错的文件、行号、列号;
  • 只要在当前页面执行的js脚本出错都会捕捉到,例如:浏览器插件的javascript、或者flash抛出的异常等。
  • 跨域的资源需要特殊头部支持。
window.onerror = function() {
    var errInfo = format(arguments);
    Reporter.send(errInfo);
    return true;
};

在上面的函数中返回 return true,错误便不会暴露到控制台中。下面是它的参数信息:

/**
 * @param {String}  errorMessage   错误信息
 * @param {String}  scriptURI      出错的文件
 * @param {Long}    lineNumber     出错代码的行号
 * @param {Long}    columnNumber   出错代码的列号
 * @param {Object}  errorObj       错误的详细信息,Anything
 */
window.onerror = function(errorMessage, scriptURI, lineNumber,columnNumber,errorObj) {
  console.log(errorMessage)//字符串错误信息
  console.log(scriptURI)//发生错误的脚本
  console.log(lineNumber)//发生错误的行号
  console.log(columnNumber)//发生错误的列号
  console.log(errorObj)//Erroe对象

  return true//将代码错误定格在捕获阶段
}

然而,使用onerror要注意,在不同浏览器中实现函数处理返回的异常对象是不相同的,而且如果报错的JavaScript和HTML不在同一个域名下,错误时window.onerror中的errorMsg全部为script error而不是具体的错误描述信息,此时需要添加JavaScript脚本的跨域设置。

需要给跨域资源的服务器的response header设置允许跨域:Access-Control-Allow-Origin:*

<script src="//www.domain.com/main.js" crossorigin></script>

如果服务器因为一些原因不能设置跨域或设置起来比较麻烦,那就只能在每个引用的文件里添加try...catch进行处理。

addEventListener全局监听

promise...catch主动捕获

在promise中使用catch可以非常方便的捕获到异步error,catch 其实是 then(undefined, () => {}) 的语法糖,如下:

let p = Promise.reject("error");

// catch
p.catch(err => {
  console.log("catch " + err); // catch error
});

// then
p.then(undefined, err => {
  console.log("catch " + err); // catch error
});

捕获错误

Promise对象内部其实自带了try catch,当同步代码发生运行时错误时,会自动将错误对象作为值reject,这样就会触发catch注册的回调,如下:

let p = new Promise((resolve, reject) => {
  throw "error";
});

p.catch(err => {
  console.log("catch " + err); // catch error
});

但需要注意的是:异步代码的运行时错误无法被自动 reject 进而被 catch 捕获,而是直接报错:

let p = new Promise((resolve, reject) => {
  setTimeout(() => {
    throw "error";
  }, 0);
});

p.catch(err => {
  console.log("catch " + err); // 不会被执行
});

关于异步错误是否会被 catch 捕获其实还有点坑,事实证明之所以 setTimeout 中产生的错误不会被 catch 捕获到,原因是 js 的事件队列中,Promise 的 catch 会在 setTimeout 回调之前执行;但是若异步操作抛出错误的回调是在 Promise 的 catch 之前执行的,其实还是可以被 catch 所捕获到的,比如 Promise 的 then 方法所抛出的错误:
 

let p = Promise.resolve();

let p1 = new Promise(function (resolve, reject) {
  p.then(()=>{
    throw 123;
  }).catch(e => {
    reject(e);
  });
});

p1.catch(err => {
  console.log(err); // 123,错误成功被捕获
});

一旦 Promise 对象已经 resolve,其后的运行时错误将被忽略

let p = new Promise((resolve, reject) => {
  resolve();
  throw "error";
});

p.catch(err => {
  console.log("catch " + err); // 不会被执行
});

return的值

与 then 方法相同,执行后会 return 一个新的 Promise 对象,以实现链式调用,你可以显式的 return 一个 Promise 对象,若不显式的 return 则会 return 一个以 undefined 值 resolve 的 Promise 对象;
 

let p = Promise.reject("error");
 
// catch
p.catch(err => {
  console.log("catch " + err); // catch error
  // 这里会默认return Promise.resolve(undefined);
}).then(res => {
  console.log(res); // undefined
});
 
let p2 = Promise.resolve("success");
 
// then
p2.catch(err => { // 由于p2正常resolve,所以此处不会执行
  console.log("catch " + err);
}).then(res => { // 由于前一个catch未执行,所以此处调用then的还是p2
  console.log(res); // success
  // 这里会默认return Promise.resolve(undefined);
}).then(res => {
  console.log(res); // undefined
});

重写XMLHttpRequest对象方法

该方法主要针对AJAX请求异常,附上参考代码:

function XMLHttpRequest() {
  var _self = this;

  // 重写 open
  XMLHttpRequest.prototype.open = function(){
    // 先在此处取得请求的url、method
    _self.reqUrl = arguments[1];
    _self.reqMethod = arguments[0];
    // 在调用原生 open 实现重写
    _self.xhrOpen.apply(this, arguments);
  }

  // 重写 send
  XMLHttpRequest.prototype.send = function () {
    // 记录xhr
    var xhrmsg = {
      'url': _self.reqUrl,
      'type': _self.reqMethod,
      // 此处可以取得 ajax 的请求参数
      'data': arguments[0] || {}
    }

    this.addEventListener('readystatechange', function () {
      if (this.readyState === 4) {
        // 此处可以取得一些响应信息
        // 响应信息
        xhrmsg['res'] = this.response;
        xhrmsg['status'] = this.status;
        this.status >= 200 && this.status < 400 ?
          xhrmsg['level'] = 'success' : xhrmsg['level'] = 'error';
        xhrArray.push(xhrmsg);
      }
    });

    _self.xhrSend.apply(this, arguments);
  }
}

 

 

资源加载错误的捕获方式

object.onerror

addEventListener全局监听

当一项资源(如图片或脚本)加载失败,加载资源的元素会触发一个Event接口的error事件,并执行该元素上的onerror()处理函数。这些error事件不会向上冒泡到window,不过(至少在Firefox中)能被单一的window.addEventListener捕获。

使用时需要注意的点:

  • 不同浏览器下返回的error对象可能不同,需要注意兼容处理。
  • 需要注意避免addEventListener重复监听。

写一个简单的例子,加载一个不存在的资源,然后使用Error事件捕获的方式来捕获错误

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>错误监控</title>
  <script>
    window.addEventListener('error', function (e) {
      console.log(e)
    }, true) // 最后一个参数一定是要true才能捕获到错误,如果为false就是冒泡,捕获不到错误
  </script>
</head>
<body>
  <script src="//baidu.com/test.js" charset="utf-8"></script>
</body>
</html>

window.addEventListener在运行时错误和资源加载错误时返回的错误对象不同,资源加载错误:

performance.getEntries(),可以获取到所有资源加载的时长,从而间接的捕获到资源的加载有没有错误

下面以一个网站为例子,直接再控制台输入这个方法

以上的资源就是成功加载的,可以通过下面方式打印出所有的img集合,这个img集合减去上面成功加载的img集合,剩下的就是没有成功加载的img,这样就间接的获取到了没有成功加载的img资源

 

 

跨域的js运行错误可以捕获吗,错误提示是什么,应该怎么处理

答案是可以捕获到的,错误的提示如下:

处理方式如下:

  • 第一步:在script标签增加crossorigin属性(客户端)
  • 第二步:设置js资源响应头Access-Control-Allow-Origin:*(这个是在服务端设置的,可以设置为*表示所有域名下都可以,也可以设置为具体某个域名或者多个域名)

 

 

 

错误上报

需上报的错误类型有几种

  • 静态资源加载失败
  • AJAX请求失败
  • JavaScript异常
    • 运行时报错
      • 同步错误
      • 异步错误
    • 语法错误
  • promise异常

上报错误的的方式

上报错误的目的是因为本地定位不到错误,所以使用ajax或者image把错误传到后端,在后端看日志

采用ajax通信的方式上报(不推荐的做法)

利用Image对象上报(重要,推荐的方式)

只需要动态创建一个Image对象即可

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>错误监控</title>
  <script>
    (new Image()).src='http://baidu.com/tesjk?r=tesjk'; // 上报的地址,后面可以跟上参数
  </script>
</head>
<body>

</body>
</html>

或者写一个通用的方法来实现上报

function logError(sev, msg){
    var img = new Image();
    img.src = "log.php?sev=" + encodeURIComponent(sev) + "&msg=" + encodeURIComponent(msg)";
}

通过network可以看到请求已经发出了

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ANTLR是一款强大的语法分析器生成工具,可用于读取、处理、执行和翻译结构化的文本或二进制文件。它被广泛应用于学术领域和工业生产实践,是众多语言、工具和框架的基石。Twitter搜索使用ANTLR进行语法分析,每天处理超过20亿次查询;Hadoop生态系统中的Hive、Pig、数据仓库和分析系统所使用的语言都用到了ANTLR;Lex Machina将ANTLR用于分析法律文本;Oracle公司在SQL开发者IDE和迁移工具中使用了ANTLR;NetBeans公司的IDE使用ANTLR来解析C++;Hibernate对象-关系映射框架(ORM)使用ANTLR来处理HQL语言。   除了这些鼎鼎大名的项目之外,还可以利用ANTLR构建各种各样的实用工具,如配置文件读取器、遗留代码转换器、维基文本渲染器,以及JSON解析器。我编写了一些工具,用于创建数据库的对象-关系映射、描述三维可视化以及在Java源代码中插入性能监控代码。我甚至为一次演讲编写了一个简单的DNA模式匹配程序。   一门语言的正式描述称为语法(grammar),ANTLR能够为该语言生成一个语法分析器,并自动建立语法分析树——一种描述语法与输入文本匹配关系的数据结构。ANTLR也能够自动生成树的遍历器,这样你就可以访问树中的节点,执行自定义的业务逻辑代码。   本书既是ANTLR 4的参考手册,也是解决语言识别问题的指南。你会学到如下知识:   识别语言样例和参考手册中的语法模式,从而编写自定义的语法。   循序渐进地为从简单的JSON到复杂的R语言编写语法。同时还能学会解决XML和Python中棘手的识别问题。   基于语法,通过遍历自动生成的语法分析树,实现自己的语言类应用程序。   在特定的应用领域中,自定义识别过程的错误处理机制和错误报告机制。   通过在语法中嵌入Java动作(action),对语法分析过程进行完全的掌控。   本书并非教科书,所有的讨论都是基于实例的,旨在令你巩固所学的知识,并提供语言类应用程序的基本范例。   本书的读者对象本书尤其适用于对数据读取器、语言解释器和翻译器感兴趣的开发者。虽然本书主要利用ANTLR来完成这些工作,你仍然可以学到很多有关词法分析器和语法分析器的知识。初学者和专家都需要本书来高效地使用ANTLR 4。如果希望学习第三部分中的高级特性,你需要先了解之前章节中的ANTLR基础知识。此外,读者还需要具备一定的Java功底。   Honey Badger版本ANTLR 4的版本代号是“Honey Badger”,这个名字来源于一段著名的YouTube短片The Crazy Nastyass Honey Badger(网址为:http://www.youtube.com/watch?v=4r7wHMg5Yjg)中的勇敢无畏的主角——一只蜜獾。它敢吃你给它的任何东西,根本不在乎那是什么!   ANTLR 4有哪些神奇之处ANTLR 4引入了一些新功能,降低了入门门槛,使得语法和语言类应用程序的开发更加容易。最重要的新特性在于,ANTLR 4几乎能够处理任何语法(除了间接左递归,稍后会提到)。在ANTLR将你的语法转换成可执行的、人类可读的语法分析代码的过程中,语法冲突或者歧义性警告不会再出现。   无论多复杂的语法,只要你提供给ANTLR自动生成的语法分析器的输入是合法的,该语法分析器就能够自动识别之。当然,你需要自行保证该语法能够准确地描述目标语言。   ANTLR语法分析器使用了一种名为自适应LL(*)或者ALL(*)(读作“all star”)的新技术,它是由我和Sam Harwell一起开发的。ALL(*)是ANTLR 3中的LL(*)的扩展,在实际生成的语法分析器执行前,它能够在运行时以动态方式对语法执行分析,而非先前的静态方式。由于ALL(*)语法分析器能够访问实际的输入文本,通过反复分析语法的方式,它最终能够决定如何识别输入文本。相比之下,静态分析必须考虑所有可行的(无限长的)输入序列。   在实践中,拥有ALL(*)意味着你无须像在其他语法分析器生成工具(包括ANTLR 3)中那样,扭曲语法以适应底层的语法分析策略。如果你曾经为ANTLR 3的歧义性警告和yacc的归约/归约冲突(reduce/reduce conflict)而抓狂,ANTLR 4就是你的不二之选!   另外一个强大的新功能是ANTLR 4极大地简化了匹配某些句法结构(如编程语言中的算术表达式)所需的语法规则。长久以来,处理表达式都是ANTLR语法(以及手工编写的递归下降语法分析器)的难题。识别表达式最自然的语法对于传统的自顶向下的语法分析器生成器(如ANTLR 3)是无效的。现在,利用ANTLR 4,你可以通过如下规则匹配表达式:   类似expr的自引用规则是递归的,更准确地说,是左递归(left recursive)的,因为它的至少一个备选分支直接引用了它自己。   ANTLR 4自动将类似expr的左递归规则重写成了等价的非左递归形式。唯一的约束是左递归必须是直接的,也就是说规则直接引用自身。一条规则不能引用另外一条规则,如果后者的备选分支之一在左侧直接引用了前者(而没有匹配一个词法符号)。详见5.4节。   除了上述两项与语法相关的改进,ANTLR 4还使得编写语言类应用程序更加容易。ANTLR生成的语法分析器能够自动建立名为语法分析树(parse tree)的视图,其他程序可以遍历此树,并在所需处理的结构处触发回调函数。在先前的ANTLR 3中,用户需要补充语法来创建树。除了自动建立树结构之外,ANTLR 4还能自动生成语法分析树遍历器的实现:监听器(listener)或者访问器(visitor)。监听器与在XML文档的解析过程中响应SAX事件的处理器相似。   由于拥有以下几点ANTLR 3所不具备的新特性,ANTLR 4显得非常容易上手:   最大的改变是ANTLR 4降低了语法中内嵌动作(代码)的重要性,取而代之的是监听器和访问器。新机制将语法和应用的逻辑代码解耦,使得应用程序本身被封装起来,而非散落在语法的各处。在没有内嵌动作的情况下,你可以在多个程序中复用同一份语法,甚至都无须重新编译生成的语法分析器。虽然ANTLR仍然允许内嵌动作的存在,但是在ANTLR 4中,它们更像是一种进阶用法。这样的行为能够最大程度地掌控语法分析过程,但其代价是语法复用性的丧失。   由于ANTLR能够自动生成语法分析树和树的遍历器,在ANTLR 4中,你无须再编写树语法。取而代之的是一些广为人知的设计模式,如访问者模式。这意味着,在学会了ANTLR语法之后,你就可以重回自己熟悉的Java领域来实现真正的语言类应用程序。   ANTLR 3的LL(*)语法分析策略不如ANTLR 4的ALL(*)强大,所以ANTLR 3为了能够正确识别输入的文本,有时候不得不进行回溯。回溯的存在使得语法的调试格外困难,因为生成的语法分析器会对同样的输入进行(递归的)多趟语法分析。回溯也为语法分析器在面对非法输入时给出错误消息设置了重重障碍。   ANTLR 4是25年前我读研究生时所走的一小段弯路的成果。我想,我也许会稍微改变我曾经的座右铭。   为什么不花5天时间编程,来使你25年的生活自动化呢?ANTLR 4正是我所期望的语法分析器生成器,现在,我终于能够回头去研究我原先在20世纪80年代试图解决的问题——假如我还记得它的话。   本书的主要内容本书是你所能找到的有关ANTLR 4的信息源中最好、最完整的。免费的在线文档提供了足够多有关基础语法的句法和语义的资料,不过没有详细解释ANTLR的相关概念。在本书中,识别语言的语法模式和将其表述为ANTLR语法的内容是独一无二的。贯穿全书的示例能够在构建语言类应用程序方面助你一臂之力。本书可帮助你融会贯通,成为ANTLR专家。   本书由四部分组成。   第一部分介绍了ANTLR,提供了一些与语言相关的背景知识,并展示了ANTLR的一些简单应用。在这一部分中,你会了解ANTLR的句法以及主要用途。   第二部分是一部有关设计语法和使用语法来构建语言类应用程序的“百科全书”。   第三部分展示了自定义ANTLR生成的语法分析器的错误处理机制的方法。随后,你会学到在语法中嵌入动作的方法——在某些场景下,这样做比建立树并遍历之更简单,也更有效率。此外,你还将学会使用语义判定(semantic predicate)来修改语法分析器的行为,以便解决一些充满挑战的识别难题。   本部分的最后一章解决了一些充满挑战的识别难题,例如识别XML和Python中的上下文相关的换行符。   第四部分是参考章节,详细列出了ANTLR语法元语言的所有规则和ANTLR运行库的用法。   完全不了解语法和语言识别工具的读者请务必从头开始阅读。具备ANTLR 3使用经验的用户可从第4章开始阅读以学习ANTLR 4的新功能。   有关ANTLR的更多在线学习资料在http://www.antlr.org上,你可以找到ANTLR、ANTLRWorks2图形界面开发环境、文档、预制的语法、示例、文章,以及文件共享区。技术支持邮件组是一个对初学者十分友好的公开讨论组。   Terence Parr2012年11月于旧金山大学致  谢Acknowledgements大约25年前,我开始致力于ANTLR的相关工作。那时,在许多人的帮助下,ANTLR工具的句法和功能逐渐成形,在此,我向他们致以由衷的感谢。要特别感谢的是Sam Harwell,他是ANTLR 4的另一位开发者。他不仅帮助我完成了此软件,而且在ALL(*)语法分析算法上做出了突出的贡献。Sam也是ANTLRWorks2语法IDE的开发者。   感谢以下人员对本书进行了技术审阅:Oliver Ziegermann、Sam Rose、Kyle Ferrio、Maik Schmidt、Colin Yates、Ian Dees、Tim Ottinger、Kevin Gisi、Charley Stran、Jerry Kuch、Aaron Kalair、Michael Bevilacqua-Linn、Javier Collado、Stephen Wolff以及Bernard Kaiflin。同时,我还要感谢那些在本书和ANTLR 4软件处于beta版本时报告问题的热心读者。尤其要感谢的是Kim Shrier和Graham Wideman,他们二位的审阅格外认真。Graham的审阅报告之仔细、翔实和广博,令我不知是该紧握他的手予以感谢,还是该为自己的疏漏羞愧难当。   最后,我还要感谢编辑Susannah Davidson Pfalzer,她一如既往地支持我完成了三本书的创作。她提出的宝贵建议和对本书内容的精雕细琢使本书更加完美。   The Translator's Words译 者 序四年前,我在读研究生时曾经参考龙书编写过一个简单的编译器前端。经过一个星期的实践后,我意识到,从头实现一个编译器前端的难度远远超出了一般开发者的能力。编写编译器前端所需要的理论基础、技术功底和精力都远非普通软件可比。   幸运的是,ANTLR的出现使这个过程变得易如反掌。ANTLR能够根据用户定义的语法文件自动生成词法分析器和语法分析器,并将输入文本处理为(可视化的)语法分析树。这一切都是自动进行的,所需的仅仅是一份描述该语言的语法文件。   一年前,我在为淘宝的一个内部数据分析系统设计DSL时,第一次接触到了ANTLR。使用ANTLR之后,我在一天之内就完成了整个编译器前端的开发工作,从而能够迅速开始处理真正的业务逻辑。从那时起,我就被它强大的功能所深深吸引。简而言之,ANTLR能够解决别的工具无法解决的问题。   软件改变了世界。数十年来,信息化的浪潮在全球颠覆着一个又一个的行业。然而,整个世界的信息化程度还远未达到合理的高度,还有大量传统行业的生产力可以被信息化所解放。在这种看似矛盾的情形背后存在着一条鸿沟:大量从事传统行业的人员拥有在本行业中无与伦比的业务知识和经验,却苦于跟不上现代软件发展的脚步。解决这个问题的根本方法就是DSL(Domain Specific Language),让传统行业的人员能够用严谨的方式与计算机对话。其实,本质上任何编程语言都是一种DSL,殊途同归。   而实现DSL的主要困难就在编译器前端。编译器被称为软件工程皇冠上的明珠。一直以来,对于普通的开发者而言,编译器的设计与实现都如同诗中描述的那样:“白云在青天,可望不可即。”   ANTLR改变了这一切。ANTLR自动生成的编译器前端高效、准确,能够将开发者从繁杂的编译理论中解放出来,集中精力处理自己的业务逻辑。ANTLR 4引入的自动语法分析树创建与遍历机制,极大地提高了语言识别程序的开发效率。   时至今日,ANTLR仍然是Java世界中实现编译器的不二之选,同时,它对其他编程语言也提供了不同程度的支持。在开始学习ANTLR时,我发现国内有关ANTLR的资料较为贫乏,这催生了我翻译本书的念头。我期望通过本书的翻译,让更多的开发者能够更加自如地解决职业生涯中碰到的难题。   本书没有冗长的理论,而是从一些具体的需求出发,由浅入深地介绍了语言的背景知识、ANTLR语法的设计方法以及基于ANTLR 4实现语言识别程序的详细步骤。它尤其适用于对语言识别程序的开发感兴趣的开发者。不过,假如你现在没有这样的需求,我仍然建议你阅读本书,因为它能够开拓你的眼界,让你深入实现层面加深对编程语言的理解。
.Net精品就业班课程表 : 1、.Net基础加强(10天) 核心技术课程 常用数据结构(List、Dictionary、Array)、多态、常用设计模式、反射、常用.net类库、泛型、IO流、委托事件、正则表达式、XML、反射、GC等。 2、数据库开发及ADO.Net(6天) 核心技术课程 数据库开发基础、Microsoft SQLServer基础、SQL语言基础、索引、事务、SQL语言高级技术(空值处理、聚合与分组、数据分页、Union、日期函数、类型转换函数、流控函数、表连接、子查询、存储过程、触发器)、数据库设计范式、数据库调优。 ADO.Net(行集、数据集、类型化数据集、SQLHelper、SQL注入漏洞防范、数据绑定)。 3、三层架构MIS项目(5天) 查看项目演示 功能点 本项目基于流行的三层架构(DAL+BLL+UI)。 主要功能点:高安全性的用户管理体系、高安全性的异构系统数据导入导出、拼音检索、复合检索、无限级次数据管理、个性化邮件群发、Excel文件导入导出。 技术点 ADO.Net技术应用、SQLServer、MD5安全算法、基于NPOI的Excel文件处理、树状结构数据处理、递归、CodeSmith、代码生成器、三层架构。 项目说明 这是一个用WinForm技术实现的系统,传智播客在开课的半个月就安排一个项目,体现了传智播客“项目驱动学习”的先进教学理念。 4、网页开发与JavaScript(7天) 查看案例演示 核心技术课程 HTML基础加强、css(包含Div+CSS布局)、JavaScript、Dom(事件、window对象、document对象、对话框、定时器、粘贴板、动态Dom、跨浏览器兼容性解决方案、JS压缩和CDN、Internet Explorer Developer Toolbar)、JQuery(JQuery函数、隐式迭代、链式编程、id选择器、tag选择器、CSS选择器、层次选择器、表单选择器、过滤选择器、复合选择器、节点导航、节点操作、样式操作、事件、动画、JQuery Cookie、JQuery Live、JQueryUI)。 课程说明 CSS、JavaScript是ASP.Net开发的基础,把这些掌握好了就能很轻松的学会ASP.Net;Dom是实现网页动态效果的技术,在网站越来越个性化年代,招聘企业对应聘者的Dom水平要求非常高;JQuery是近几年异军突起的JavaScript框架库,几乎成了Web前端开发事实上的标准,大部分企业都是使用JQuery进行Web前端的开发。 学完了这阶段课程,学员将学会开发主流网站的前端效果,比如:焦点图、滚动展示图、网页防复制、网页自定义菜单、WebOS、美女时钟、无刷新评论、评分控件、表格特效、图片悬浮详细信息、微博界面、QQ消息框效果、Div对话框等。 5、ASP.Net开发(12天) 核心技术课程 自己动手写Web服务器(Socket、多线程)、ashx模式Web开发、ViewState、Cookie、Session、Http协议、Web开发基本原则、XSS漏洞防范、Request对象、Response对象、Server对象、虚拟路径、HttpHandler深入、ASP.Net生命周期、WebForm原理、服务端基本控件、WebShell漏洞防范、HTML服务端控件、验证框架、MasterPage、数据绑定控件(ObjectDataSource、列表类绑定控件、GridView、FormView、ListView、Repeater、高效率分页)、CKEditor、Membership、缓存、互联网调优(SEO、HTML压缩、页面静态化、移除ViewState、表单GET化)、URL重写、错误处理、AJAX(XMLHTTP、JQuery AJAX、Json)、全局文件、HttpHandler与HttpModule、IIS配置。 课程说明 由于微软对ASP.Net进行高度封装,因此ASP.Net入门非常简单,开发人员不需要了解HTML、JavaScript、Http协议也可以快速开发出一个Web系统,正因为如此,社会上充斥着大量这样的“拖控件的开发人员”,使得很多Java、PHP等语言的开发人员诋毁ASP.Net开发人员的时候经常会说“你们什么都不懂,就会拖控件”。ASP.Net的快速开发是ASP.Net非常大的一个优点,可以加快开发效率,这是行业的发展趋势,但是局限于这样的“傻瓜化开发方式”的开发人员的竞争力和成长性都是非常有限的,遇到ASP.Net一些高级技术(比如ASP.Net MVC、SEO、网站调优、服务端客户端混合编程、AJAX等)的时候就完全不能胜任。通过上一个阶段的HTML、JavaScript、Dom的学习,学员已经有了很好的HTML、JavaScript基础;在ASP.Net课程的一开始,不是直接教学员怎么拖ASP.Net控件进行快速开发,而是通过ashx的模式开发原始的动态网站,让学员明白“请求—处理—响应模型”、“Http协议、Http无状态”、“c#代码渲染生成浏览器端JavaScript”、“ViewState的作用”、“Session的原理”等这些基本而又重要的原理,从而扫清后面ASP.Net知识学习的基础性障碍。 由于访问量非常大,因此互联网项目的开发对ASP.Net开发人员的要求非常高,所以我们安排了互联网调优、缓存、网站防黑等内容。 ASP.Net中控件数量是非常多的,讲解ASP.Net的教材通常要上千页,让初学者望而生畏,其实ASP.Net大部分控件相似性非常强的,同类型的控件学会了一个那么其他控件也就很容易学会了。比如只要学会了DropDownList,那么RadioButtonList、ListBox、CheckBoxList、BulletedList等几乎不用学就会用;再比如只要学会了ListView,那么Repeater、GridView、FormView等控件也是触类旁通。传智播客认真钻研教学,对知识进行分类、整理、提炼精华,让学员在短时间内掌握ASP.Net技术。 ASP.Net中有一些技术是有局限性的,传智播客根据这些技术在企业中的实际应用情况进行了调整、补充。比如项目中几乎没有在UI层直接访问数据库的,而是采用三层架构,因此我们不讲解UI层直连数据库的控件SQLDataSource,而是把主要精力放在讲解三层架构开发模式。再比如ASP.Net内置的AJAX解决方案UpdatePanel只在部分要求不高的内网项目中才被使用,因此我们在讲解UpdatePanel的使用和原理之外,把更多的时间放在讲解企业中用的最多的JQuery AJAX解决方案上。 6、B/S系统项目(7天) 项目说明 1、网上图书商城。这是一个典型的B2C网上商城,使用经典的复杂三层架构(工厂模式)进行开发。涉及图书管理、搜索、订单管理、导航管理等核心模块。在讲解ASP.Net基础后安排这样一个B2C网上商城系统,让学员在实际项目中将学到的知识学以致用。 2、办公自动化OA系统。这是一个典型的基于ASP.Net技术的OA协同办公项目,包含了权限管理、公告管理、文档管理、工作流、论坛管理、新闻模块管理、人员管理等典型的OA系统模块。 3、数据采集和邮件群发。这是一个基于多线程的邮件营销平台,核心技术包括网络爬虫、多线程、HTML解析、邮件发送、生产者消费者模式等。 注:以上三个案例,上课时会根据每个班的课堂反馈选择其中一个案例予以讲解学习。 7、如鹏网项目(9天) 查看项目演示 功能点 站内搜索、栏目管理、视频播放(完全模仿优酷视频页面)、焦点图、静态页面生成(新浪、搜狐等大型网站普遍采用的技术)、文章管理、无刷新评论、评论的无刷新分页、敏感词过滤、用户管理、友情链接管理、缓存管理、广告位管理、RSS输出、水印设置、无刷新上传图片、搜索引擎优化设置、数据备份恢复、伪静态设置、网上商城、订单管理、在线支付(支持支付宝、财付通、块钱等第三方支付平台)、网站调优(数据库优化、缓存、静态页、CSS Spirit、js压缩)。 技术点 搜索引擎技术:Lucene.Net、多线程开发、爬虫技术、网页分析、正则表达式、Log4Net日志框架、Quartz.Net定时作业调度。 大型互联网开发技术:代码生成、网页静态化、基于JQuery的Web2.0页面开发、AJAX、SEO、网站调优、采集器、RSS/XML、网站防黑(防XSS攻击、防注入漏洞攻击、防CC攻击、防挂马、防盗链、敏感词过滤、广告帖智能过滤)、IIS管理与调优、流量分析、第三方脚本嵌入(广告、统计代码、内容联盟等)、图片服务器分离。 项目说明 如鹏网项目是已经上线三年的网站,日访问量最高20000人次,网址www.rupeng.com。本系统旧版本基于PHP、J2EE技术,由如鹏网开发者亲手操刀用.net重写新版本。系统分为前台Web界面、后台管理界面、站内搜索、监控客户端四个子系统。 大型互联网站由于访问量非常大,因此不是那些单纯用ASP.Net控件拖拽开发的开发人员能够开发的,也不是闭门造车能够造出来的,必须是在实际项目中经过无数访问者的使用、反馈、修改才能做出来的。搜房网、汽车之家等大型网站中用到的网站静态化、图片服务器分离、高性能缓存、HTML/JS压缩、CDN、CSS Sprite、负载均衡、Memcached、镜像服务器同步等问题不是那些随手写出来的所谓在线商城、电子商务系统所所能够涉及到的。 这个项目完全按照高访问量互联网站进行设计,通过这个项目,学员不仅可以在实战中巩固对前面学习的ASP.Net、ADO.Net、WinForm等知识的掌握,还可以掌握网站防黑、缓存、SEO、静态化、搜索引擎技术、AJAX等大型互联网开发中涉及到的技术。 8、.Net新技术(Windows Phone、ASP.Net MVC)(6天) 项目说明 未来是移动互联网的时代,未来将是Windows Phone、Android、iphone三足鼎立的时代,掌握了移动开发的技能的人是就业市场的抢手货。微软推出的Windows Phone平台是微软在移动互联网时代的一个重量级产品,微软对于WindowsPhone7的推广力度非常大,因此很多公司也开始进行Windows Phone7产品的研发,2011年下半年Windows Phone7开发人员的需求将会出现井喷,为了帮助学员掌握移动3G开发技术,传智播客.Net班加入了Windows Phone开发课程,采用传智播客独创的WP7Simulator教学平台,学员可以做出一个基于云计算架构的LBS系统。点击查看传智播客独创WP7Simulator教学平台。 ASP.Net MVC是微软推出的区别于ASP.Net WebForm的Web开发新技术,由于ASP.Net MVC解决了ASP.Net WebForm的很多缺点,非常适合大型、中型项目的开发,一经推出就受到了.Net开发社区的追捧,很多.Net开发人员的职位要求中都提到了MVC,可见掌握ASP.Net MVC技术必将提升自己就业的砝码。 9、就业指导(2天) 项目说明 总结以往所学知识,讲解《传智播客.Net面试、笔试宝典》,介绍简历、笔试、面试等所需的知识和技巧。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值