Hash 模式?history 模式?

分享

前言

这次的 why what or how 主题:单页应用的 router 模式,HashHistory是什么?

router 作为单页应用中重要的组成,有两种模式供我们选择,那么这两种模式的区别如何,分别的优势又在哪里?

想要深入对比两种模式的区别,我们首先要知道什么是路由?

什么是路由?

路由定义如下:路由为 URL 的路径,也就是 URL 中的 path 部分,一个路由对应一个具体的资源,可能是文件,可能是数据。

在单页应用出现之前,路由已在服务端被广泛使用,那么前端何时开始有了路由?

伴随着浏览器性能的提升、网速加快、Ajax 技术的成熟,部分前端程序员发现,使用 JavaScript 在前端维护一个模板,然后在用 Ajax 去服务端获取数据,就能够将模板和数据拼凑成一个动态的页面呈现给用户。随着这项技术的日渐成熟,一个问题渐渐的显示出来:如果 JavaScript 端维护了几个不同模板,用以在不同的状态下的呈现,该如何去维护这个状态?

路由!服务器就是用路由来区分不同资源,只需要把路由的概念引入前端开发中,用路由来标志这些状态!

那么如何引入?或者说如何实现?

模拟

路由的样子:一个形如 <path>?<query> 的字符串。

那么该如何存储这个路由呢?页面生成之初,我们所拥有的只有 URL。如果一开始就需要确定页面的状态,那就只能用这个 URL

首先分析下 URL 的组成:

<protocol>://<token>@<host>:<port>/<path>?<query>#<hash>

除去服务器需要使用的,能使用的仅剩下了 hash

虽然在浏览器中 hash 为一个锚点值,但却拥有以下特性:

  1. hash 值改变会记录历史记录。
  2. hash 值未匹配到元素时,页面并不会发生滚动。
  3. hash 值为一个任意的字符串。
  4. hash 的改变并会不让浏览器刷新页面。

那么现在再来看一个前端路由所需要的特性

  1. 需要记录历史。
  2. 一个类似 /a/b/c 的字符串。
  3. 路由改变不需要浏览器重新获取资源(也就是不刷新页面)。

这两者似乎是生来就该呆在一起,简直是完美契合。

有了思路,那我们使用 hash 来模拟一个简单的前端路由,如下:

http://test.com/app#/page/123

# 号前为需要请求服务器路由,# 后为前端路由。

看起来一切都挺完美?服务器浏览器各自处理各自的部分,JavaScript 中包含了所有的页面模板,以及路由映射表。但这就是最终的版本了吗?

是的!至少在 pushStatereplaceState 出现之前是。那么这两个 Api 效果是如何?为何会有这两个 Api

history Api

先来看看官方定义:

API 作用
pushStatus 向浏览器的历史记录中添加一条历史,同时将地址栏改为相应的地址,但却并不会导致浏览器刷新。
replaceState 直接替换地址栏的链接,不会产生新的历史,同样不会导致浏览器刷新。

需要注意的是,这两 API 仅能改变 URL<path>?<query> 部分,并不能改变其余部分。

看起来挺符合前端路由的概念的,甚至可以说为了配合前端路由诞生了这两个 API。但是问题真的解决了吗?

一切问题隐藏在用户主动刷新上。虽然说这两 API 屏蔽了浏览器的刷新,但用户主动触发的刷新却不能控制,思考以下场景:

  1. 用户打开 http://test.com/app
  2. 用户点击按钮导航到 http://test.com/app/page/123 由于是 API 控制,不会导致浏览器发出对应地址的请求。
  3. 用户主动刷新了页面。
  4. 浏览器发出 http://test.com/app/page/123 的请求,但服务器并没有对应的资源,导致 404

那么如何解决?由于问题发生在服务器,那只能在服务器上解决,nginx 重定向,或是让 http://test.com/app/page/123 返回和 http://test.com/app 一样的结果,那么其他页面怎么办,单页应用可不止有两个页面!写正则过滤请求!

优缺点

在说明优缺点时,把使用 hash 实现前端路由称为 hash 模式,把使用 history Api 称为 history 模式。

hash 模式

使用 hash 模拟路由,URL 格式如下

<protocol>://<token>@<host>:<port>/<path>?<query>#<path>?<query>

优点

  1. 职责明确,各部分处理各部分的事,互不干扰。
  2. 服务器不需要支持实现
  3. JavaScript 获取简单

缺点

  1. 带有 #/ 不精简,hash 部分的分享可能有问题。

history 模式

