w3ctech 2011 JavaScript 专题会议(广州站)​综述

  • 崔康

2011 年 8 月 8 日

话题:Java.NETRubyWeb框架编程语言开源JavaScript社区架构ChromeHTML5DevOpsNode.js语言 & 开发文化 & 方法

w3ctech 2011 JavaScript 专题会议(广州站)​日前在华师大附中召开,参会者近 300 人,来自国内技术社区的四位知名专家陈广琛、赵劼、周爱民、贺师俊分别做了精彩的演讲,涉及的内容包括​​​​云端 NodeJS、JS 异步解决方案 Jscex、开源 Javascript 引擎 Narcissus、ECMAScript 5 的 strict 模式等。InfoQ 中文站整理了大会的精彩内容,供读者参考。

云端 JavaScript 漫游指南

雅虎前端工程师陈广琛演讲的主题是《云端 JavaScript 漫游指南》​,他以丰富的实例和现场演示介绍了NodeJS的强大功能和云端部署的​知识。

正如陈广琛在开场白里所说,十年前的 Javascript 还要看 VBScript、PHP、CGI 的脸色,而如今 Javascript 的强大从前端延伸到了后端。在​解释 JavsScript 依靠 NodeJS 平台作为服务器端编程语言​的优势时​,他在会场演示了两个功能不大但让人印象深刻的 NodeJS 开发案例,这些以前 Web 开发人员需要采用其他语言实现的功能,如今用熟悉的 JavaScript 即可完成。让我们来体会一下 NodeJS 的魅力。

域名重定向(biz-to-me)代码示例​:

 const http = require('http');

 var server = http.createServer(function(request, response) {

    var host = request.headers['host'];

    var url = request.url; 

    console.log('request from: http://' + host + url);



    host = host.replace(/catchen\.biz$/, 'catchen.me');

    if (host == request.headers['host']) {

        host = 'catchen.me';

        url = '/'

    }

    var location = 'http://' + host + url;



    console.log('redirect to: ' + location);

    response.writeHead(302, {

        Location: location

    });

    response.write('Temporarily moved to <a href="' + location + '">' + location + '</a>.');



    response.end();

});

var port = process.env.PORT || 3000;

server.listen(port, function(){



    console.log("Listening on " + port);

});

​短 URL 解析(traceurl)的代码示例可以从这里查看。

从这两个例子中,我们可以看到一些亮点,比如:

  • 导入函数库时,可以赋值给命名常量,便于范围管理,像 const http = require('http')。
  • 服务器端处理主要函数是 createServer 中传入的回调函数 function(request, response)。
  • 从 request 解析 http 请求,用 response 返回响应。
  • 采用 Javascript 语言,参数 Json 风格。
  • 无需配置 Apache。
  • 支持 URL 路由(字符串定义和正则表达式两种)。

陈广琛特别介绍了 NodeJS 的Express.js 库,常用的功能包括:

  • 日志管理
  • 路由
  • cookie 解析
  • session 管理
  • 模板引擎

有志于从事 NodeJS 应用开发的朋友,可能会担心 NodeJS 相关的支持工具包(package)不够多从而导致开发比较麻烦。陈广琛建议大家利用NPM搜索已有的工具包。NPM 是针对 NodeJS 的包管理器,可以用来安装和发布 NodeJS 应用,它能够管理依赖等。除了利用第三方的工具包,陈广琛还介绍了如何构建自己的 package(见短 URL 解析代码示例),大体分为三步:

  • 使用 module.exports 编写模块。
  • 提供 package.json 和 index.js 文件。
  • 使用 npm publish 发布。

演讲的后半部分转到了演讲的关键字——云端。对于已经构建好的 NodeJS 应用,部署在何处?陈广琛指出,无论是租用机房的服务器还是购买 VPS 服务,都不是理想的选择,“云端”才是大势所趋。他介绍了四款 NodeJS 云端服务:

其中 Heroku 提供每月 750 小时的单进程免费服务,适合于简单的 NodeJS 应用和学习实践。

