本文仅介绍个人使用vscode进行web开发从生疏到习惯使用过程中,逐步使用的插件简介。

插件安装

很简单,打开vscode左侧菜单项对应的“扩展”功能,点开后,可以搜索插件,也叫扩展。安装了某个插件后,有其使用说明,有些是可定义参数、可配置的,有些则是默认生效。

Buautify

可以美化js、json、css、sass和html,初步避免代码编写时的不规范。

Document this

可以用于自动生成JSDoc。

Dracula Official

一款下载量近10万得主题。
下载该插件后需要如下进行配置:

1
文件 -- 首选项 -- 颜色主题

ESLint

eslint,规范js/es代码,特点是api很简单,可以自由配置属性来控制适合自己项目的约束。

HTML CSS Support

在html中书写css时,自动展示当前支持的css列表。

Instant Markdown

md文件实时网页预览,功能不错,不过如果你经常写md时,用起来也不舒服,因为每当你保存md文件,它会自动启动一个web服务并预览该md文件的html版本。
其实vscode自带简单的md预览功能,在文件编辑视图右上角的“放大镜”按钮,只是不支持以网页形式预览。

Local History

使用vscode编辑文件时,很头疼的问题时无法记录之前的文件状态,该插件可以自动记录文件历史状态。保存的文件位置、保存的天数支持可自定义配置。

Path Intellisence

智能路径提示。当你想引入一个js文件、css文件时,它会帮你智能提示路径。

Terminal

terminal。

TODO Parser

帮你分析当前的“TODO”项数目,并在左下角提示。

vscode-fileheader

为文件添加固定的头信息,支持动态变动每一次的更新时间。

vscode-icons

为每种文件类型,添加友好的图标,目前已支持非常多文件类型。
下载该插件后需要如下进行配置:

1
文件 -- 首选项 -- 文件图标

End

vscode插件库包含的插件非常丰富,包括有ng2/ts/vue/react等相关的支持,有git/svn等相关的支持,可以根据关键字自行搜索,尝试使用。



money☜☜☜ wechat 『『『 reward 点击扫码打赏 ~~~ ^_^ 』』』alipay ☞☞☞ money



Chrome Devtools是目前做web开发必备的工具,网上也有各种教程、文档教大家怎么使用,资源太多就不一一列举了,下面介绍几个我自己日常除了基础常用的功能外,额外会用到的技能。

Snippets

Snippets,中文直译为片段,可以理解为代码片段,主要功能是可以保存临时的代码片段,功能位于Sources--Snippets
在Snippets面板写代码片段有三个好处:

  • 可以临时保存,自己不删不会丢
  • 代码有简单格式,换行、回车都支持
  • 可以暂存多个代码片段,很方便

平时调试代码习惯使用Console面板,简单的代码,可以在Console处编辑,但是在这边编辑有个缺点就是格式不好控制,且关闭后代码就清除了,下次想再找就没办法了,因此推荐使用Snippets功能暂存临时代码片段。

Performance

该面板大家平时可能不大用,大多在分析性能的时候会用到,其中的每个子功能会使用的话都可以很多的进行性能分析,网上教程很多,可自行查阅。

Network

捕获网络请求必备。可以对当前的请求进行非常全面的分析,包括请求头信息、请求体信息、请求方式及返回。
同时,可以模拟断网状态,可以强制不使用缓存进行请求。通过分析请求的时间、大小,可以进行性能的分析。

Application

该面板用的比较多的可能是进行本地存储的管理、查看等,目前还支持编辑cookie。

实用快捷键

  • Ctrl + F8 ,trigger 断点
  • Ctrl + P ,查找文件
  • Ctrl + Shift + F , 全局搜索
  • Ctrl + G ,定位某一行
  • Ctrl + L ,清空console
  • Ctrl + R ,强制刷新


money☜☜☜ wechat 『『『 reward 点击扫码打赏 ~~~ ^_^ 』』』alipay ☞☞☞ money



背景

  • 互联网(Internet):诞生于20世纪60年代,美苏冷战时期。
  • 万维网(WWW/Web/W3):蒂姆·伯纳斯·李(Tim Berners-Lee)在1989年12月发明了World Wide Web,即万维网(WWW)。1991年,万维网在Internet上首次露面,当时引起全球轰动。
  • 网景:1993年,美国一个浏览器“Mosaic”燃爆Internet。1994年4月,该浏览器开发团队的核心人物马克·安德森和Silicon Graphic公司的创始人吉姆·克拉克成立“MOSAIC Communication Corp”。但是由于他们此时没有浏览器版权及技术,只能重写浏览器。1994年10月13日,该公司开发的浏览器Mosaic Netscape 0.9发布,虽然仍是beta版本,该浏览器获得重大成功,成为当时最热门的浏览器。1994年11月14日,为了避免和NCSA的商标拥有权问题,更名为网景通信公司(Netscape Communications Corporation)。同年12月15日,网景浏览器1.0正式版发布,软件改名为网景导航者(Netscape Navigator),并且迅速占领市场。
  • 微软:在网景浏览器疯狂吸金的时候,引起了微软的注意,它收购了Mosaic的授权,以此为基础研发出Internet Explorer,江湖人称IE。至此之后,网景与微软开始了著名的“浏览器大战”。
  • Sun:创建于1982年,主要做工作站(一种高端的通用微型计算机)和服务器。1986年在美国成功上市,1993年进入财富500强。1995年5月,Sun公司将Oak语言改名为Java,并且正式推出市场,Sun公司大肆宣传,许诺这种语言可以”一次编写,到处运行”(Write Once, Run Anywhere)。
  • 诞生背景:1994年,也就是0.9版本发布时,该浏览器只能用来浏览,不具备与访问者互动的能力。此时网景公司也意识到自己急需一种网页脚本语言,使得浏览器可以与网页互动。 网页脚本语言到底是什么语言?网景公司当时有两个选择:一个是采用现有的语言,比如Perl、Python、Tcl、Scheme等等,允许它们直接嵌入网页;另一个是发明一种全新的语言。这两个选择各有利弊。第一个选择,有利于充分利用现有代码和程序员资源,推广起来比较容易;第二个选择,有利于开发出完全适用的语言,实现起来比较容易。到底采用哪一个选择,网景公司内部争执不下,管理层一时难以下定决心。时间来到了1995年,Java的推出让网景公司动了心,于是决定与Sun公司结盟,想让浏览器支持Java以applet(小程序)的形式直接在浏览器中运行。

诞生

