BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

Angular Universal的三种开发模式

| 作者 David Iffland 关注 4 他的粉丝 ,译者 张卫滨 关注 13 他的粉丝 发布于 2016年5月13日. 估计阅读时间: 6 分钟 | QCon上海2018 关注大数据平台技术选型、搭建、系统迁移和优化的经验。

虽然Angular是一种构建Web应用的强大方式,但是长期以来,开发人员都知道它在SEO和可访问性方面的限制。当然,Google的爬虫能够执行JavaScript,但是它并不是唯一的爬虫方案。例如,在将一个链接提交给Slack之后,它的爬虫会抓取一个预览,但是并不会执行JavaScript,所以原始的Angular HTML模板将会显示在预览之中。为了消除这种现象所产生的问题,Jeff Whelpley和Patrick Stapleton开发了Angular Universal,它允许在服务端进行渲染。

Universal JavaScript(有时会被误称为“isomorphic”)并不是Angular特有的技术。Angular Universal的工作原理是在服务端进行应用的初始化渲染,并将其发送给浏览器,用户就能马上看到了,然后才发送客户端的JavaScript。这与Angular应用的典型顺序是有所区别的,在典型的顺序中会首先发送客户端JavaScript,然后初始化UI才会在客户端渲染。

Welpley和Stapleton开发Angular Unversal已经超过一年了,在这个过程中发现了六个经常遇到的模式。在2016 ng-conf的分享中,它们主要关注了其中的三项:

  1. 事件脱节(Gap Event)
  2. 异步(Async)
  3. 依赖(Dependencies)

事件脱节是在服务端渲染所造成的副作用,在这种方式下,渲染会在JavaScript客户端脚本发送到浏览器之前执行。根据JavaScript发送和执行的速度不同,用户在与UI进行交互的时候,可能代码还没有为这些交互做好准备。这种脱节可能会导致用户交互的丢失。

针对该问题的解决方案就是记录用户的事件,并在客户端JS加载完成之后进行重放。如下的样例展现这种代码会是什么样子的:

var myEvents = [];
var myInputValue;

// 记录客户端视图myInput的所有keyup事件
function recordEvents() {
  var $myInput = document.querySelector('.myInput')
  $myInput.addEventListener('keyup', function (event) {
    myEvents.push(event);
    myInputValue = event.target.value;
  });
}

// 在服务器视图myInput上回放所有的keyup事件
function replayEvents() {
  var $myInput = document.querySelector('.myInput');
  myEvents.forEach(function (event) {
    $myInput.dispatchEvent(event);
  });
  $myInput.value = myInputValue;
  $myInput.focus();
}

//  在window加载完成之后,马上就开始记录
window.addEventListener('load', recordEvents);

Angular Universal使用一种名为preboot过程来处理这项任务,而不是要求开发人员手动地做这些事情,可以通过如下的标记启用该功能:

preboot: true

JavaScript在本质上是异步的,在服务端渲染Angular的时候,这就会产生问题。通常的解决方案是使用链(chaining)或回调,但要求开发人员重写他们的代码来解决这个问题显然不是好的可选方案。“我们不能这样做,而是必须要找到一种方式来处理这些不同的异步事件,并调整它们何时将响应发送回来”,Whelpley这样说到。

Angular Universal使用另外一个标记来解决这个问题,只需一行就可以了:

async: true

将这个标记打开之后,将会使用Angular新的Zones特性,“跟踪所有的异步调用,并且能够知道它们何时完成。”

在服务端渲染Angular代码的第三个主要的问题在于使用平台特定的依赖。例如,localStorage是浏览器的特性,在服务器端根本不存在。Whelpley和Stapleton指出,可以使用依赖注入(Dependency Injection,DI)作为解决方案。他们建议根据代码所执行的上下文,借助DI来替换实现,而不是使用平台具体的特性。

对于测试过他们功能的开发人员来说,这应该不足为奇。Whelpley指出,Angular所运行的测试和其他平台已经证明了这项技术在Angular 2的代码中将会非常普遍。“平台相关的依赖基本上已经被我们消除掉了。这个模式是我今天所讨论的最强大的模式”,Whelpley说道。

他们ng-conf分享的完整视频已经可以观看了。

查看英文原文3 Development Patterns of Angular Universal

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我
社区评论

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT