黑色小鸟 - 前端分层架构

介绍

一群恶魔的猪从无辜的小鸟那里偷走了所有的前端架构,现在它们要夺回来。一对特工英雄(愤怒的小鸟)将攻击那些卑鄙的猪,直到夺回属于他们的前端架构。(译者注:本系列是关乎前端架构的讨论,作者借用当前最风靡的游戏 - 愤怒的小鸟,为我们揭开了前端架构的真实面目。)

小鸟们最终能取得胜利吗?它们会战胜那些满身培根味的敌人吗?让我们一起来揭示 JavaScript 之愤怒的小鸟系列的另一个扣人心弦的章节!

阅读本系列的介绍文章,查看所有小鸟以及它们的进攻力量。

战况

黑色小鸟的攻击力

black bird

在这篇文章中,我们将看看黑色小鸟,它们使用 Backbone.js 的组织方式,用炸弹进攻肥小猪们。慢慢的,小鸟们将一个接一个地夺回本属于他们的东西。

黄色小鸟 - 模块化、依赖管理、性能优化

介绍

一群恶魔的猪从无辜的小鸟那里偷走了所有的前端架构,现在它们要夺回来。一对特工英雄(愤怒的小鸟)将攻击那些卑鄙的猪,直到夺回属于他们的前端架构。(译者注:本系列是关乎前端架构的讨论,作者借用当前最风靡的游戏 - 愤怒的小鸟,为我们揭开了前端架构的真实面目。)

小鸟们最终能取得胜利吗?它们会战胜那些满身培根味的敌人吗?让我们一起来揭示 JavaScript 之愤怒的小鸟系列的另一个扣人心弦的章节!

阅读本系列的介绍文章,查看所有小鸟以及它们的进攻力量。

战况

黄色小鸟的攻击力

在这片文章中,我们将看看黄色小鸟,它使用 RequireJS 作为助推器,利用动态脚本加载来攻击那些讨厌的猪。慢慢的,小鸟们将一个接一个地夺回本属于他们的东西。

蓝色小鸟 - 事件

介绍

一群恶魔的猪从无辜的小鸟那里偷走了所有的前端架构,现在它们要夺回来。一对特工英雄(愤怒的小鸟)将攻击那些卑鄙的猪,直到夺回属于他们的前端架构。(译者注:本系列是关乎前端架构的讨论,作者借用当前最风靡的游戏 - 愤怒的小鸟,为我们揭开了前端架构的真实面目。)

小鸟们最终能取得胜利吗?它们会战胜那些满身培根味的敌人吗?让我们一起来揭示 JavaScript 之愤怒的小鸟系列的另一个扣人心弦的章节!

阅读本系列的介绍文章,查看所有小鸟以及它们的进攻力量。

战况

蓝色小鸟的攻击力

在这篇文章中,我们将看看蓝色小鸟,它通过触发事件和消息来渗透进猪猪的城堡中,慢慢的,小鸟们将一个接一个地夺回本属于他们的东西。

红色大鸟 - 立即调用的函数表达式

介绍

一群恶魔的猪从无辜的小鸟那里偷走了所有的前端架构,现在它们要夺回来,一对特工英雄(愤怒的小鸟)将攻击那些卑鄙的猪,直到夺回属于他们的前端架构。(译者注:本系列是关乎前端架构的讨论,作者借用当前最风靡的游戏 - 愤怒的小鸟,为我们揭开了前端架构的真实面目。)

本文将介绍红色大鸟,它们以 IIFE 作为中坚力量进行进攻,IIFE 是一切私有化的基础。

译注:IIFE (Immediately-invoked Function Expression) 立即调用的函数表达式

猪猪偷走了什么

多年来小鸟们们习惯于将它们自定的变量和函数乱扔在全局命名空间下(window 对象),随着时间的推移,它们慢慢学会了如何使用一些技巧来保护他们的对象,但是,最近这些非全局命名空间中的秘密都被猪猪给偷走了,幸好小鸟们很辛运,这项技术存在一些缺陷,它们计划攻击猪群,然后释放本属于它们的东西。