1995年4月,网景公司聘用了34岁的程序员,Brendan Eich(布兰登·艾奇)。Brendan Eich的主要方向和兴趣是函数式编程,网景公司招聘他的目的,是研究将Scheme语言作为网页脚本语言的可能性。Brendan Eich本人也是这样想的,以为进入新公司后,会主要与Scheme语言打交道。仅仅一个月之后,1995年5月,网景公司做出决策,未来的网页脚本语言必须”看上去与Java足够相似,但是比Java简单,使得非专业的网页作者也能很快上手”。这个决策实际上将Perl、Python、Tcl、Scheme等非面向对象编程的语言都排除在外了。Brendan Eich被指定为这种”简化版Java语言”的设计师。但是,他对Java一点兴趣也没有。为了应付公司安排的任务,他只用10天时间就把Javascript设计出来了。由于设计时间太短,语言的一些细节考虑得不够严谨,导致后来很长一段时间,Javascript写出来的程序混乱不堪。
多年以后,Brendan Eich还是看不起Java。
他说:”Java(对Javascript)的影响,主要是把数据分成基本类型(primitive)和对象类型(object)两种,比如字符串和字符串对象,以及引入了Y2K问题。这真是不幸啊。”
何为Y2K问题?
根据设想,Date.getYear()返回的应该是年份的最后两位:

1
2
var date1 = new Date(1999,0,1);
  var year1 = date1.getYear(); // 99

但是实际上,对于2000年,它返回的是100!

1
2
var date2 = new Date(2000,0,1);
  var year2 = date2.getYear(); // 100

这个问题完全来源于Java,因为Javascript的日期类直接采用了java.util.Date函数库。Brendan Eich显然很不满意这个结果,这导致后来不得不添加了一个返回四位数年份的Date.getFullYear()函数。如果不是公司的决策,Brendan Eich绝不可能把Java作为Javascript设计的原型。作为设计者,他一点也不喜欢自己的这个作品:

1
"与其说我爱Javascript,不如说我恨它。它是C语言和Self语言一夜情的产物。十八世纪英国文学家约翰逊博士说得好:'它的优秀之处并非原创,它的原创之处并不优秀。'(the part that is good is not original, and the part that is original is not good.)"

设计思路

  • 借鉴C语言的基本语法
  • 借鉴Java语言的数据类型和内存管理
  • 借鉴Scheme语言,将函数提升到”第一等公民”(first class)的地位
  • 借鉴Self语言,使用基于原型(prototype)的继承机制

所以,Javascript语言实际上是两种语言风格的混合产物—-(简化的)函数式编程+(简化的)面向对象编程。这是由Brendan Eich(函数式编程)与网景公司(面向对象编程)共同决定的。

标准化