最后,陈广琛指出 NodeJS 的最大优势在于高并发和异步 IO,只有应用存在这些需求时,NodeJS 才会表现出相比其他平台或语言的过人之处。

提升 JavaScript 生产力的“异样”编程手段

IBM 高级咨询师、InfoQ 中文站编辑赵劼以《提升 JavaScript 生产力的“异样”编程手段》为题介绍了其创建的 Javascript 开源项目Jscex,对深陷异步编程困扰的开发人员很有启发和帮助。

老赵在开场阶段一如既往地批评 Java 语言的不足,他以构建书籍索引为例,C# 语言的实现代码如下:

// C#

List<string> keywords = ...;

var result = keywords

    .GroupBy(k => k[0].ToUpper())

    .ToDictionary(

        g => g.Key,

        g => g.OrderBy(k => k).ToList());

与此形成鲜明对比的是 Java 语言的实现代码:

List<String> keywords = ...;

Map<Character, List<String>> result = new HashMap<...>();

for (String k: keywords) {

    char firstChar = k.charAt(0);

    if (!result.containsKey(firstChar)) {

        result.put(firstChar, new ArrayList<String>());

    }

    result.get(firstChar).add(k);

}

for (List<String> list: result.values()) {

    Collections.sort(list);

}

老赵总结了 Java 的四点不足:

  • 命令式编程(强调怎么做)
  • 复杂的匿名类型语法
  • 强制写清所有类型名
  • 无法扩展既有类型

而现代语言的常见特性是什么呢?

  • 声明式编程(做什么)
  • 易用的 Lambda 表达式语法
  • 类型推断(对于静态语言)
  • 无侵入的类型扩展

老赵指出,Javascript 有着优秀的特性,不过在异步编程时存在不足,会破坏代码局部性,将逻辑拆分地支离破碎,同时对异步操作之间的协作和组合、异常处理及取消造成了困难,开源项目 Jscex(JavaScript Computation EXpression)正是为了解决这些问题,其借鉴了 F# 的计算表达式特性,Jscex 是 Javascript 语言扩展,通过非常巧妙的手段让开发人员享受异步编程的乐趣。比如,在定义异步操作时,需要采用如下代码形式:

// 使用异步构造器执行编译后的代码

var somethingAsync = eval(Jscex.compile("async",

    function (...) {

        // 实现

    }

));

调用形式如下:

function () {

    var res = $await(<async work>);

}

适用的异步任务包括:HTTP 请求、UI 事件、时钟回调、查询响应、Web Service 响应、代理消息等。这种编程方式使得开发人员在异步处理时不会被无处不在的 SetTimeout() 函数困扰,确保代码结构清晰、便于维护。

老赵特别介绍了其 Jsces 编译器所采用的核心思想和技术:

  • 视 JavaScript 代码为 DSL
  • 使用函数的 toString 方法获得代码
  • 使用 eval 动态执行代码

关键思路可以概括为:

var compile = function (f) {

    // 获得函数代码

    var code = f.toString();

    // 解析代码至语法树

    var ast = parse(code);

    // 生成新代码

    return generateCode(ast);

}

其优点包括:

  • 载体即为普通 JS 代码,行为一致
  • 无需额外编译步骤
  • 可以使用原有 JavaScript 编辑环境

针对 eval 的性能和安全问题,老赵指出 JScex 支持在发布前生成编译后的代码,去除 eval 和 compile 的开销,解除与编译器的依赖。

目前社区中存在多种异步框架和异步语言,老赵在对比分析时表示,Jscex 的优势在于:

  • 使用 JavaScript 表达逻辑
  • 极高的灵活度和表达能力
  • 只需少量学习
  • 完全使用 JavaScript 语法
  • 完全保留 JavaScript 语义
  • 完全保留 JavaScript 编程体验

Jscex 基于 BSD 协议开源,目前托管于githubsndacode上。感兴趣的读者朋友可以阅读老赵为InfoQ 中文站独家撰写的深度技术文章《使用 Jscex 改善 JavaScript 异步编程体验》。

JS in JS——在 JS 中实现 JS 引擎的详细剖析

资深技术专家、支付宝架构师周爱民分享了 Mozilla 开源 Javascript 引擎Narcissus(采用 Javascript 实现)在语法分析、语句执行方面的技术细节,让到场的开发人员对 Javascript 有了更深的理解。

周爱民首先抛出了三个例子,让大家判断一下运行结果分别是什么(读者可以尝试一下):

function() {

}()

function() {

}(1)

(function() {

})(1)

在强调了理解 Javascript 语法的重要性之后,周爱民介绍了 Narcissus 项目的基本情况,它由 js.js、jsdefs.js、jsparse.js 和 jsexec.js 四个文件组成。其中重点是后两个文件。jsparse.js 主要用于语法分析。在 Narcissus 中,语法层次由高到低分为 Script、Statements、Statement、ParenExpression、Expression 等,都视为 Node。以 var a, i = 100 , v = i + 100; 为例,其语法树为:

jsexec.js 文件主要包含了语句执行的引擎代码,周爱民介绍了 Javascript 语言上下文执行环境、new、with、function、object、eval 等重要概念、技术的实现细节和对开发者的启示。以 new 为例,其中的关键代码如下:

v = f.__construct__(a, x);

……

FOp.__construct__ = function(a,x) {

  var o = {}, p = this.prototype;

  o.__proto__ = p;

  var v = this.__call__(o, a, x);

  if (isObject(v)) return v;

  return o; 

周爱民建议大家认真读一下 Narcissus 项目的源代码,有助于体会 Javascript 的精髓。jsparse.js 和 jsexec.js 两个文件的代码都在 1000 行左右,感兴趣的读者可以结合周爱民的视频学习 Narcissus 项目,这是一个很好的起点。 

ECMAScript 5——Improve the Safety of JavaScript

盛大创新院研究员贺师俊在第四场演讲中以 ECMAScript 5 为主题精彩收尾。他首先指出了 ECMAScript 的发展方向,包括:

  • API 扩展和标准化:JSON、Array.protoype.forEach/map/filter...
  • 通用化,可实现平台对象:get/set accessor、Object.defineProperty 等等
  • 适应于 PITL(programming-in-the-large)

他认为 Javascript 传统上是小型开发语言,存在一些不足:

  • 设计为一门依赖于 host 环境的脚本语言
  • 无内置 module/namespace
  • 缺少较全面的标准 API 库
  • 缺乏各种 invariants 约束的能力
  • 残缺的 OO

正式因为存在这些缺陷,导致开发人员在使用 Javascript 编程时,经常掉进危险的陷阱。贺师俊结合日常工作中的亲身实践列举了几个,包括 this 引用、with 语句等,都会引起潜在的代码漏洞,在企业级开发中,由于代码结构比较复杂,使得开发人员在调试 bug 时难以定位。比如下面这个小例子:

Dog.prototype.setName = function(name) {

    this.name = String(name).toLowerCase()

}

贺师俊认为 String(name) 并不是一种鲁棒性的实践方式,反而可能在开发人员的不经意间导致代码的错误而且不易发现,比如:

var q = new Dog()

q.setName(q)    // q.setName('q')

如何解决这些问题呢?贺师俊建议开发人员在条件允许的情况下开启 ECMAScript 5 的strict 模式,并应用一些辅助开发工具包,例如guard.jsjsguardsjsHelpers OverloadTrademark/Guard proposal等。 

没有参会的朋友可以通过主办方w3ctech的相关页面下载幻灯片和观看演讲视频。JavaScript 专题会议北京站和上海站分别将在 8 月 27 日和 9 月 24 日举行,感兴趣的读者可以报名(北京)和预约(上海)参加。InfoQ 中文站将继续关注国内 Web 技术社区的发展。

Java.NETRubyWeb框架编程语言开源JavaScript社区架构Chrome