同构JavaScript应用开发(txt+pdf+epub+mobi电子书下载)


发布时间:2020-07-17 21:00:10

点击下载

作者:杰森·史特林贝尔(Jason Strimpel)

出版社:人民邮电出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

同构JavaScript应用开发

同构JavaScript应用开发试读:

前言

Jason Strimpel

我在多年前就开始了 Web 开发的职业生涯,当时我在加州大学圣地亚哥分校担任行政助理。我的工作职责之一就是维护部门网站。那个年代的 Web 开发还是站点管理员、表格式布局和 CGI 程序的天下,且网景浏览器仍然是浏览器领域中的佼佼者。当时,我的专业知识还有很多不足,也缺乏经验。我清晰地记得,当时我很担心,如果我发送的电子邮件中存在拼写错误,收件人就会看到它们被红色下划线标记出来,正如我看到他们的拼写错误时一样。幸运的是,我的上司很耐心,他说我的邮件中并没有拼写错误,并向我传授了关于网站开发的许多要点。

转眼 15 年过去了,如今我在各大会议上发表演讲,管理开源项目,合著图书,成了这个领域的“专家”。有时候我会问自己:“我是如何取得今天的成就的?”这个问题的答案绝不仅仅是任由时间一天天地流逝——至少不完全是虚度时光。为什么需要同构JavaScript