因为 JavaScript 1.0 的成功,Netscape 在 Netscape Navigator 3.0 中发布了 1.1 版。此时,微软进军浏览器市场,发布了 IE 3.0 并搭载了一个 JavaScript 的克隆版,叫做 JScript(这样命名是为了避免与 Netscape 潜在的许可纠纷)。微软步入 Web 浏览器领域的这重要一步虽然令其声名狼藉,但也成为 JavaScript 语言发展过程中的重要一步。
在微软进入后,有 3 种不同的 JavaScript 版本同时存在:Netscape Navigator 3.0 中的 JavaScript、IE 中的 JScript 以及 CEnvi 中的 ScriptEase。与 C 和其他编程语言不同的是,JavaScript 并没有一个标准来统一其语法或特性,而这 3 种不同的版本恰恰突出了这个问题。随着业界担心的增加,这个语言的标准化显然已经势在必行。
1997 年,JavaScript 1.1 作为一个草案提交给欧洲计算机制造商协会(ECMA)。第 39 技术委员会(TC39)被委派来“标准化一个通用、跨平台、中立于厂商的脚本语言的语法和语义”(http://www.ecmainternational.org/memento/TC39.htm)。由来自 Netscape、Sun、微软、Borland 和其他一些对脚本编程感兴趣的公司的程序员组成的 TC39 锤炼出了 ECMA-262,该标准定义了名为 ECMAScript 的全新脚本语言。
在接下来的几年里,国际标准化组织及国际电工委员会(ISO/IEC)也采纳 ECMAScript 作为标准(ISO/IEC-16262)。从此,Web 浏览器就开始努力(虽然有着不同的程度的成功和失败)将 ECMAScript 作为 JavaScript 实现的基础。

JavaScript实现

尽管 ECMAScript 是一个重要的标准,但它并不是 JavaScript 唯一的部分,当然,也不是唯一被标准化的部分。实际上,一个完整的 JavaScript 实现是由以下 3 个不同部分组成的:

  • 核心部分(ECMAScript)
  • 文档对象模型(DOM)
  • 浏览器对象模型(BOM)

ECMAScript及版本历史

ECMA-262 标准(第 2 段)的描述表示:

1
“ECMAScript 可以为不同种类的宿主环境提供核心的脚本编程能力,因此核心的脚本语言是与任何特定的宿主环境分开进行规定的... ...”

简单来说就是,ECMAScript 并不与任何具体浏览器相绑定。其主要描述了以下内容:

  • 语法
  • 类型
  • 语句
  • 关键字
  • 保留字
  • 运算符
  • 对象
    ECMAScript 分成几个不同的版本,它是在一个叫做 ECMA-262 的标准中定义的,其主要版本包括以下:
  • ECMA-262第一版,1997年06月,在本质上与 Netscape 的 JavaScript 1.1 是一样,只是把所有与浏览器相关的代码删除了,此外还有一些小的调整。首先,ECMA-262 要求对 Unicode 标准的支持(以便支持多语言)。第二,它要求对象是平台无关的(Netscape 的 JavaScript 1.1 事实上有不同的对象实现,例如 Date 对象,是依赖于平台)。这是 JavaScript 1.1 和 1.2 为什么不符合 ECMA-262 规范第一版的主要原因。
  • ECMA-262第二版,1998年06月,大部分更新本质上是编辑性的。这次标准的更新是为了与 ISO/IEC-16262 的严格一致,也并没有特别添加、更改和删除内容。ECMAScript 一般不会遵守第二版。
  • ECMA-262第三版,1999年12月,是该标准第一次真正的更新。它提供了对字符串处理、错误定义和数值输出的更新。同时,它还增加了正则表达式、新的控制语句、try…catch 异常处理的支持,以及一些为使标准国际化而做的小改动。一般来说,它标志着 ECMAScript 成为一种真正的编程语言。
  • ECMA-262第四版,预计2008年8月发布,由于关于语言的复杂性出现分歧,发布前被放弃,其中的部分精华成为了第5版本及Harmony(next版本)的基础。
  • ECMA-262第五版,2009年12月,新增“严格模式(strict mode)”,提供更彻底的错误检查。澄清了许多第3版本的模糊规范,增加了部分新功能,如getters及setters,支持JSON以及在对象属性上更完整的反射。
  • ECMA-262第5.1版,2011年06月,成为ISO国际标准(ISO/IEC16262:2011)。到2012年底,所有主流浏览器都支持该版本的所有功能。
  • ECMA-262第六版,2015年06月发布,并更名为“ECMAScript 2015”,简称ES6。这是因为TC39委员会计划,以后每年发布一个ECMAScirpt的版本,下一个版本在2016年发布,称为“ECMAScript 2016”。ES6增添了许多必要的特性,新功能包括:模块和类以及一些实用特性,例如Maps、Sets、Promises、生成器(Generators)等。
  • ES2016、ES2017、ES.Next…

DOM

Document Object Model,文档对象模型。是W3C组织推荐的处理可扩展标志语言的标准编程接口。在网页上,组织页面(或文档)的对象被组织在一个树形结构中,用来表示文档中对象的标准模型就称为DOM。在 1998 年,W3C 发布了第一级的 DOM 规范。这个规范允许访问和操作 HTML 页面中的每一个单独的元素。所有的浏览器都执行了这个标准,因此,DOM 并不存在兼容性问题。DOM 可被 JavaScript 用来读取、改变 HTML、XHTML 以及 XML 文档。DOM 被分为不同的部分(核心、XML及HTML)和级别(DOM Level 1/2/3)。

  • 核心 DOM:针对任何结构化文档的标准模型,例如遍历DOM树、添加新节点、删除节点、修改节点
  • XML DOM:针对 XML 文档的标准模型,其主要针对XML节点对象(Node)
  • HTML DOM: 针对 HTML 文档的标准模型,其主要针对HTML标签对象,如Body、Form、Image
  • 1级DOM在1998年10月份成为W3C的提议,由DOM核心与DOM HTML两个模块组成。DOM核心能映射以XML为基础的文档结构,允许获取和操作文档的任意部分。DOM HTML通过添加HTML专用的对象与函数对DOM核心进行了扩展。
  • 2级DOM通过对象接口增加了对鼠标和用户界面事件(DHTML长期支持鼠标与用户界面事件)、范围、遍历(重复执行DOM文档)和层叠样式表(CSS)的支持。同时也对DOM 1的核心进行了扩展,从而可支持XML命名空间。
  • 3级DOM通过引入统一方式载入和保存文档和文档验证方法对DOM进行进一步扩展,DOM3包含一个名为“DOM载入与保存”的新模块,DOM核心扩展后可支持XML1.0的所有内容,包括XML Infoset、 XPath、和XML Base。

BOM

Browser Object Model,浏览器对象模型。浏览器对象模型提供了独立于内容的、可以与浏览器窗口进行互动的对象结构,BOM由多个对象组成,其中代表浏览器窗口的Window对象是BOM的顶层对象,其他对象都是该对象的子对象。
1999年,Internet Explorer对BOM进行扩展以包括ActiveX对象类,可以通过JavaScript来实现ActiveX对象,为日后Ajax的出现埋下伏笔。

Ajax

Asynchronous Javascript And XML,异步JavaScript和XML。1999年W3C发布第四代HTML标准,同年微软推出用于异步数据传输的ActiveX,随即各大浏览器厂商模仿实现了XMLHttpRequest,这标志着Ajax的诞生,但是Ajax这个词是在六年后(2005年)问世的,特别是在谷歌使用Ajax技术打造了Gmail和谷歌地图之后,Ajax获得了巨大的关注。
在2005年之前,也即Ajax问世之前,Web应用可以称之为Web 1.0时代。此时的Web应用甚至不能称为应用,顶多算Web网页。
Web 1.0时代的网页大致有以下三个特点:

  • 所有的网页都基于HTML页面,因为没有任何手段可以控制局部内容的显示和隐藏,因此任何局部的变化哪怕只多出一个标点符号,都只能重新下载一个新的页面
  • 计算任务只能在服务端实现。由于网速限制,与服务器通信的过程是非常缓慢的,并且此过程是同步阻塞的,于是会出现这样的场景:用户提交一个表单,然后整个页面消失,浏览器呈现白屏,经过漫长的等待,浏览器渲染出一个和之前一模一样的页面,只不过输入框旁边多了一排红色小字:用户名错误
  • 所有页面都是静态的,这意味着一个电商网站有一千种商品,哪怕页面布局一模一样,也必须写一千个单独的页面
    Ajax是Web网页迈向Web应用的关键技术,它标识着Web2.0时代的到来,2006年,XMLHttpRequest被W3C正式纳入标准。
    由于Web 1.0时代,网页的各种受限,导致早起的网页应用由后端主导,前端顶多能做的也就是操作DOM。
    起初制约Web开发从后到前的因素很简单,就是前端很多事干不了或干不好,当时的浏览器性能弱,标准化程度低。特别是占据大量市场份额的IE,不仅ugly,并且buggy。
    这时候前端开发者开始尝试推出一些框架来做出改变。

Prototype

Prototype框架是由Sam Stephenson在2005年2月推出的,它是最受欢迎的Ajax框架之一。Prototype框架以面向对象的方式封装js代码,引入了前端类的概念,大大简化了客户端的开发工作。

JQuery

2005年8月,John Resig提议改进Prototype的“Behaviour”库,他的提议主要包括三点:

  • 为元素注册一个事件
  • 为不同的元素注册不同的事件
  • 为不断变化的元素注册不同的事件
    他的这三点提议,也是jQuery语法设计的最初雏形。2006年1月14日,John Resig正式发布了jQuery,jQuery主要用于操作DOM,其优雅的语法、符合直觉的事件驱动型的编程思维使其极易上手,因此很快风靡全球,大量基于jQuery的插件构成了一个庞大的生态系统。
    JQuery整体架构如下图:

V8

由于IE为主导的浏览器性能实在太差,google于2008年推出V8引擎。V8引擎带来的性能提升最要在下面三个方面:

  • 快速属性访问
  • 动态生成机器码
  • 高效的垃圾回收
    现代浏览器的崛起终结了微软的垄断时代,前端的计算能力一下子变得过剩了。标准组织也非常配合的在2009年发布了第五代JavaScript,前端的装备得到了整体性的提高,前端界如同改革开放走进了一个令人目不暇接的新时代。
    2009年AngularJS诞生,随后被谷歌收购。2010年backbone.js诞生。2011年React和Ember诞生。2014年Vue.js诞生…,前后端分离可谓大势所趋。
    前后端分离,一般指后端只负责数据,前端负责其余工作。前后端沟通的数据通过接口规范定义。早期Web应用使用Web Service技术实现,现代Web应用或者说Web2.0之后的应用,一般通过RESTful架构实现。

Knockout

knockout是一个轻量级的UI类库,通过MVVM模式使JavaScript前端UI简单化。knockout有四大重要概念:

  • 声明式绑定:使用简明移读的语法很容易地将模型(model)数据关联到dom元素上。
  • UI界面自动刷新:当宁的模型状态(model state)改变时,您的UI将自动更新
  • 依赖跟踪:为转变和联合数据,在你的模型数据之间隐式建立关系
  • 模板:为你的模型数据快速编写复杂的可嵌套的UI

Backbone

backbone将数据呈现为模型, 你可以创建模型、对模型进行验证和销毁,甚至将它保存到服务器。 当UI的变化引起模型属性改变时,模型会触发”change”事件; 所有显示模型数据的视图会接收到该事件的通知,继而视图重新渲染。 你无需查找DOM来搜索指定id的元素去手动更新HTML。 — 旦模型改变了,视图便会自动变化。其主要组成包括:

  • model:创建数据,进行数据验证,销毁或者保存到服务器上
  • collection:可以增加元素,删除元素,获取长度,排序,比较等一系列工具方法,说白了就是一个保存models的集合类
  • view:绑定html模板,绑定界面元素的事件,初始的渲染,模型值改变后的重新渲染和界面元素的销毁等

AngularJS 1

AngularJS 1 诞生于2009年,是一款前端架构,其专注于web开发,后来杀出另一个基于ng 1的框架ionic,才让ng 1支持移动开发。其比较核心的一些特性包括:

  • MVC
  • 模块化
  • 指令系统
  • 双向数据绑定
  • HTML模版
  • 依赖注入
    ng 1 功能很强大,一经推出世人沸腾。不过在日后的使用过程中,随之而来的是其核心特性带来的多个问题:
  • 该框架太重,虽然后期在不断的分离出部分模块
  • 其脏检测机制带来的性能问题很严重
    由于以上等问题,google推出了ng 2,ng 2与ng 1属于不同的框架,因此单独描述。

AngularJS 2

Angular 2 于2015年推出,在github上的描述为:One framework. Mobile & desktop.
ng 2的源码目前使用ts(type script)书写,开发者也可以使用js书写。ng 2主要由8个部分组成:

  • 模块 (Modules)
  • 组件 (Components)
  • 模板 (Templates)
  • 元数据 (Metadata)
  • 数据绑定 (Data Binding)
  • 指令 (Directives)
  • 服务 (Services)
  • 依赖注入 (Dependency Injection)
    由于目前现代浏览器并不完全都支持ES6+,因此现阶段的ng 2项目一般都要通过一些工具来转换。
    systemjs - 通用模块加载器,支持AMD、CommonJS、ES6等各种格式的JS模块加载
    es6-module-loader - ES6模块加载器,systemjs会自动加载这个模块
    traceur - ES6转码器,将ES6代码转换为当前浏览器支持的ES5代码。systemjs会自动加载 这个模块,常用的转码器还有babel。

与ng 1比较,ng 2其实算是一个完全的新框架,主要的区别点在于:

  • 原生移动支持
  • 支持服务端渲染
  • ng 1中,依赖注入可以在多个地方使用不同的方法来注入,例如直接通过名字、在controller注入等,而在ng 2中只能在构造函数中通过类型注入
  • ng 1无法使用ES6来正常的书写,显然已经跟不上发展的脚步了

React

React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设Instagram 的网站。做出来以后,发现这套东西很好用,就在2013年5月开源了。由于 React的设计思想极其独特,属于革命性创新,性能出众,代码逻辑却非常简单。所以,越来越多的人开始关注和使用,认为它可能是将来 Web 开发的主流工具。这个项目本身也越滚越大,从最早的UI引擎变成了一整套前后端通吃的 Web App 解决方案。衍生的 React Native 项目,目标更是宏伟,希望用写 Web App 的方式去写 Native App。如果能够实现,整个互联网行业都会被颠覆,因为同一组人只需要写一次 UI ,就能同时运行在服务器、浏览器和手机。
React主要用于构建UI,所以并不算是一套MVC框架,它主要用于V层。React 独有的 JSX 语法,跟 JavaScript 不兼容,由于此原因,最早的react项目可能需要使用Browser.js将JSX语法转为JavaScript语法。React的主要原理包括以下几点:

  • Virtual DOM,虚拟DOM。

    1
    更新Virtual DOM并不保证马上影响真实的DOM,React会等到事件循环结束,然后利用内部diff算法,通过当前新的dom表述与之前的作比较,计算出最小的步骤更新真实的DOM。
  • Components,组件。

    1
    DOM树上的节点叫元素,而在React的Virtual DOM上自定义的节点称为commponent。
  • State、Props 和 Render。

    1
    State属性包含定义组件所需要的一些数据,当组件数据发生变化时,可以使用props将state顺序传递下去,并且将会调用Render重现渲染真实DOM,这里只能通过提供的setState方法更新数据。

目前react这边技术栈多使用react全家桶:react+redux+react-router+less+es6+webpack等,当然还有其他,例如结合mobx使用。

Ember

Vue

Grunt

Gulp

Webpack

SystemJs

jspm

nodejs

npm

bower

yarn

RESTful

REST这个词,是Roy Thomas Fielding在他2000年的博士论文中提出的。Fielding将他对互联网软件的架构原则,定名为REST,即Representational State Transfer的缩写,翻译为中文大概是”表现层状态转化”,如果一个架构符合REST原则,就称它为RESTful架构。
RESTful架构中的“表现层”,指的是资源“Resources”的表现层。所谓”资源”,就是网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的实在。你可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI。要获取这个资源,访问它的URI就可以,因此URI就成了每一个资源的地址或独一无二的识别符。所谓”上网”,就是与互联网上一系列的”资源”互动,调用它的URI。”资源”是一种信息实体,它可以有多种外在表现形式。我们把”资源”具体呈现出来的形式,叫做它的”表现层”(Representation)。比如,文本可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式;图片可以用JPG格式表现,也可以用PNG格式表现。它的具体表现形式,应该在HTTP请求的头信息中用Accept和Content-Type字段指定,这两个字段才是对”表现层”的描述。
互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生”状态转化”(State Transfer)。而这种转化是建立在表现层之上的,所以就是”表现层状态转化”。客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。
因此,一个RESTful架构大概要包括以下描述:

  • 每一个URI代表一种资源;
  • 客户端和服务器之间,传递这种资源的某种表现层;
  • 客户端通过四个HTTP动词,对服务器端资源进行操作,实现”表现层状态转化”。
    因为”资源”表示一种实体,所以其对应的URI应该是名词,不应该有动词,动词应该放在HTTP协议中。

http://www.cnblogs.com/kidney/p/6079530.html
http://www.jianshu.com/p/8dc5c6aa01fc
https://www.ibm.com/developerworks/cn/web/1509_dongyue_react/index.html

JS模块简介

js模块化,简单说就是将系统或者功能分隔成单独的、互不影响的代码片段,经过严格定义接口,使各模块间互不影响,且可以为其他所用。
常见的模块化有,C中的include (.h)文件、java中的import等。

为什么JS需要模块

很显然,没有模块我们也可以实现同样的功能,为什么我们还要使用模块来写js代码呢?下面几点是模块化给我们带来的一些变化:

  • 抽象代码:我们在使用模块来调用一个api时,可以不用知道内部是如何实现的,避免去理解其中复杂的代码;
  • 封装代码:在不需要再次修改代码的前提下,我们可以在模块内部隐藏其具体实现;
  • 复用代码:一些常用的、通用的功能,以模块来实现可以避免过多的重复代码;
  • 管理依赖:可以通过简单的修改依赖项来管理功能的实现,而不需要去重新修改自己内部的代码实现。

ES5及之前的模块系统

在ES5及之前版本,还没有原生的模块语法。不过这并不代表ES5之前,前端没有使用模块。简单介绍两种:IIFE、Revealing Module.

IIFE

Immediately Invoked Function Expression,立即执行函数表达式。

1
2
3
(function(){
// ...
})()

看上面的代码,IIFE可以说成是一个在定义的时候就执行的匿名函数。注意函数是先被”()”包起来了,然后后面紧跟”()”表示执行函数。如果是以下代码,将会报错:

1
2
3
4
5
function(){
console.log('test');
}()
// => Uncaught SyntaxError: Unexpected token )

这种写法表示,先定义一个匿名函数,然后再去解析”()”。由于在第一行”function”出现在首位,这表明此处定义一个函数,函数后紧跟”()”,此时表示单独解析”()”,就会报出上面的错误信息,因此需要先将函数定义包裹起来。
“(function…)”这种写法表示执行”()”内部代码,并返回该语句执行结果,此处返回结果为该函数,后面紧跟”()”即表示执行该函数。IIFE可以帮助我们做到:

  • 不需要了解具体的代码实现情况下取得想要的效果;
  • 在内部定义的变量不会污染全局作用域。

显而易见,这种编码方式并没有提供良好的机制来解决依赖管理问题。

Revealing Module

根据字面暂解释为揭示模式,与IIFE形式类似,但是提供了一个返回值。方便集中管理公有的api,使模块、公用api更加简洁清晰。

1
2
3
4
5
6
7
8
9
10
11
// Expose module as global variable
var singleton = function(){
// Inner logic
function sayHello(){
console.log('Hello');
}
// Expose API
return {
sayHello: sayHello
}
}()

稍微注意下,上面的代码,我们并没有用”()”去包裹,因为关键字”function”并不在该行的开头。
我们可以像下面这样使用模块api:

1
2
3
// Access module functionality
singleton.sayHello();
// => Hello

当然,我们也可以以构造函数形式导出:

1
2
3
4
5
6
7
8
9
10
11
12
13
// Expose module as global variable
var Module = function(){
// Inner logic
function sayHello(){
console.log('Hello');
}
// Expose API
return {
sayHello: sayHello
}
}

请注意,上面函数在定义的时候并没有执行。
我们可以这么使用它:

1
2
var module = new Module();
module.sayHello(); // => Hello

与IIFE一样,揭示模式并没有提供良好的解决依赖管理的方案。

更多模块化解决方案

ES6或者ES2015,自带原生的模块语法。
在这之前,有以下几种常见的用于模块化的解决方案:

  • AMD
  • CMD
  • CommonJs
  • UMD
  • System.register
  • ES6

AMD

AMD,Asynchronous Module Definition,异步模块定义。AMD形式被用于浏览器端,使用”define”来定义模块依赖:

1
2
3
4
5
6
//Calling define with a dependency array and a factory function
define(['dep1', 'dep2'], function (dep1, dep2) {
//Define the module value by returning a value.
return function () {};
});

CMD

CMD,Common Module Definition,通用模块定义。该规范由国内大神玉伯提出,与AMD区别在与AMD是依赖关系前置,有该依赖就必须先加载依赖,CMD是按需加载。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// CMD
define(function(require, exports, module) {
var a = require('./a')
a.doSomething()
// 此处略去 100 行
var b = require('./b') // 依赖可以就近书写
b.doSomething()
// ...
})
// AMD 默认推荐的是
define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好
a.doSomething()
// 此处略去 100 行
b.doSomething()
...
})