直接使用 URL<path>?<query>,格式与 URL 一致

<protocol>://<token>@<host>:<port>/<path>?<query>#<hash>

优点

  1. URL 简单,分享容易。
  2. hash 可以匹配 ID

缺点

  1. 服务器需要支持。
  2. 职责不明确,项目废弃后还需要去服务将相应的过滤去掉,会埋下一些隐藏 bug
  3. 如果有二级目录存在,请求过滤会比较复杂。

小结

个人喜欢使用 hash 模式,原因如下

  1. 开发简单。
  2. 现在分享基本上使用二维码,不用直接分享链接。
  3. 不会污染服务器。
  4. 锚点?什么是锚点?我不认识

最后,惯例提几个问题

  1. 什么是路由?
  2. 前端路由存在意义?
  3. hash 模式与 history 模式的区别?

最后的最后

该系列所有问题由 minimo 提出,爱你哟~~~

阅读更多

JavaScript 对象 & 原型

前言 这次的 why what or how 主题:JavaScript 对象 & 原型。 此类文章在百度上一搜一大把,其实不用再写了,但是本着把这个问题解释的清清楚楚明明白白,还是开始写了。 原因如下: 1. 面试宝典类文章,弄张图片一糊弄,让人觉得自己理解了。 2. 解释类文章,告诉你一堆语法,对语法一顿解释,告诉你就是这样的,还是没说清楚。 3. 很少有文章单独解释这个点!但这个点是基础!真的很重要! 所以本篇文章想说一说对象 & 原型,但为了确保能顺利理解,请先看完 JS 变量存储?栈 & 堆?NONONO!,因为该篇文章从变量存储的角度来解释 JavaScript 对象 & 原型,请确保看完,在看这篇文章。 什么是对象? 既然要说清楚,

By Breeze

浏览器下的 Event Loop

前言 javascript 是以单线程的形式运行在宿主环境下,javascript 采用了回调的形式来解决异步任务。 为什么是单线程? javascript 的最开始的出现是为了给 web 页面增添一些动态的效果,那么就避免不了获取页面上的元素信息,如果 javascript 是以多线程的形式运行在浏览器内,如果两个线程内的 javascript 同时去获取/修改,某个页面上的元素,那么浏览器该让哪个 javascript 线程拥有获取/修改该元素的权限呢?由于元素的信息会经常性的发生变化,那么又改如何去同步各个线程内所保存的元素信息呢? 所以综合以上问题, javascript 是单线程的原因就显示意见了,单线程在执行时,对于元素信息的引用在同一时间仅可能只有一个,那么以上所有的问题都不存在了。 什么是异步任务? 任何代码在执行时,都会碰到一些需要经过大量时间运算或是等待的代码,在浏览器的环境下,常见的就是 http 任务,比如:资源的加载(图片的 onload 事件),ajax 的请求(XMLHttpRequest 的 onLoad 事件)还有页面元素的点击事件以及

By Breeze

node 下的 Event Loop

前言 通过 浏览器下的 Event Loop ,可以得知 javascript 是一门事件驱动的语言, javascript 主线程通过不断的调用事件队列中的事件来完成异步任务。那么 Node 下是否也是如此? Node 下的事件队列 在 Node 官网有这样一篇文章:The Node.js Event Loop, Timers, and process.nextTick() 。 该文章主要讲述了 Node 中是如何处理以及实现 Node 下的 Event Loop。 主要包含以下内容: 事件队列 不同于浏览器,Node 下的有 6 个事件处理阶段,其执行顺序和队列名称如下: ┌───────────────────────────┐ ┌─>│ timers │ │ └─────────────┬─────────────┘ │ ┌─────────────┴─────────────┐ │ │ pending callbacks │ │ └─────────────┬─────────────┘ │

By Breeze

什么是 HTML 5?

前言 作为程序员,技术的落实与巩固是必要的,因此想到写个系列,名为 why what or how 每篇文章试图解释清楚一个问题。 这次的 why what or how 主题:现在几乎所有人都知道了 HTML5 ,那么 H5 到底相比于 HTML4 有什么区别呢? 升级版?标准版! HTML5 做为 HTML 标准的第 5 版,于 2014 年发布,相信关注过 HTML5 的发展史的朋友都知道该版本是 WHATWG 和 W3C 握手言和后诞生的,是 W3C 组织与浏览器厂商相互妥协的结果,其中的绝大部分规范都由 WHATWG 组织所制定,之后由 W3C 采纳并入标准中。

By Breeze