愤怒的小鸟与 JavaScript 系列

OlechkaDesign.com

介绍

一群恶魔的猪从无辜的小鸟那里偷走了所有的前端架构,现在它们要夺回来,一对特工英雄(愤怒的小鸟)将攻击那些卑鄙的猪,直到夺回属于他们的前端架构。(译者注:本系列是关乎前端架构的讨论,作者借用当前最风靡的游戏 - 愤怒的小鸟,为我们揭开了前端架构的真实面目。)

来认识一下我们的特工英雄

在接下来的几周里会逐渐向你介绍我们的超级英雄…

  • 红色大鸟(大兄弟)

    红色大鸟兄弟依靠 IIFE 的力量进行攻击,IIFE 是一切私有化的基础。封装你的代码,保护代码免受其他代码的干扰。

    译注:IIFE (Immediately-invoked Function Expression) 立即调用的函数表达式

  • 蓝色小鸟(分身鸟)

    蓝色小鸟触发事件和消息来渗透进猪猪的城堡中。

  • 黄色小鸟(神风敢死鸟)

    黄色小鸟使用 RequireJS 作为助推器,利用动态脚本加载来攻击那些讨厌的猪。

  • 黑色小鸟(炸弹鸟)

    黑色小鸟被证明是最有组织的方法来打击小猪们,它们引入了 Backbone.js 的先进理念,采用炸弹进攻。

  • 白色小鸟(巾帼英雄)

    白色小鸟看似没有攻击力,但是,当它们拿出严格的代码风格和质量检查时,小猪们都惊呆了。

  • 绿色小鸟(回旋鸟)

    绿色小鸟可以抵达那些难以到达的地方,利用模拟和间谍方式来打击那些偷东西的猪。

  • 橙色小鸟(气球鸟)

    开始时,它是一个简单的模板,然后被解析成 DOM 对象,这明确传达了一个消息就是小鸟们是认真的。

  • 大兄弟

    大兄弟拿出了设计模式和有限状态机这杆大枪。

  • 神鹰

    神鹰使用超级武器,一套工具,可以组织和部署其它鸟儿们,来对抗他们即将征服的敌人。

图片来源于 Angry Birds Wiki

Promises 和异步编程

在 JavaScript 中处理异步和回调就是家常便饭,我们通常会面对这样一些问题:

  1. 如何优雅滴组织我们的回调代码
  2. 对异步函数错误处理的最佳实践是什么
  3. 异步嵌套问题
  4. 怎样使我们的代码可读性和可维护性更高

Programs are meant to be read by humans and only incidentally for computers to execute. 程序是给人读的,只是顺带让计算机执行一下。 ——《编写可维护的JavaScript》@Donald Knuth

当然,最常见也是最简单的处理方式就是,直接将回调函数或错误处理函数作为异步函数的参数,在异步函数返回时进行相应的调用,这种方式的缺陷估计大家心里或多或少都有点见解。难道就没有爽的编程模式?

这里分享了几篇文章,主要讲解了 JavaScript 中的 Promise 机制,以及如何使用它来改善我们的异步编程和回调问题。其中三篇参阅了 http://nuysoft.com/2013/08/29/async-programming/ ,另外一篇来自 html5rocks 的 Promise 教程

下图是 jQuery 中动画回调链,图片来自 @司徒正美 的 MVC 分享 PPT。

回调的噩梦

凌乱的异步编程

1. 异常和 try/catch

当执行可能失败的操作时,采用异常机制和 try/catch 是一种直观的方式,这样我们就可以从异常中恢复,或将异常抛出,异常沿着调用堆栈到达调用者,调用者可以处理该异常或将其继续抛出。

看一个简单的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function thisMightFail() {
//...
if(badThingsHappened) {
throw new Error(...);
}
return theGoodResult;
}
function recoverFromFailure(e) {
//...
return recoveryValue;
}
function getTheResult() {
var result;
try {
result = thisMightFail();
} catch(e) {
result = recoverFromFailure(e);
}
return result;
}