CommonJs

CommonJs在Node.js中用的较多,使用”require”来定义依赖,使用”module.exports”来定义模块:

1
2
3
4
5
6
var dep1 = require('./dep1');
var dep2 = require('./dep2');
module.exports = function(){
// ...
}

UMD

UMD,Universal Module Definition,通用模块定义。可以用于浏览器端与Node.js端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['b'], factory);
} else if (typeof module === 'object' && module.exports) {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module.exports = factory(require('b'));
} else {
// Browser globals (root is window)
root.returnExports = factory(root.b);
}
}(this, function (b) {
//use b in some fashion.
// Just return a value to define the module export.
// This example returns an object, but the module
// can return a function as the exported value.
return {};
}));

System.register

System.register方式设计初衷主要是为了在ES5中能够支持ES6模块语法:

1
2
3
4
5
6
7
import { p as q } from './dep';
var s = 'local';
export function func() {
return q;
}
export class C {
}

ES6 module

ES6中自带原生的模块语法,使用关键字”export”来导出模块的公用api:

1
2
3
4
5
6
7
8
9
// lib.js
// Export the function
export function sayHello(){
console.log('Hello');
}
// Do not export the function
function somePrivateFunction(){
// ...
}

以关键字”import”来导入模块:

1
2
3
import { sayHello } from './lib';
sayHello();
// => Hello