到目前为止,我的 Web 开发之路的最后一站是沃尔玛实验室的平台团队,我的同构 JavaScript 探索之旅就是从这里开始的。刚开始在沃尔玛工作时,我被分配到了一个负责开发 Web 新框架的团队。这个框架是从零开始开发的,其目标是支撑面向公众的大型网站。除了满足这类网站的最低要求,支持 SEO 并优化网页加载速度之外,保持 UI 工程师(包括我在内)的开发愉悦感和高效率也非常重要。很明显,为了更好地实现 UI 工程师的目标,我们的首选是基于现有的单页面应用。(Single-Page Application,SPA,https://en.wikipedia.org/wiki/Single-page_application)技术进行扩展。但 SPA 模型有一个问题,它不能很好地支持我们的最低要求(详情请参见下文中的“完美风暴:一个极其平常的故事”和 1.2.3 节中的“单页面 Web 应用”),所以我们最终选择采用同构的方式。以下是这样做的理由。● 对于同一个渲染周期,客户端和服务器端可以使用同一套代码。这意味着不需要重复劳动,可以在降低界面开发与维护成本的同时提高团队开发速度。● 在服务器端渲染一份初始的 HTML 代码后,用户会感觉网页的加载速度更快,这是因为用户可以在浏览器中先看见首屏渲染的内容,而无须等待应用资源的加载和数据抓取完成。在网络延迟比较严重的环境中,这种改进页面预加载的方式尤为重要。● 同构应用支持 SEO,因为同构应用使用的 URL 不包含 # 号片段。此外,在那些不支持 History API 的浏览器中,它可以(对后续的每次请求)优雅地降级为服务器端渲染的方式。● 在支持 History API 的浏览器中,同构应用使用了 SPA 模型的分布式渲染,因此后续请求可以减轻服务器负载。● 无论是在服务器端还是在客户端,UI 工程师都可以完全掌控界面(https://www.nczonline.net/blog/2013/10/07/node-js-and-the-new-web-front-end/),而且同构应用在前后端之间划分了明确的界限,这有助于降低操作成本。

以上是我们团队走上同构 JavaScript 之路的主要原因。但在详细介绍同构 JavaScript 之前,先交代一些背景知识是很有必要的,这可以帮助你理解我们今天所处的具体环境。平台的演进

Web 技术的快速演进令人难以想象。当初,CSS 和 JavaScript 技术被引入浏览器的目的是提供一种交互模型和关注点分离。你还记得曾有无数的文章提倡结构、样式和行为分离吗?即便在引入了这些技术之后,应用的架构也并没有发生太大变化。文档通过 URI 的形式进行请求,浏览器解析返回内容后,再进行渲染。唯一的不同之处就是 JavaScript 让界面变得更丰富了一点。直到微软公司引入一项被称为 XMLHttpRequest(https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest)的新技术,Web 才在这项技术的催化下演进为应用平台。Ajax:应用平台的崛起

尽管很多前端工程师对微软公司及其 IE 浏览器嗤之以鼻,但他们仍然应当对微软怀有一份感激之情。如果没有微软,前端工程师未必能达到今天的职业高度。如果 XMLHttpRequest 技术没有出现,Ajax 技术也就不会诞生;如果没有 Ajax,就不会有这么多修改页面内容的需求,我们也就没有必要使用 jQuery(https://jquery.com/)。你猜接下来会发生什么呢?我们就不会有大量的前端 MV* 库可供选择,单页面应用的模式也不会出现,进而 History API 也不会出现。所以,下一次抱怨 IE 浏览器给你带来麻烦时,请你务必对微软作出客观评价,毕竟微软改变了历史进程,为今天的 Web 应用奠定了基础,还为你提供了一个锻炼思维的场所。Ajax:技术债的积累

虽然 Ajax 技术影响了 Web 平台的发展进程,但它也以技术债的形式造成了一些破坏性的影响。Ajax 模糊了以前清晰定义的模型。过去,当用户导航到一个新页面或者提交表单数据时,浏览器只需依次发送请求、取得响应并解析完整的文档流。当 Ajax 成为 Web 开发的主流技术后,这种方式完全改变了。现在,工程师不需要向服务器请求重新获取整份文档,只需要根据用户的请求来判断是加载更多数据还是返回另一个视图。这意味着应用可以仅更新页面中的某个区域。这种特性大大优化了客户端和服务器端的性能,同时明显改善了用户体验。不幸的是,客户端的应用架构几乎变得不存在了,而本来负责处理视图层的那些工程师并没有应对这种范式转变的经验。日积月累,这些因素将应用的维护工作变成了噩梦。由于模型定义变得模糊,Web 开发从此经历了一段艰难成长的时期。完美风暴:一个极其平常的故事

想象一下如下情景:你所在的团队负责维护一个商业应用的商品页面。在该页面的右侧有一个用于显示用户点评的轮播组件,用该组件可以翻页。当用户点击翻页按钮时,客户端会改变 URI 并向服务器发起请求以重新获取整个商品页面。这种低效的做法会让身为工程师的你感到非常苦恼。你认为没有必要刷新整个页面并调用一个重新渲染页面的数据请求,真正需要获取的只是下一页评论的 HTML 内容。好在你一直在跟踪行业内最新的技术发展,准备尝试使用最近学习的 Ajax 来解决这个问题。你收集了一些关于 Ajax 的概念证明,并向上司推荐了这项技术。这时候的你看起来就像巫师一样。像其他技术一样,这项技术最终会正式投入到生产环境中。

你对目前的成果感到非常满意,直到后来了解到一种新的数据交换格式。这种称为 JSON 的格式受到了 JavaScript 的非官方代言人 Douglas Crockford(http://www.crockford.com/)的极力推荐。你马上就觉得目前的实现不够完美了。第二天,你使用一种称为微模板。(micro-templating,http://ejohn.org/blog/javascript-micro-templating/)的技术编写了一份新的概念证明,并再次向上司推荐。这项技术同样受到了好评并再次投入到生产环境中。

此时普通的工程师已经将你奉为神明。这时候,代码在审查阶段被发现有 bug。上司找到你并让你修复 bug,因为这段逻辑是你实现的。你审查了代码,并向上司宣称 bug 在服务器端的渲染中。然后你需要对使用两套渲染方案的原因进行一番解释。在解释完为什么 Java 不能在浏览器中运行后,你还得向上司保证这种实现是值得的,因为这样可以大大提升用户体验。这个问题像烫手的山芋那样被传来传去,直到最后才得以解决。

尽管违背了 DRY(don't repeat yourself,不要重复你自己)原则,但你依然被誉为专家。你的实现模式逐渐被大家学习、模仿,进而充斥着整个代码库。但随着这种模式的渗透,意料之外的事情发生了。bug 的数量开始不断上升,开发人员开始害怕因修改代码而造成的回归问题。目前欠下的技术债甚至比国家的财政赤字还要严重。工程经理和开发人员开始互相推卸责任。应用变得非常脆弱,公司也因此难以应对市场的快速变化。你感到一种强烈的罪恶感。幸好,你发现了一种叫作单页面应用的新模式……客户端架构的救赎

近段时间,你阅读了一些文章,内容主要是人们对于前端架构的缺失而感到沮丧。这些人通常会将责任归咎于 jQuery,尽管这个库本来只是对 DOM 操作的封装(façade)。好在业界有人遇到了和你一样的困境,并且没有在其他不明真相的人的评论中停止自己的脚步。其中一个人就是 Backbone(http://backbonejs.org/)框架的作者 Jeremy Ashkenas(https://github.com/jashkenas)。

你开始了解 Backbone,阅读相关文章,并且深感兴趣。Backbone 将应用逻辑从数据检索中抽离出来,并将界面代码整合为单一语言和运行时,因此可以有效减少服务器端的压力。“找到了!”你在心中欢欣鼓舞地喊道。这个框架将解决我们遇到的所有问题。你又提出了一份新的概念证明,并开始实施。在我们访问时发生了什么

你很快就被称为救世主。这种新的 SPA 模式在公司范围内被广泛接受。bug 的数量开始减少,工程师又重拾了信心。交付代码时的恐惧感几乎已经消失。这个时候,负责产品的同事找到你,并告知你自从实现 SPA 模式之后,网站的访问量下降了。你得想办法处理 # 号片段带来的问题了。经过一番详尽的研究后,你确定问题出在搜索引擎没有考虑 URI 中的 window.location.hash 部分,而 Backbone.Router 用这部分来创建可跳转、可收藏书签、可分享的页面视图。因此,当搜索引擎爬取这个应用时,没有任何可以收录的内容。现在你面临的形势更加严峻了,因为这个问题会对商品销量产生直接影响。因此,你再次开启了调研与开发的循环。结果你发现有两种方案可供选择:第一种方案是运转新的服务器,模拟 DOM 操作以运行客户端应用,并将搜索引擎重定向到这些新服务器上;第二种方案是付费让其他公司为你提供解决方案。除了 SPA 实现给公司带来的损失外,这两种方案都需要支付额外成本。同构JavaScript:一个美好的新世界

上述这个故事综合了我的个人经历以及我从其他工程师那里目睹或听说的故事。如果你也曾为某个 Web 应用付出很多时间,我相信你也会有类似的经历和感受。故事当中的某些问题已经成为了历史,但部分问题依然存在。此外还有一些问题没有明说,例如页面加载速度有待优化以及缺少感知渲染。如果将路由的响应与渲染的生命周期合并为一个通用的代码库,并同时支持在客户端和服务器端运行,应该就可以解决上述这些问题以及其他潜在问题。这就是同构 JavaScript 的意义所在。同构 JavaScript 应用是整合两种架构,以创建易于维护的、更好的用户体验。未来的路

本书的主要目的是提供实现同构 JavaScript 所需的基础知识,帮助你理解业界现有的同构 JavaScript 解决方案。本书旨在提供足够多的信息,让你在实际中判断同构 JavaScript 是否为可行的解决方案,同时介绍业内最先进的解决方案,避免你重复造轮子。

第一部分是对这个主题的介绍。首先,详尽地介绍现有的几种 Web 应用架构,内容涵盖同构 JavaScript 的基本原理和用例,如 SEO 支持和提升页面的感知加载速度。然后,概述不同种类的同构 JavaScript 应用,如实时应用与类似 SPA 模式的应用。此外,还介绍了同构应用方案的组成部分,其中包括提供环境 shim 和抽象的实现,以及真正与环境无关的实现。该部分将为第二部分奠定代码基础。

第二部分将主题分解为关键概念,这些概念在大部分同构 JavaScript 解决方案中被普遍使用。每种概念都无须依赖现有的库[如 React(https://facebook.github.io/react/)、Backbone(https://facebook.github.io/react/)或 Ember(https://facebook.github.io/react/)]即可实现。这样做是为了避免将概念和某种特定的解决方案混淆。

第三部分将会介绍业内的专家是如何在他们的解决方案中作出权衡的。排版约定

本书使用了下列排版约定。● 黑体。表示新术语或重点内容。● 等宽字体(constant width)表示程序片段,以及正文中出现的变量、函数名、数据库、数据类型、环境变量、语句和关键字等。● 加粗等宽字体(constant width bold。)表示应该由用户输入的命令或其他文本。● 等宽斜体(constant width italic。)表示应该由用户输入的值或根据上下文确定的值替换的文本。 该图标表示提示或建议。

 该图标表示一般注记。 该图标表示警告或警示。代码示例

补充材料(代码示例、练习等)可以从 https://github.com/isomorphic-javascript-book 下载。

本书是要帮你完成工作的。一般来说,如果本书提供了示例代码,你可以把它用在你的程序或文档中。除非你使用了很大一部分代码,否则无须联系我们获得许可。比如,用本书的几个代码片段写一个程序就无须获得许可,销售或分发 O'Reilly 图书的示例光盘则需要获得许可;引用本书中的示例代码回答问题无须获得许可,将书中大量的代码放到你的产品文档中则需要获得许可。

我们很希望但并不强制要求你在引用本书内容时加上引用说明。引用说明一般包括书名、作者、出版社和 ISBN。比如:“Building Isomorphic JavaScript Apps。 by Jason Strimpel and Maxime Najim (O'Reilly). Copyright 2016 Jason Strimpel and Maxime Najim, 978-1-491-93293-3”。

如果你觉得自己对示例代码的用法超出了上述许可的范围,欢迎你通过 permissions@oreilly.com 与我们联系。联系我们

请把对本书的评价和问题发给出版社。美国:

  O'Reilly Media, Inc.

  1005 Gravenstein Highway North

  Sebastopol, CA 95472

中国:

  北京市西城区西直门南大街 2 号成铭大厦 C 座 807 室(100035)

  奥莱利技术咨询(北京)有限公司致谢Jason Strimpel

首先,我要感谢妻子 Lasca 的耐心与支持。我每天都被你的智慧、幽默、慈悲和爱所包围。感谢你选择了和我一起生活,这是我莫大的荣幸。是你让我成为了更加优秀的人,感谢你对我的爱。

其次,我想感谢与我合著本书的同事 Maxime。没有你的激情、知识、想法和专业知识,我的努力将大打折扣。你对于软件架构的洞察力每天都能给予我灵感。非常感谢你。

感谢我的编辑 Allyson。你提出的观点、疑问和修改意见让我的写作增色不少。感谢你。

最后,我要感谢第三部分中所有内容的贡献者,感谢你们在百忙之中抽空和读者分享你们的故事。这一部分展示了同构 JavaScript 的深度以及解决方案的多样性。你们用独特的解决方案证明了每一位工程师都是富有创造力的。感谢你们。Maxime Najim

首先要感谢我的家人——我的妻子 Nicole,以及我的孩子 Tatiana 和 Alexandra,感谢他们在本书的编写和出版过程中给予我的支持与鼓励。

我也永远感激 Jason 邀请我和他合著本书,能与你合作让我感到非常荣幸。这是一个千载难逢的机会,是你的智慧、知识和努力把这个机会变成了现实。我对你感激不尽。同样,非常感谢我们的编辑 Allyson 在整个过程中提供了宝贵的支持和建议。

最后,我要特别感谢第三部分内容的贡献者在百忙中抽空与我们分享他们的故事和经历。非常感谢你们!第一部分简介与关键概念“黄金时代”一词最早源自早期的希腊和罗马诗人,而现在就成为了技术革新时段的代名词。在 20 世纪广播电视的黄金时代,作家和艺术家将他们的技能运用于新的媒介中,创造出了各种新鲜和引人注目的内容。或许我们现在就处于 JavaScript 的黄金时代,尽管这需要时间证明。但毫无疑问,JavaScript 已经为在浏览器中运行类似于桌面程序的应用这一新时代铺好了道路。

在过去的十年中,Web 已经演进为一个构建丰富、高度交互应用的平台。浏览器不再仅仅是一个文档渲染工具,Web 也不再仅仅是将各种文档链接到一起。网站。已经发展为 Web 应用。。这意味着越来越多的 Web 应用逻辑将会在浏览器端,而非服务器端运行。然而,在过去的十年中,用户的期望也在不断提高,首屏加载速度显得越发重要。Radware 的一份报告(http://www.slideshare.net/Radware/2015-spring-state-of-the-union-ecommerce-page-speed-web-performance-infographic)显示,1999 年,一般用户愿意等待的页面加载时间为 8 秒。到 2010 年,57% 的在线购物者称,如果一个页面在 3 秒之内没有显示任何内容,那么他们就会将它关闭。调查结果正好反映出了 JavaScript 黄金时代的问题所在:客户端 JavaScript 在丰富页面内容和增强交互性的同时,也延长了页面加载时间,这使得用户在初次加载时的体验非常糟糕。页面加载时间最终会影响公司的效益。amazon.com 和 walmart.com 的报告都显示:页面加载时间每缩短 100 毫秒,他们的收入就会获得高达 1% 的增长(http://www.globaldots.com/how-website-speed-affects-conversion-rates/)。

我们将在本书的第一部分中介绍同构 JavaScript 的概念,以及同构渲染如何大幅提升用户体验。我们还将以图谱的形式探讨同构 JavaScript,简述几种不同类型的同构代码。最后,我们将目光放远,看看同构 JavaScript 如何基于服务器端渲染技术,创建出复杂、实时更新、支持协作的实时应用。第1章为什么需要同构 JavaScriptJason Strimpel、Maxime Najim

2010 年,Twitter 对其网站进行了一次重构,并发布了新的版本。这个称为“#NewTwitter”的新版本将 UI 渲染和业务逻辑放在了 JavaScript 中,并在用户的浏览器中运行。这种架构在当时是开创性的。然而,不到两年的时间,Twitter 再次进行了重构,将渲染功能移回了服务器端。Twitter 的这次改版将页面的初始渲染时间缩短到了原来的五分之一(https://blog.twitter.com/2012/improving-performance-on-twittercom)。Twitter 的做法在 JavaScript 社区中引起了轰动。开发者和其他许多人很快意识到,客户端渲染对性能有着非常明显的影响。 构建客户端 Web 应用的最大劣势在于,首次加载需要付出高昂的代价下载一个 JavaScript 大文件。互联网中的主要传输协议是 TCP(Transmission Control Protocol,传输控制协议),该协议定义了一种被称为慢启动。(slow start)的拥塞控制机制,这意味着数据是以逐渐增加数据块的方式进行发送的。Ilya Grigorik 在《Web 性能权威指南》1 一书中解释了 TCP 协议如何经过“客户端与服务器端之间的 4 次往返……以及几百毫秒的延迟,才能达到 64KB 的吞吐量”。显然,发送给用户的前几千字节的数据对良好的用户体验和页面响应性至关重要。

1此书已由人民邮电出版社出版,http://www.ituring.com.cn/book/1194。——编者注

客户端 JavaScript 应用在初始化时只包含一个 ...

2.1.2 共享视图逻辑

模板的 helper 是对象,如数字、字符串或散列对象,通常比较容易共享。对于日期这样的格式化数据的共享,许多格式化库都同时支持在服务器端和客户端运行,比如 Moment.js 可以同时在服务器端和客户端进行日期的解析、验证、操作与显示。另外,URL 的格式化需要在路径前面添加主机名和端口,而在客户端中只需要简单地使用相对 URL 即可。2.2 共享路由

大部分现代的 SPA 框架都支持路由的概念,路由负责在用户跳转页面时跟踪用户的状态。在 SPA 中,路由是控制跳转事件、改变状态和页面视图,以及更新浏览器跳转历史的主要机制。在同构应用中,我们同样需要一套路由配置(即将 URI 的模式映射到路由处理器中),而且这套配置能够在服务器端和客户端之间方便地进行共享。共享路由的难点在于路由处理器自身,因其经常需要访问与环境相关的 API 来获取 URL 信息、HTTP 头部和 cookie 等。在服务器端,这些信息可以通过请求对象的 API 取得,而在客户端则需要通过浏览器的 API 取得。2.3 共享模型

模型通常被称为业务对象、域对象或者实体。通过移除状态存储并从 DOM 恢复,模型为数据建立了一种抽象。在最简单的实现中,同构应用可以使用服务器端返回首屏响应之前一模一样的状态,对客户端应用进行初始化。在同构 JavaScript 图谱的一个极端中,服务器端和客户端共享状态与模型的定义规范包括双向同步(第 4 章将对这种实现进行更为详细的探讨)。2.4 小结

应用在同构 JavaScript 图谱中可以处于不同的位置。客户端和服务器端共用的代码量不尽相同,从共享模板到共享应用的整个视图层,再到共享应用的大部分逻辑。随着在同构 JavaScript 图谱中的位置不同,应用可能需要建立更多的抽象。在下一章中,我们将会讨论不同类别的同构 JavaScript,并且更深入地分析这些抽象。第3章同构 JavaScript 分类Maxime Najim

同构 JavaScript。(isomorphic JavaScript)这一术语公认的出处是 Charlie Robbins 在 2011 年发表的博文“Scaling Isomorphic Javascript Code”(https://blog.nodejitsu.com/scaling-isomorphic-javascript-code/)。随后,这个术语在 Spike Brehm 于 2013 年发表的博文“Isomorphic JavaScript: The Future of Web Apps”(http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/)及随后的一些文章和会议演讲中多次出现,并因此开始流行起来。然而,在 JavaScript 社区(https://www.oreilly.com/ideas/renaming-isomorphic-javascript),关于同构的用词“isomorphic”曾存在一些争论。Michael Jackson(React.js 讲师、react-router 项目作者之一)认为,应该将“同构 JavaScript”称为“universal JavaScript”(https://medium.com/@mjackson/universal-javascript-4761051b7ae9#.h655sp39b)。Jackson 认为 universal 这个词可以突出“JavaScript 代码不仅可以在服务器端和客户端上运行,还可以在原生设备和嵌入式架构上运行”的特点。

而另一方面,isomorphism 是一个数学术语:对于两个数学对象来说,如果我们简单地忽略它们的个体差异,则当它们具有相似的属性和操作时,就是同构的。当我们将这个概念应用到图论中时,一切就变得很好理解了。图 3-1 中的这两个图就是很好的例子。

图 3-1:同构的图。

尽管这两个图看起来差别很大,但它们却是同构的。这两个图具有相同的结点数,而且每个结点拥有相同的边数。但它们是同构图的真正原因是,左图中的每个结点都能映射到右图中对应的结点,并且同时保留某些属性。比如,结点 A 可以映射到结点 1,并且右图中结点 1 的相邻关系和结点 A 是一致的。事实上,左图中的每个结点映射到右图后都保留了原有的相邻关系。

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载