在这个例子中,调用 thisMightFail 时一定会失败并抛出一个 Error 异常, getTheResult 捕获了该异常,然后调用 recoverFromFailure(例如,返回某个默认值)来从异常中恢复。这个例子之所以能够工作,是因为 thisMightFail同步的。

用 Promises 简化异步编程

凌乱的异步编程一文中,我们见识了用回调处理异步调用的尴尬局面,即使是一组简单的函数调用。

快速回顾一下,看看我们最初的代码,使用回调函数时的凌乱结果,以及我们为了回到正途而想要解决的几个问题:

  1. 我们再也不能使用简单的“调用 - 返回”(call-and-return)编程模型
  2. 我们再也不能使用 try/catch/finally 来处理异常
  3. 我们必须为可能执行异步操作的每个函数的签名增加 callback 和 errback 参数

1. Promises

一个 Promise(或者叫 Future, Delayed value, Deferred value)代表一个尚不可用的值,因为产生这个值的计算过程尚未完成。一个 Promise 是最终的成功结果或失败原因的占位符。

Promises 还提供了一个简单的 API(见下文),用于在结果完成或故障发生时获取通知。

Promises 不是一个新概念,已经在许多语言中被实现。一些 JavaScript 实现也已经有一段时间了,并且最近变得更加流行,因为我们开始构建更庞大、更复杂的系统,需要协调更多的异步任务。

(注意:虽然 Promise API 标准存在多个提案,但是 Promises/A+ 已经在多个主流框架中被实现,似乎正在成为事实上的标准。无论哪种提案,基本的概念是相同的:1) Promises 作为结果或错误的占位符;2) 提供了一种在结果完成或错误发生时的通知方式。)

用 Promises 控制异步错误处理

正如我们在凌乱的异步编程一文中看到的那样,基于回调函数的异步代码的错误处理也很快变得混乱起来,丢失了许多同步代码具有的优秀品质,使我们更难定位到错误原因。在用 Promises 简化异步编程一文中,我们介绍了 Promises,看到了它如何使我们回到“调用 - 返回”编程模型,允许异步错误像同步错误那样沿着调用堆栈向上传播,并提供一种更清晰方法来管理异步,特别是在处理错误时。

1. Try/catch/finally

在同步代码中,try/catch/finally 提供了一种简单友好但非常强大的惯用语法来执行任务、处理错误,并且总是确保稍后可以执行清理。

译注:idiom 习语

下面是一个简单的 try/catch/finally 示例,与 Part 1 中的原始 getTheResult() 一模一样:

1
2
3
4
5
6
7
8
9
10
// 同步版本
function getTheResult() {
try {
return thisMightFail();
} catch(e) {
return recoverFromFailure(e);
} finally {
alwaysCleanup();
}
}

正如我们已经看到的那样,通过基于回调函数的方式来模拟 try/catch 充满了陷阱,加入 finally 的概念后(即确保执行清理)只会使事情变得更糟。

使用 Promises,我们可以建立一种方法,类似于友好的 try/catch/finally 惯用语法,并且没有深度回调结构。

JavaScript Promises 教程

童鞋们,请准备好迎接 Web 开发历史上一个重大时刻。。。

[鼓声响起]

JavaScript 有了原生的 Promise!

[漫天的烟花绽放,人群沸腾了]

这时候你大概是这三种人之一:

  • 你的身边拥挤着欢呼的人群,但是你却不在其中,甚至你还不大清楚“Promise”是什么。你耸耸肩,烟花的碎屑在你的身边落下。不过不要担心,我也是花了多年的时间才明白 Promise 的意义,你可以从这里开始
  • 你一挥拳!太赞了对么!你已经用过一些 Promise 的库,但是所有这些第三方实现在 API 上都略有差异,JavaScript 官方的 API 会是什么样子?请看这里
  • 你早就知道了,看着那些欢呼雀跃的新人你的嘴角泛起一丝不屑的微笑。你可以安静享受一会儿优越感,然后直接去看 API 参考吧。
go2top