目前各浏览器对ES6的支持度不一,因此我们现在需要使用编译器,像Babel,来将ES6的代码编译成ES5的形式。

模块加载器

一个模块加载器可以理解模块,并以固定的形式来加载模块。
模块加载器工作在运行时,流程大致如下:

  • 你在浏览器中运行模块加载器;
  • 你告诉模块加载器需要加载哪个主文件;
  • 模块加载器下载并解析主文件;
  • 模块加载器按需加载其他文件。

一些比较常见的模块加载器有:

  • RequireJS:以AMD风格加载模块;
  • SeaJS:以CMD风格加载模块;
  • SystemJS:以AMD, CommonJS, UMD 或者 System.register风格加载模块;
  • jspm:jspm基于SystemJS,是模块加载器,同时也具备浏览器端包管理功能。

模块打包

模块打包可以替换模块加载器。
然而,相比模块加载器,模块打包动作是在编译时运行的:

  • 使用模块打包在编译期生成一个js文件;(例如bundle.js)
  • 在浏览器中加载该文件。

截止目前,比较常用的模块打包方案有以下两种:

  • Browserify:为CommonJS模块打包;
  • Webpack: 为AMD、CommonJS、ES6模块打包。

总结

为了在现代js开发环境中更好的使用这些工具,你首先需要知道模块、模块化解决方案、模块加载、模块打包之前的区别。
模块是一段封装好的代码,可以以公用api形式导出并在其他代码中被加载和调用;
模块化解决方案或者模块化思想,实际含义是定义一个模块的语法。由于定义语法的差异,目前常用的有AMD、CMD、CommonJS、UMD等;
模块加载,在运行期解析和加载模块。常见的有RequireJS、SeaJS、SystemJS和jspm;
模块打包,其替换了模块加载的概念,在编译期间生成一个所有代码整合后的bundle.js文件。常见的有Browserify和Webpack。
另,想要了解更多可以查阅下面几处链接。

参考&学习

详解JavaScript模块化开发
SeaJS与RequireJS最大的区别
使用 jspm 把握 JavaScript 模块的未来
Javascript模块化编程(一):模块的写法 By 阮一峰 2012年10月26日
Javascript模块化编程(二):AMD规范 By 阮一峰 2012年10月30日
Javascript模块化编程(三):require.js的用法 By 阮一峰 2012年11月07日

(本文译自:A 10 minute primer to JavaScript modules, module formats, module loaders and module bundlers By Jurgen Van de Moere, February 21st, 2017)



money☜☜☜ wechat 『『『 reward 点击扫码打赏 ~~~ ^_^ 』』』alipay ☞☞☞ money



批处理

常用常见的批处理文件有.bat文件,可用文本编辑器直接编辑内部代码,运行也比较方便,windows平台直接双击执行即可,具体请自行了解。

需求背景

angular项目中,当项目越来越大时,很多通用模块(module)可能需要抽象出来,这是一点,另外可能有某些子应用也会单独抽离出来,这是另一点。
当一个大型项目同时包括多个子应用时,编码后的编译或者打包就会比较麻烦,特别是在项目持续集成的一种状态下,或者项目组有新成员(经验稍微薄弱)情况下。

需要了解

看下面的代码之前,如果您是angular使用者+gulp使用者,为了更好的理解下面的代码,你可能需要了解以下东西:node、npm、node_modules、gulp。
如果您不使用angular或者gulp,也没有太大关系,你可以通过我肤浅的解释来理解一些批处理相关的操作,以应用到其他用途。

示例&&解释

    // 关闭回显,加上这句,当前执行的命令不会显示(即,下面这些代码不会显示在屏幕上)
    @echo off

    // 读取run_config.txt文件第一行数据,以参数domain存储,然后跳转到secondArgs命令执行
    // 我这么写不可取,跳转secondArgs命令主要用于读取第二行数据
    for /f %%i in (run_config.txt) do (
    set domain=%%i
    goto secondArgs
    )

    // 读取第二行数据以参数dir存储
    :secondArgs
    for /f %%i in (run_config.txt) do (
    set dir=%%i
    )

    // 输出参数domain、dir
    echo the root path is:%domain%
    echo the project path is:%dir%

    echo AUTO RUNING, PLEASE ENTER ACCORDING THE TIPS......

    // begin命令
    :begin
    echo ************TIPS START************
    echo at the first use,please input 'm' to set root path and project path according the tips.
    echo ************TIPS ENDS!************

    // 改变字体颜色,可选颜色不多
    color 07
    // 以命令选择的形式,给使用者选择的权利,其中将各个项目(各应用)需要的打包分离出来,分别对应相应的自动化构建脚本命令
    // 以字母RCAPMQ一一对应,例如输入Q,则进入exit命令
    choice /m ROOT,COMMONS,APP,PORTAL,MODIFY,EXIT /c:RCAPMQ

    if errorlevel 6 goto exit
    if errorlevel 5 goto modify
    if errorlevel 4 goto portal
    if errorlevel 3 goto app
    if errorlevel 2 goto commons
    if errorlevel 1 goto root

    :root
    color 0a
    // 用于进入对应的盘符
    %domain%
    // 用于进入对应的项目目录
    cd%dir%
    // 执行当前目录下的gulp命令
    node %domain%%dir%\node_modules\gulp\bin\gulp.js
    echo -----------------------------ROOT PROCESS FINISHED!----------------------------
    // 跳转begin命令,可以让使用者进行下一次使用
    goto begin
    // 以下几个命令类似上面

    :commons
    color 0d
    %domain%
    cd%dir%\commons
    node %domain%%dir%\node_modules\gulp\bin\gulp.js
    echo ----------------------------COMMONS PROCESS FINISHED!--------------------------
    goto begin

    :app
    color oe
    %domain%
    cd%dir%\app
    node %domain%%dir%\node_modules\gulp\bin\gulp.js debug
    echo ---------------------------APP_BASE PROCESS FINISHED!--------------------------
    goto begin

    // 该命令可以进行多个应用的一键构建
    :portal
    color 0a
    %domain%
    cd%dir%
    node %domain%%dir%\node_modules\gulp\bin\gulp.js
    cls
    echo -----------------------------ROOT PROCESS FINISHED!----------------------------
    echo ***************************COMMONS PROCESS STARTING!***************************
    color 0d
    %domain%
    cd%dir%\commons
    node %domain%%dir%\node_modules\gulp\bin\gulp.js
    cls
    echo ----------------------------COMMONS PROCESS FINISHED!--------------------------
    echo ******************************APP PROCESS STARTING*****************************
    color 0e
    %domain%
    cd%dir%\app
    node %domain%%dir%\node_modules\gulp\bin\gulp.js debug
    cls
    echo ------------------------------APP PROCESS FINISHED-----------------------------
    echo *******************************************************************************
    color 0f
    goto begin

    // modify命令用于修改盘符及项目目录路径
    :modify
    // 删除config文件
    del run_config.txt
    // '/p'会暂停当前命令
    // 此处主要用于获取用户输入
    set /p domain=please input yours root path,end with ':', eg.'d:':
    echo the root path is:%domain%
    // 输出输入的信息并保存到config文件中
    @echo %domain%>>run_config.txt

    set /p dir=please input yours project path, start with '/', eg. '/xx/xx':
    echo the project path is:%dir%
    @echo %dir%>>run_config.txt
    goto begin

    // 关闭当前窗口
    :exit
    pause

心得

弄这个.bat文件,主要也是为了偷懒。花了一点时间查找了相应的操作、使用说明,也算是初步可用。
目前使用起来也比较方便,可以在以后有机会时再次自定义一个类似文件,便捷开发,提高效率。



money☜☜☜ wechat 『『『 reward 点击扫码打赏 ~~~ ^_^ 』』』alipay ☞☞☞ money



名词解释

Partial Application,也译作“偏应用”或“部分应用”。
Curring,也译作“柯里化”。
arity,元。表示函数的参数数量。如,unary(一元),binary(二元),ternary(三元),polyadic(多元)。

完全应用

假设有一个函数A,其需要n个参数来应用,而当我们调用函数A时,给它传入了n个参数。则A函数完全应用了我们传入的参数。

局部应用

即函数调用的时候只提供部分参数供其应用。例如以下:

    function mapWith(fn){
        return function(list){
            return map(list,fn);
        }
    }
如上,当我们调用mapWith函数时,先传入一个参数,其返回一个函数结果,执行该结果的时候再传入第二个参数,返回最终结果。类似于:
    mapWith(square)([1,2,3]);

局部套用

上面的局部应用,其中的map函数为一个我们已知的具体函数,我们可以稍加修整,如下:
第一步,先将map用一个更抽象的函数binaryFn取代,暗示此处可以做任何一种二元函数的处理。同时,最外层的函数名,也就可以做相应的调整了,我们可以使用wrapper取代之。
第二步,既然用来最终处理的函数都抽象化了,那传入的参数自然也没有必要限定其类型。
于是,我们可以将其稍微调整为如下状态:

    function wrapper(secondArg){
        return function(firstArg){
            return binaryFn(firstArg,secondArg);
        }
    }

到这里,会突然发现其中的binaryFn函数并未做初始化,无法灵活的使用,于是我们可以再包装一层:


function rightmostCurry(binaryFn) {
return function (secondArg) {
return function (firstArg) {
return binaryFn(firstArg, secondArg);
};
};
}

到现在,我们可以试着调用一下rightmostCurry函数。


var rightmostCurriedMap = rightmostCurry(map);
var squareAll = rightmostCurriedMap(square);
squareAll([2, 3, 5]); // => [4, 9, 25]
squareAll([1, 4, 7, 6]); // => [1, 16, 49, 36]

对比局部应用会发现,在局部应用中,最内层的处理函数是确定的。而在局部套用中,最内层的实际处理函数,是未知的,其最终结果是在最外层函数调用后,分批传入其他参数来获取的。
由此可以做如下解释:

  • 局部应用: 返回最终结果的处理方式是限定的,每一层的函数调用所传入
    的参数都将逐次参与最终处理过程中去;
  • 局部套用: 返回最终结果的处理方式是未知的,需要我们在使用的时候将
    其作为参数传入。

leftmost(最左形式)

仔细观察上面的函数,可能会有疑问,在中间层函数中,把参数调换会出现什么情况呢?先把函数改造下,如下:


function leftmostCurry(binaryFn) {
return function (firstArg) {
return function (secondArg) {
return binaryFn(firstArg, secondArg);
};
};
}
var leftmostCurriedMap = leftmostCurry(map);

function square(n) { return n * n; }
function double(n) { return n + n; }

var oneToThreeEach = leftmostCurriedMap([1, 2, 3]);
oneToThreeEach(square);   // => [1, 4, 9]
oneToThreeEach(double);   // => [2, 4, 6]


上面就是最左形式的局部套用示例用法。
由于一般代码逻辑都是“从左向右”,因此在其他项目中见过比较多的应该是leftmost形式。习惯上直接把leftmost形式叫做curry。

现实使用

现实中用到局部套用情况一般可能做如下处理:


function rightmostUnaryPartialApplication(binaryFn, secondArg) {
return function (firstArg) {
return binaryFn(firstArg, secondArg);
};
}
var applyLast = rightmostUnaryPartialApplication;

var squareAll = applyLast(map, square);
var doubleAll = applyLast(map, double);
squareAll([1,2,3]);
doubleAll([1,2,3]);


以上用法,仔细观察会发现有很多开发者都在多次使用,希望在用到或者看到这类用法时,能真正理解其区别及联系。

参考文献

函数式编程中局部应用(Partial Application)和局部套用(Currying)的区别
Curry or Partial Application? Eric ElliottFollow Jul 20, 2015



money☜☜☜ wechat 『『『 reward 点击扫码打赏 ~~~ ^_^ 』』』alipay ☞☞☞ money



Good News: 现在我们可以用浏览器调试node.js了!!!

前提

  • Node.js 6.3+, 这个可上Node.js官网自行下载;
  • Chrome 55+. 如果您本地的chrome升级到最新版后还是<55, 可以从此处下载:Chrome Canary,亲测可行。

配置

就目前来说,在浏览器端并行调试JavaScript与Node.js还属于新特性,新体验。为了能够正常使用,你还需要做如下配置:

  • 输入url:chrome://flags/#enable-devtools-experiments. 注:如果使用中文版Chrome,显示的配置项名称应该为: 开发者工具实验性功能 ,如下图;
    flags
  • 启用它;
  • 重启Chrome;
  • 打开 DevTools Setting -> Experiments 页卡;
  • 找到 Node debugging , 勾选.

最后应该能看到类似下图,表示环境已准备好:
debugging

调试

调试很简单,像普通的js文件一样,利用DevTools进行断点调试.

运行Node.js app

需要在debug模式下运行Node.js应用,很简单,只要添加 –inspect 参数即可。

1
node --inpect server.js

注:server.js 为我自己的应用文件,自定义,下图中为’ node.js ‘。如果顺利的话,应该能看到类似下图信息:
debugging
运行后,可以看到在 DevTools -> Sourcesserver.js 应用:
source
展开后,可以查看当前node应用的js文件,至此,您已经可以利用Chrome进行并行调试操作了。
success

最后

使用此新版Chrome,还有许多其他的功能,比如在调试期间修改文件内容、保存文件快照等。
最后的最后,感谢原作者 Serg Hospodarets 的分享,Thank You!

(本文译自:Node.js debugging with Chrome DevTools (in parallel with browser JavaScript) By Serg Hospodarets, September 29, 2016)



money☜☜☜ wechat 『『『 reward 点击扫码打赏 ~~~ ^_^ 』』』alipay ☞☞☞ money



ES6(ES2015)带来了箭头函数,箭头函数带来了些许问题。

关于{}

第一个问题是关于箭头函数与{}
箭头函数,乍一看,用法似乎很简单,比如像下面这样用来给数组每一项乘以2:

1
2
3
const numbers = [1, 2, 3];
const result = numbers.map(n => n * 2);
// produces [2,4,6]

但是,如果使用不当,可能会引发意想不到的问题。比如下面,尝试为数组中每一项去产生对象字面量,看上去挺简单的map操作,还是引发了意外。

1
2
3
const numbers = [1, 2, 3];
const result = numbers.map(n => { value: n });
// produces [undefined], [undefined], [undefined]

什么原因造成的呢?
稍微分析可知,引起上面问题在于,箭头函数内部包裹在花括号之间的代码,被认为是一段独立的代码块而不是对象字面量,因此其单独执行,显然得到的结果就是一个全为undefined的数组。
于是,在这种情况下,其中的代码就必须有明确的返回语句或者用圆括号()包括对象字面量。

1
2
const result = numbers.map(n => ({ value: n }));
// [{value: 1}, {value:2}, {value:3}]

关于this

第二个问题是关于箭头函数与this
使用箭头函数,你可以像下面这样写代码而不用额外在局部作用域中去暂存this:

1
2
3
4
5
6
7
8
9
10
const adder = {
sum: 0,
add(numbers) {
numbers.forEach(n => {
this.sum += n;
});
}
};
adder.add([1, 2, 3]);
// adder.sum === 6

然而,很多时候你可能会自以为是的在不经意间写错。正如下面的代码所示,this并不指向”adder”对象,而指向”adder”对象所在的作用域:

1
2
3
4
5
6
7
8
9
10
11
12
const adder = {
sum: 0,
add: (numbers) => { // scope here is important
numbers.forEach(n => {
this.sum += n;
});
}
};
adder.add([1, 2, 3]);
// adder.sum === 0

最后请记住一点:箭头函数中的this继承自外围作用域的值,因此我们不能改变其指向。

(本文译自:The Troubles with JavaScript Arrow Functions By K. Scott Allen , Thursday, September 1, 2016 )



money☜☜☜ wechat 『『『 reward 点击扫码打赏 ~~~ ^_^ 』』』alipay ☞☞☞ money



当浏览器最小化或者打开其他页签时,很多情况下,你可能并不希望当前页签应用被中止或者打断,而是期望当前页签应用的状态能够维持原状。
幸运的是,我们可以使用Page Visibility APi来实现。PC系统中规中矩的参照api使用即可,下面主要介绍几点Mobile端使用需要注意的几点。

visibilityState, pageshow, pagehide, beforeunload, unload

很多移动应用中使用此api遇到的问题在于他们没有考虑手机的生命周期:他们监听了一些可能永远都不会触发的事件,或者忽视了少数高耗用户的用户体验。
老实说,移动平台对于探索不同的事件也确实并非易事,那针对上面的那些事件,我们到底该在何时何处,如何使用呢?
先上一张图说明app的生命周期:
lifecycle

你别寄希望在移动平台触发上面的pagehidebeforeunloadunload事件了。这个问题并不来源于你喜爱的浏览器出现的bug,根源在于所有的移动操作系统的工作原理。
一个应用从active状态到background状态,可能由以下几种方式触发:

  • 用户可以通过点击消息通知等切换到其他app;
  • 用户可以通过任务管理器的切换进入其他app;
  • 用户可以点击home返回桌面;
  • 操作系统选择是否中断用户的行为-例如:有来电。
    一旦应用切换到background状态,它就可能在未来某一刻被杀死-例如:操作系统可能会中止进程并释放资源、用户可能会通过任务管理器关闭app。
    这样导致的结果就是你期望触发的上面三个事件,都没有触发。

为了良好的用户体验,不管是Mobile端还是PC端的应用,都必须使用Page Visibility Api,在visibilityChange事件触发时来执行session保存及暂存逻辑等操作,这是你应用可以依赖的唯一一个事件。

1
2
3
4
5
6
7
8
9
10
11
// query current page visibility state: prerender, visible, hidden
var pageVisibility = document.visibilityState;
// subscribe to visibility change events
document.addEventListener('visibilitychange', function() {
// fires when user switches tabs, apps, goes to homescreen, etc.
if (document.visibilityState == 'hidden') { ... }
// fires when app transitions from prerender, user returns to the app / tab.
if (document.visibilityState == 'visible') { ... }
});

如果你指望unload事件来做这些事,你就忽视了移动端可能永远不会触发unload事件。同样的,如果你指望beforeunload事件,你就忽视了在清理应用情况下关闭应用时将不会触发此事件。

实际情况下的考虑

一般情况下,你只需要使用Page Visibility Api就够了。然而在今天,你可能会想讨论下pagehide,这算是当页面进入unloaded状态的一种特例。下面是一些主流浏览器在哪些情况下会触发哪些事件的一个简要说明:

can i use?

  • visibilityChange在移动平台的任务切换状态下可以正常工作;
  • beforeunload备受限制,只能在PC端可以正常使用;
  • unload不能在Safari浏览器中正常工作。

最后(自己想法)

Page Visibility Api用途有哪些呢,比如音视频播放,切换后台可以暂停,再切换进来保持状态等,希望通过此文可以在使用过程中避免一些莫名的坑。

(本文译自:dont-lose-user-and-app-state-use-page-visibility By Ilya Grigorik on November 20, 2015 )



money☜☜☜ wechat 『『『 reward 点击扫码打赏 ~~~ ^_^ 』』』alipay ☞☞☞ money



本文主要介绍一些对自己技术有很大帮助的网站,后续也将更新,感谢这些网站的相关人员,致敬!

Can I Use

can i use网站很常见,很多博客里面介绍一些CSS/JS/H5新特性的时候,会用到它,可以用来查看某一特性在各浏览器的支持程度,使用效果如下图:
function

学习CSS布局

该网站虽然功能比较单一,只介绍CSS布局相关的知识,但是界面和介绍比较通俗易懂,适合CSS初学者学习,如下图:
function

Understanding JavaScript OOP

本文是一篇2011年的国外文章,主要介绍JavaScript OOP。推荐这篇文章的原因并不是写的有多好,而是个人觉得此文比较适合作为慢慢阅读英文博客的开始,另外该站还有一些其他技术博客可供赏阅。
function

奇舞周刊

本站每周会更新一次,更新的内容都是一些比较有质量的前端知识。
function

free-programming-books

该资源提供广大网友贡献的一些编程书籍列表,涉及领域很多,每个领域也有细分多个分支,如果有需要可以上去看看,不过大多是英文版。

JavaScript 标准库

该资源由MOZILIA MDN提供,算是一份比较详尽的JavaScript参考文档,唯一的缺点是由网友贡献,并不算完善。
function

FontAwesome

提供字体图标,我介绍这个并不只是简单的引用后当图标来用—-你可以将字体文件下载下来,然后用PS,按照自己需求,做成透明雪碧图,可换颜色。
function



money☜☜☜ wechat 『『『 reward 点击扫码打赏 ~~~ ^_^ 』』』alipay ☞☞☞ money