From 544a7eb341a893f2e6b6606da6033b219a5b741d Mon Sep 17 00:00:00 2001 From: Trotyl Date: Tue, 11 Oct 2016 17:09:59 +0530 Subject: [PATCH 001/177] Add article --- .../_index.md" | 105 ++++++++++++++++++ src/app/_shared/api/articles/index.ts | 10 ++ 2 files changed, 115 insertions(+) create mode 100644 "src/app/_shared/api/articles/180.\346\263\250\350\247\243\344\270\216\350\243\205\351\245\260\345\231\250\347\232\204\347\202\271\347\202\271\346\273\264\346\273\264/_index.md" diff --git "a/src/app/_shared/api/articles/180.\346\263\250\350\247\243\344\270\216\350\243\205\351\245\260\345\231\250\347\232\204\347\202\271\347\202\271\346\273\264\346\273\264/_index.md" "b/src/app/_shared/api/articles/180.\346\263\250\350\247\243\344\270\216\350\243\205\351\245\260\345\231\250\347\232\204\347\202\271\347\202\271\346\273\264\346\273\264/_index.md" new file mode 100644 index 0000000..34d2a67 --- /dev/null +++ "b/src/app/_shared/api/articles/180.\346\263\250\350\247\243\344\270\216\350\243\205\351\245\260\345\231\250\347\232\204\347\202\271\347\202\271\346\273\264\346\273\264/_index.md" @@ -0,0 +1,105 @@ +# 注解与装饰器的点点滴滴 + +原文地址: https://zhuanlan.zhihu.com/p/22277764 + + +对于很多 Java 开发人员来说,注解(Annotation)已经是一个十分熟悉的概念。而在 JavaScript 中(目前仍然是 Stage 2 的 ES Proposal),引入了一个类似的语法——装饰器(Decorator)。 + +甚至有很多人在生活中不加区分两个的概念,把装饰器也叫做注解。那么,装饰器和注解到底有什么联系与区别呢? + +## 概念 + ++ 注解(Annotation):仅提供附加元数据支持,并不能实现任何操作。需要另外的 Scanner 根据元数据执行相应操作; ++ 装饰器(Decorator):仅提供定义劫持,能够对类及其方法的定义并没有提供任何附加元数据的功能。 + +虽然语法上很相似,但在不同的语言中可能使用的是不同的概念: + ++ 使用注解(Annotation)的语言:AtScript、Java、C#(叫 Attribute); ++ 使用装饰器(Decorator)的语言:Python、JavaScript/ECMAScript。 + +从概念上来说,我们可以很清晰的看出,**注解和装饰器在语义上没有任何共性!** + +但是,这个结论并不是那么符合我们的直觉,一个最直接的例子就是 Angular 2,在曾经结合 AtScript 使用的时候,用的是注解;在改成结合 TypeScript/ES next 使用的时候,用的是装饰器。虽然叫法变了,但在 API 方面几乎没有任何可见的变化,这又是为什么呢? + + +## 实现 + +这里以 AtScript 的注解和 ES Stage 2(截至目前)的 Decorator 为例。 + +在 AtScript 中,我们使用的是真真切切的 Annotation,也就是完完全全的单纯附加元数据,例如: + +```atscript +// app.component.as(我也不记得 AtScript 后缀名是什么了) + +@Component({ + selector: 'app' +}) +class AppComponent {} +``` + +等价于: + +```javascript +// app.component.js + +class AppComponent {} + +AppComponent.annotations = [ + new Component({ + selector: 'app' + }) +] +``` + +也就是简单地把注解中的类型转化成实例构造然后挂到被注解的类型上。 + +而在 ES next 的 Decorator 中,我们也可以使用类似的语法: + +```typescript +// app.component.ts + +@Component({ + selector: 'app' +}) +class AppComponent {} +``` + +但却具有完全不同的语义: + +```javascript +// app.component.js + +let AppComponent = Component({ + selector: 'app' +})(class AppComponent {}) +``` + +*这里的对应结果并不完全精确,仅供表意。* + +## 事实上 + +我们发现,对于注解有一个构造函数调用,对于装饰器而言有一个普通的函数调用。**既然有这个函数调用过程,我们其实可以该函数调用中做任何事情!** + +**或者说的更为直白一些,(AtScript 的)注解和(ES next 的)装饰器在实现上可以相互模拟!** + +*对于装饰器而言,如果想要实现注解的功能,在原来的类型上挂点什么东西就好;对于注解而言,如果想要实现装饰器的功能,把现有类型(或其属性)按需替换掉就好。当然,后者可能会有一些限制,因为前提是要能够获取到目标类型,但 Annotation 本身并没有提供这个功能。* + +现在我们可以知道,所有 Angular 2 中使用的 Decorator 都并不是真正作为 Decorator 使用,只是通过 Decorator + Reflect.metadata(泛指 Reflect.metadata 和 Reflect.xxxMetadata 等,下同) 的组合来模拟 Annotation 的功能。即附加元数据走的是 Reflect.metadata,该实现和 Decorator 本身并无联系。 + +**所以 Angular 2 中其实并没有通过 Decorator(这个语言特性)来实现附加数据,而是在 Decorator 的应用过程中,通过 Reflect.metadata 来附加数据,Decorator 在这里的意义仅仅是作为语法糖,把函数调用写的更好看了而已。** + +另外,虽然我们的用法没有发生变化,但经过上面的讨论我们很容易知道在 Angular 2 中原先配合 AtScript 的 Component 实体的实现和现在配合 ES next 的 Component 实体的实现是完全不一样的,前者就是 ComponentMetadata,而后者是一个 ComponentDecoratorFactory。 + +在 rc6 及之前 Component 这个函数的配置对象的类型叫做 ComponentMetadata,rc7 及之后也同样叫 Component,但是不同的实体(前者是 const,后者是 interface),也就是说在 TypeScript 中如果 `import { Component } from '@angular/core'` 这样是同时引入了两个叫做 Component 的同名标识,本文不是 TypeScript 相关所以不做过多介绍。 + + +## 总结 + ++ 注解和装饰器语法上很接近; ++ 注解和装饰器语义上没有一丁点关系; ++ Angular 2 曾经在 AtScript 中用的是注解语法; ++ Angular 2 现在在 ES next 中用的是装饰器语法; ++ 装饰器没有提供任何附加数据的功能; ++ 从 Core 模块中引入的 Component 是两个不同类型的同名标识符(TypeScript only); ++ Angular 2 虽然用的装饰器的语法但并没有使用装饰器的功能; ++ Angular 2 的附加元数据是通过 Reflect.metadata 实现的,和装饰器本身并没有任何关系。 diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 3ea5d0f..f6b8962 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -182,6 +182,16 @@ const items: Article[] = [ tags: [], authors: ['trotyl'], }, + { + id: '注解与装饰器', + title: '注解与装饰器的点点滴滴', + summary: '注解(Annotation)和装饰器(Decorator)是两个截然不同的概念,但在 Angular 中往往容易造成混淆,本文将简要阐述两个的区别与联系', + content: require('./180.注解与装饰器的点点滴滴/_index.md'), + first: false, + column: 'trotyl', + tags: [], + authors: ['trotyl'], + }, ]; @Injectable() From f34fac791e004061cd0942c1598e60d8742b1f95 Mon Sep 17 00:00:00 2001 From: Trotyl Date: Wed, 12 Oct 2016 16:30:49 +0530 Subject: [PATCH 002/177] Adjust wording --- .../_index.md" | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git "a/src/app/_shared/api/articles/180.\346\263\250\350\247\243\344\270\216\350\243\205\351\245\260\345\231\250\347\232\204\347\202\271\347\202\271\346\273\264\346\273\264/_index.md" "b/src/app/_shared/api/articles/180.\346\263\250\350\247\243\344\270\216\350\243\205\351\245\260\345\231\250\347\232\204\347\202\271\347\202\271\346\273\264\346\273\264/_index.md" index 34d2a67..67bfca0 100644 --- "a/src/app/_shared/api/articles/180.\346\263\250\350\247\243\344\270\216\350\243\205\351\245\260\345\231\250\347\232\204\347\202\271\347\202\271\346\273\264\346\273\264/_index.md" +++ "b/src/app/_shared/api/articles/180.\346\263\250\350\247\243\344\270\216\350\243\205\351\245\260\345\231\250\347\232\204\347\202\271\347\202\271\346\273\264\346\273\264/_index.md" @@ -5,7 +5,7 @@ 对于很多 Java 开发人员来说,注解(Annotation)已经是一个十分熟悉的概念。而在 JavaScript 中(目前仍然是 Stage 2 的 ES Proposal),引入了一个类似的语法——装饰器(Decorator)。 -甚至有很多人在生活中不加区分两个的概念,把装饰器也叫做注解。那么,装饰器和注解到底有什么联系与区别呢? +甚至有很多人在日常工作中不区分这两个概念,把装饰器也叫做注解。那么,装饰器和注解到底有什么联系与区别呢? ## 概念 @@ -78,9 +78,9 @@ let AppComponent = Component({ ## 事实上 -我们发现,对于注解有一个构造函数调用,对于装饰器而言有一个普通的函数调用。**既然有这个函数调用过程,我们其实可以该函数调用中做任何事情!** +我们发现,对于注解有一个构造函数调用,对于装饰器而言有一个普通的函数调用。**既然有这个函数调用过程,我们其实可以在该函数调用中做任何事情!** -**或者说的更为直白一些,(AtScript 的)注解和(ES next 的)装饰器在实现上可以相互模拟!** +**或者说得更为直白一些,(AtScript 的)注解和(ES next 的)装饰器在实现上可以相互模拟!** *对于装饰器而言,如果想要实现注解的功能,在原来的类型上挂点什么东西就好;对于注解而言,如果想要实现装饰器的功能,把现有类型(或其属性)按需替换掉就好。当然,后者可能会有一些限制,因为前提是要能够获取到目标类型,但 Annotation 本身并没有提供这个功能。* @@ -90,7 +90,7 @@ let AppComponent = Component({ 另外,虽然我们的用法没有发生变化,但经过上面的讨论我们很容易知道在 Angular 2 中原先配合 AtScript 的 Component 实体的实现和现在配合 ES next 的 Component 实体的实现是完全不一样的,前者就是 ComponentMetadata,而后者是一个 ComponentDecoratorFactory。 -在 rc6 及之前 Component 这个函数的配置对象的类型叫做 ComponentMetadata,rc7 及之后也同样叫 Component,但是不同的实体(前者是 const,后者是 interface),也就是说在 TypeScript 中如果 `import { Component } from '@angular/core'` 这样是同时引入了两个叫做 Component 的同名标识,本文不是 TypeScript 相关所以不做过多介绍。 +在 rc6 及之前 Component 这个 Factory 函数的配置对象的类型叫做 ComponentMetadata,rc7 及之后也同样叫 Component,但两者是不同的实体(前者是 const,后者是 interface),也就是说在 TypeScript 中如果 `import { Component } from '@angular/core'` 这样是同时引入了两个叫做 Component 的同名标识,本文不是 TypeScript 相关所以不做过多介绍。 ## 总结 From bad463b1fdf3f73278547ebcd397864b9a08be35 Mon Sep 17 00:00:00 2001 From: Trotyl Date: Wed, 12 Oct 2016 16:32:51 +0530 Subject: [PATCH 003/177] Adjust layout --- .../_index.md" | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git "a/src/app/_shared/api/articles/180.\346\263\250\350\247\243\344\270\216\350\243\205\351\245\260\345\231\250\347\232\204\347\202\271\347\202\271\346\273\264\346\273\264/_index.md" "b/src/app/_shared/api/articles/180.\346\263\250\350\247\243\344\270\216\350\243\205\351\245\260\345\231\250\347\232\204\347\202\271\347\202\271\346\273\264\346\273\264/_index.md" index 67bfca0..b7b2b96 100644 --- "a/src/app/_shared/api/articles/180.\346\263\250\350\247\243\344\270\216\350\243\205\351\245\260\345\231\250\347\232\204\347\202\271\347\202\271\346\273\264\346\273\264/_index.md" +++ "b/src/app/_shared/api/articles/180.\346\263\250\350\247\243\344\270\216\350\243\205\351\245\260\345\231\250\347\232\204\347\202\271\347\202\271\346\273\264\346\273\264/_index.md" @@ -88,9 +88,7 @@ let AppComponent = Component({ **所以 Angular 2 中其实并没有通过 Decorator(这个语言特性)来实现附加数据,而是在 Decorator 的应用过程中,通过 Reflect.metadata 来附加数据,Decorator 在这里的意义仅仅是作为语法糖,把函数调用写的更好看了而已。** -另外,虽然我们的用法没有发生变化,但经过上面的讨论我们很容易知道在 Angular 2 中原先配合 AtScript 的 Component 实体的实现和现在配合 ES next 的 Component 实体的实现是完全不一样的,前者就是 ComponentMetadata,而后者是一个 ComponentDecoratorFactory。 - -在 rc6 及之前 Component 这个 Factory 函数的配置对象的类型叫做 ComponentMetadata,rc7 及之后也同样叫 Component,但两者是不同的实体(前者是 const,后者是 interface),也就是说在 TypeScript 中如果 `import { Component } from '@angular/core'` 这样是同时引入了两个叫做 Component 的同名标识,本文不是 TypeScript 相关所以不做过多介绍。 +另外,虽然我们的用法没有发生变化,但经过上面的讨论我们很容易知道在 Angular 2 中原先配合 AtScript 的 Component 实体的实现和现在配合 ES next 的 Component 实体的实现是完全不一样的,前者就是 ComponentMetadata,而后者是一个 ComponentDecoratorFactory。在 rc6 及之前 Component 这个 Factory 函数的配置对象的类型叫做 ComponentMetadata,rc7 及之后也同样叫 Component,但两者是不同的实体(前者是 const,后者是 interface),也就是说在 TypeScript 中如果 `import { Component } from '@angular/core'` 这样是同时引入了两个叫做 Component 的同名标识,本文不是 TypeScript 相关所以不做过多介绍。 ## 总结 From fa551f7f0ba6d75f2e5c4cb2a438bebd9daf683e Mon Sep 17 00:00:00 2001 From: Trotyl Date: Wed, 12 Oct 2016 16:39:12 +0530 Subject: [PATCH 004/177] Remove footnote --- .../_index.md" | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git "a/src/app/_shared/api/articles/110.\345\246\202\344\275\225\347\220\206\350\247\243RxJS/_index.md" "b/src/app/_shared/api/articles/110.\345\246\202\344\275\225\347\220\206\350\247\243RxJS/_index.md" index 65ab76e..a6a8d9a 100644 --- "a/src/app/_shared/api/articles/110.\345\246\202\344\275\225\347\220\206\350\247\243RxJS/_index.md" +++ "b/src/app/_shared/api/articles/110.\345\246\202\344\275\225\347\220\206\350\247\243RxJS/_index.md" @@ -1,6 +1,6 @@ # 如何理解 RxJS ? -在 Angular 2 中,我们遇到了一个新的概念 —— RxJS[^new]。 +在 Angular 2 中,我们遇到了一个新的概念 —— RxJS。 对很多人而言,这可能是一个比较难以理解的地方。所谓的难以理解并不是说 API 有多复杂,而是对于 RxJS 本身的理念就无从下手。 @@ -8,7 +8,7 @@ ## 函数响应式编程(FRP) -FRP 早在上世纪 90 年代就已经被提出[^1],但由于早期的编译器和运行时能力有限,大部分编程实践中往往采用的是人迁就机器的理念,即**命令式编程**,或者叫广义的面向过程[^procedural]。 +[FRP](https://en.wikipedia.org/wiki/Functional_reactive_programming) 早在上世纪 90 年代就已经被提出,但由于早期的编译器和运行时能力有限,大部分编程实践中往往采用的是人迁就机器的理念,即**命令式编程**,或者叫广义的面向过程。(这里指包括面向对象在内的以指定步骤的方式来编程的方式) 而另一类编程方式,叫做**声明式编程**。在声明式编程中,并不会为一个操作指定步骤,而只是单纯的给出我们的意图,而函数响应式编程就是声明式编程中的一个重要实践。 @@ -113,9 +113,11 @@ allPeople$.filter(person => person.age >= 18) 事实上,我们确实也可以把 Observable 看成一个有可变数据量的 Promise,而 Promise 只能包含一个数据。 -如果看成状态机的话,那么 Promise 具有 3 个状态[^2]:pending、resolved、rejected。而 Observable 有 N + 3 个状态:idle、pending、resolved_0、resolved_1 ... resolved_N、completed 和 error。 +如果看成状态机的话,那么 Promise 具有 3 个状态:pending、resolved、rejected(如果 [Cancelable Promise](https://github.com/tc39/proposal-cancelable-promises) 正式通过,那么还会增加一个状态)。而 Observable 有 N + 3 个状态:idle、pending、resolved_0、resolved_1 ... resolved_N、completed 和 error。 -因此,相比于 Promise 这个有限状态机而言,Observable 既可能是有限状态机,也可能是无限状态机(N 为无穷)。并且 Observable 还具有可订阅性,对于 Cold Observable[^3] 而言,只有订阅后才开始起作用,而 Promise 一经产生便开始起作用。 +因此,相比于 Promise 这个有限状态机而言,Observable 既可能是有限状态机,也可能是无限状态机(N 为无穷)。并且 Observable 还具有可订阅性,对于 Cold Observable 而言,只有订阅后才开始起作用,而 Promise 一经产生便开始起作用。 + +*Observable 可以分为 Cold Observable 和 Hot Observable,Cold Observable 只有被订阅后才开始产生事件,比如封装了 Http 的 Observable,而 Hot Observable 始终产生事件,比如封装了某元素 Click 事件的 Observable。* 此外,由于 Promise 仅有一个数据,故数据被获取即为 Promise 完成,仅需要一个状态。而对于 Observable,由于可以有任意多个数据,因此需要一个额外的状态来表示完成,一经完成后便不能再产生数据。 @@ -164,7 +166,7 @@ Observable[Symbol.iterator] = function () { } ``` -这样[^4],我们就能够通过 for...of 循环的方式来使用: +这样(仅供表意的实现版本,并没有经过严格验证,请勿直接用于实际项目中),我们就能够通过 for...of 循环的方式来使用: ```typescript for (let itemPromise of someObservable) { @@ -173,7 +175,7 @@ for (let itemPromise of someObservable) { } ``` -不过,这样我们仍然需要在循环体中使用 await,并不美观(其实已经比较美观了,只是为了引出下文这么说),为此我们可以更进一步,直接实现 Async Iterable[^5]: +不过,这样我们仍然需要在循环体中使用 await,并不美观(其实已经比较美观了,只是为了引出下文这么说),为此我们可以更进一步,直接实现 Async Iterable(目前仍然是 Stage 3 的[提案](https://github.com/tc39/proposal-async-iteration),有望进入 ES2017 中): ```typescript Observable[Symbol.asyncIterator] = function () { @@ -224,12 +226,3 @@ Rx 的知识在 Angular 2 中并不必须,主要用在 API 交互上,之所 理解了 Iterable 和 AsyncIterable 之后,也可能把 Observable 看成一个 AsyncIterable 的特例,也就是一个异步的迭代容器。 Rx 提供了大量的运算符,用于对 Observable 的组合与变换。 - - -[^new]: 也可能并没有遇到,因为是否需要在应用中直接使用 RxJS 完全是可选的,如果不想用 RxJS 的话也完全可以不直接使用。(至于 Angular 在内部有没有用和我们没什么关系了,好比我们说没有操作 DOM 的时候难道真的没有操作 DOM 吗?只是我们不去直接操作而已) -[^procedural]: 这里的面向过程指包括面向对象在内的以指定步骤的方式来编程的方式。 -[^1]: https://en.wikipedia.org/wiki/Functional_reactive_programming -[^2]: 如果 https://github.com/tc39/proposal-cancelable-promises 正式通过,那么还会增加一个状态。 -[^3]: Observable 可以分为 Cold Observable 和 Hot Observable,Cold Observable 只有被订阅后才开始产生事件,比如封装了 Http 的 Observable,而 Hot Observable 始终产生事件,比如封装了某元素 Click 事件的 Observable。 -[^4]: 仅供表意的实现版本,并没有经过严格验证,请勿直接用于实际项目中。 -[^5]: 目前仍然是 Stage 3 的提案(https://github.com/tc39/proposal-async-iteration),有望进入 ES2017 中。 From c9e34c0f0c860aaf53ec7755fc719ca89b8a3066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=81=E4=B9=90=E5=8D=8E?= Date: Thu, 13 Oct 2016 14:12:19 +0800 Subject: [PATCH 005/177] new article about RxJS --- src/app/_shared/api/articles/index.ts | 9 +++++++++ src/app/_shared/api/authors/index.ts | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 77dbb3b..801ddec 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -210,6 +210,15 @@ const items: Article[] = [ tags: ['ts'], authors: ['袁志'], }, + { + id: 'RxJS Overview阅读笔记', + title: 'RxJS Overview阅读笔记', + summary: 'RxJS 是事件监听与Promise的组合,同时提供了丰富的操作返回数据的接口。', + content: require('./250.RxJS Overview阅读笔记/_index.md'), + first: true, + tags: ['RxJS'], + authors: ['lhtin'], + }, ]; @Injectable() diff --git a/src/app/_shared/api/authors/index.ts b/src/app/_shared/api/authors/index.ts index 84f2f5c..0738a1f 100644 --- a/src/app/_shared/api/authors/index.ts +++ b/src/app/_shared/api/authors/index.ts @@ -40,6 +40,15 @@ const items: Author[] = [ avatar: require('./_images/王传业.jpg'), columnist: false, homepage: 'https://csser.me/' + }, + { + id: 'lhtin', + name: '丁乐华', + bio: 'Why didn\'t the spider go to school? Because she learned everything on the web.', + description: require('./250.丁乐华.md'), + avatar: require('./_images/250.丁乐华.md'), + columnist: false, + homepage: 'https://github.com/lhtin' } ]; @Injectable() From 1c8408124d6f41f1644b52b8016413f41bb3357e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=81=E4=B9=90=E5=8D=8E?= Date: Thu, 13 Oct 2016 14:15:48 +0800 Subject: [PATCH 006/177] new article about RxJS --- .../_index.md" | 189 ++++++++++++++++++ ...0.\344\270\201\344\271\220\345\215\216.md" | 3 + ....\344\270\201\344\271\220\345\215\216.jpg" | Bin 0 -> 84904 bytes 3 files changed, 192 insertions(+) create mode 100644 "src/app/_shared/api/articles/250.RxJS Overview\351\230\205\350\257\273\347\254\224\350\256\260/_index.md" create mode 100644 "src/app/_shared/api/authors/250.\344\270\201\344\271\220\345\215\216.md" create mode 100644 "src/app/_shared/api/authors/_images/250.\344\270\201\344\271\220\345\215\216.jpg" diff --git "a/src/app/_shared/api/articles/250.RxJS Overview\351\230\205\350\257\273\347\254\224\350\256\260/_index.md" "b/src/app/_shared/api/articles/250.RxJS Overview\351\230\205\350\257\273\347\254\224\350\256\260/_index.md" new file mode 100644 index 0000000..f89e33a --- /dev/null +++ "b/src/app/_shared/api/articles/250.RxJS Overview\351\230\205\350\257\273\347\254\224\350\256\260/_index.md" @@ -0,0 +1,189 @@ +# *RxJS Overview* 阅读笔记 + +*RxJS Overview*为官方对RxJS的一个概述,点击[这里](http://reactivex.io/rxjs/manual/overview.html)进行原文阅读。 + +## 前言 + +本文是阅读*RxJS Overview*所做的笔记。该概述写的非常之清晰和简洁,是很好的初学RxJS入门资料。概述内容包括:**RxJS涉及到的主要概念及概念相关的必要背景知识**,其中主要概念包括:Observable、Observer、Subscription、Subject、Operator、Scheduler,本文会一一进行介绍。尤其是那些时不时出现的手书斜体格式的总结文字,非常值得认真思考的。本文尝试进行总结,力求把RxJS的核心思想表达清楚。 + +用一句话介绍RxJS的话,就是**RxJS将异步抽象为数据流,并提供对数据流进行各种操作的接口**。 + +## 数据传输 + +数据从生产者传输到消费者那里,有两种方式:一是消费者从生产者那里拉取(**pull**)数据,二是生产者推送(**push**)数据给消费者。前者就是常见的函数调用(消费者调用生产数据的函数),后者则是用于处理异步的回调方式(消费者只定义接受数据的函数,然后供生产者调用),也就是由哪一方去主动调用。如下代码所示: + +```js +// 拉取式 +var producer = function () { + var data = 42; + return data; +} +var consumer = function () { + // 数据消费者主动调用数据生产函数 + var data = producer(); + // 可以消费数据了 +} +// 直接获取数据并进行消费 +consumer(); +``` + +```js +// 推送式 +var producer = function (consumer) { + setTimeout(function () { + var data = 42; + // 数据生产者推送数据给数据消费者 + consumer(data); + }, 3000) +} +var consumer = function (data) { + // 可以消费数据了 +} +// 等到异步数据准备好时,就会调用消费者 +// 调用之后才可以消费数据 +producer(consumer); +``` + +拉取的方式,常用在获取同步数据上;而推送的方式,则更多用在获取异步数据上。会有异步数据这个说法,是因为有些数据的获取需要等待(比如浏览器通过URL接口获取服务器上的数据)。如果数据消费者在原地傻傻地等着数据,而不去做其他的事情,必然导致效率低下。正确的做法是在数据还没有到的时候去做其他的事情,等数据到了再来通知消费者。 + +在获取异步数据上面,常见的有事件监听和Promise(都是通过回调)。区别是事件监听可以触发多次回调,一个Promise只能触发一次回调。**一次和多次更深层次的区别,在于生产者可以有多少个返回值**。RxJS是两者的结合,**提供了Promise形式的异步编程方式(看起来像同步),但又有多个返回值**。对比以下代码就很容易理解上一句话了: + +```js +// 事件监听 +button.addEventListener('click', function (event) { + // 触发回调的时机是该元素被点击了 + // 现在可以消费数据event了 +}) + +// Promise +var promise = new Promise(function (resolve, reject) { + setTimeout(function () { + var data = 42; + resolve(data); + }, 3000); +}); +promise.then(function (data) { + // 可以开始消费数据data了 +}); + +// RxJS +var observable = Rx.Observable.fromEvent(button, 'click'); +observable.subscribe(function (event) { + // 可以开始消费数据event了 +}) +``` + +## 基本概念 + +**除了拥有对异步处理能力,RxJS还提供了对生产的数据的进行常见操作的接口,以及提供不同的触发回调的策略(比如同步、异步等)**。理解RxJS的概念有利于更好地利用它,接下来介绍RxJS所包含的基本概念。 + +### Observable + +使用RxJS的第一步就是得到一个Observable,Observable是一个含有数据生产过程的对象。Observable的特点是不主动运行数据生产过程,而是需要被启动(懒运算)。同时它可以被多次启动,并且每次启动得到的对象没有任何关系。 + +**没有任何关系**的意思是回调独享一份数据,不同启动中的回调不共享数据。且看如下代码(展示Observable中回调独享数据的特点): + +```js +var observable = Rx.Observable.create(function (observer) { + observer.next({ + a: 1, + b: 2 + }); +}); +observable.subscribe({ + next: function (data) { + console.log(data.a); // 输出 1 + data.a = 3; + } +}); +observable.subscribe({ + next: function (data) { + console.log(data.a); // 输出 1 + data.a = 3; + } +}); +``` + +### Observer + +Observer是一个包含回调函数的对象(可包含`next`、`complete`、`error`三种回调),比较好理解。例如上面在调用`subscribe`时所传入的参数,就是一个Observer。 + +### Subscription + +Subscription是调用Observable的启动生产数据过程的方法(比如`subscribe`)所返回的对象,表示Observable的执行过程。这个过程可以被取掉。 + +### Subject + +Subject是Observable的一个变体,区别是Subject只能启动一次,而Observable可以被多次启动。这就意味着数据在所有的回调中共享。另外一点区别是后添加的回调无法处理生产数据过程之前产生的数据。且看如下代码(展示Subject中回调共享数据的特点): + +```js +var subject = new Rx.Subject(); +subject.subscribe({ + next: function (data) { + console.log(data.a); // 输出 3 + data.a = 3; + } +}); +subject.subscribe({ + next: function (data) { + console.log(data.a); // 输出 3 + } +}); +subject.next({ + a: 1, + b: 2 +}); +``` + +### Operator + +Operator是操作异步数据的方法,其返回另一个Observable对象,可链式调用。常见的操作有处理数据(`map`)、过滤数据(`filter`)、累积数据(`reduce`)。例如以下示例代码: + +```js +Rx.Observable.of(0, 1, 2, 3) + .map((n) => n * n) // 每项取平方 + .filter((n) => n > 0) // 取出平方后大于0的项 + .reduce((acc, curr) => acc + curr, 0) // 累加每一项 + .subscribe((sum) => console.log(sum)); // 输出 14,等于1*1 + 2*2 + 3*3 +``` + +### Scheduler + +Scheduler指触发回调的策略,是一个对象。这里的策略,控制了触发回调的时机。比如把触发放到下一次事件循环里面去。以下代码展示了使用`async`策略的运行结果(重点在于使用`async`策略会异步触发回调,): + +```js +var observable = Rx.Observable.create(function (observer) { + console.log('a'); + observer.next(1); + console.log('b'); + observer.complete(); + console.log('c'); +}).observeOn(Rx.Scheduler.async); + +console.log('before'); +observable.subscribe({ + next: (x) => console.log(x), + complete: () => console.log('done'), +}); +console.log('after'); +``` + +输出顺序如下: + +``` +before +a +b +c +after +1 +done +``` + +由于目前JS解释器都是单线程运行JS代码,Scheduler的作用局限于提供异步等策略。但是在Rx.NET等服务端的实现中,Scheduler有非常大的作用,比如可以将耗时的任务放到新的线程中,从而提高主线程的响应速度。对这部分感兴趣的同学可以去阅读Rx的服务端实现,比如Rx.NET。 + +## 总结 + +本文主要介绍了RxJS中涉及到的基本概念,并提供代码示例。理解这些概念是使用好RxJS的基础,同时RxJS包含了丰富的Operator。在解决实际问题时,对这些Operator的理解会有利于找到快速高效的解决方法。如果你打算继续深入学习RxJS的话,建议从Operator入手,并结合实际问题。 + +现遗留下来的问题是:为什么要使用RxJS?RxJS适合哪些问题?这些是下一篇RxJS文章所涉及到的内容,敬请期待。 \ No newline at end of file diff --git "a/src/app/_shared/api/authors/250.\344\270\201\344\271\220\345\215\216.md" "b/src/app/_shared/api/authors/250.\344\270\201\344\271\220\345\215\216.md" new file mode 100644 index 0000000..cd00915 --- /dev/null +++ "b/src/app/_shared/api/authors/250.\344\270\201\344\271\220\345\215\216.md" @@ -0,0 +1,3 @@ +- 吭哧吭哧的前端学习者 + +- 爱好计算机、经济解释、音乐、徒步 \ No newline at end of file diff --git "a/src/app/_shared/api/authors/_images/250.\344\270\201\344\271\220\345\215\216.jpg" "b/src/app/_shared/api/authors/_images/250.\344\270\201\344\271\220\345\215\216.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..03daf9872ccfa17365a2f82f757031dbbb7eba97 GIT binary patch literal 84904 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%0DbvuUkOzbiB!iZ0#y_==te9`{RT*E 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 Date: Thu, 13 Oct 2016 14:16:24 +0800 Subject: [PATCH 007/177] change author avatar --- src/app/_shared/api/authors/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/_shared/api/authors/index.ts b/src/app/_shared/api/authors/index.ts index 0738a1f..c89b8ab 100644 --- a/src/app/_shared/api/authors/index.ts +++ b/src/app/_shared/api/authors/index.ts @@ -46,7 +46,7 @@ const items: Author[] = [ name: '丁乐华', bio: 'Why didn\'t the spider go to school? Because she learned everything on the web.', description: require('./250.丁乐华.md'), - avatar: require('./_images/250.丁乐华.md'), + avatar: require('./_images/250.丁乐华.jpg'), columnist: false, homepage: 'https://github.com/lhtin' } From b3492bc0e5ecc655a2005aedfb77070e4bd446fa Mon Sep 17 00:00:00 2001 From: Zhicheng Wang Date: Sat, 15 Oct 2016 19:45:55 +0800 Subject: [PATCH 008/177] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=9D=82=E8=B0=88?= =?UTF-8?q?=EF=BC=9A=E4=BD=95=E4=B8=8D=E9=A3=9F=E8=82=89=E7=B3=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_readme.md" | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 "src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" diff --git "a/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" "b/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" new file mode 100644 index 0000000..287faa6 --- /dev/null +++ "b/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" @@ -0,0 +1,19 @@ +# 杂谈:何不食肉糜? + +## 历史 + +晋朝。某年大旱。 + +老百姓没有粮食吃,被迫吃草根、树皮、观音土充饥。皇宫中照样歌舞升平。当大臣来报告这场饥荒时,晋惠帝真是为老百姓操碎了心:“老百姓都没有粮食吃了?那岂不是要饿死了?他们怎么不吃皮蛋瘦肉粥呢?” + +别笑。晋惠帝是认真的。在那个门阀分明的时代,晋惠帝可谓是精英中的精英,顶级精英。然而,他自小在深宫长大,无法看见平常人家的生活,无法理解平民的喜怒哀乐。不过,把这些归于晋惠帝的“白痴”、“无良”也不够公允。 + +事实上,这是那个时代的常态。语文课上,我们可能学过“王凯与石崇斗富”,这只是晋朝积重难返的一个缩影。其根本原因在于阶层的固化和互不理解。 + +这种阶层固化不但让上层大乱斗,成为八王之乱的诱因。但这还只是小问题,更严重的是它撕裂了社会,让晋朝在面对游牧民族入侵时毫无还手之力。底层人民并不认为这是自己的国家,因此连一个“岳飞”也没出过。史家称这段悲剧为“五胡乱华”,但其根本原因并不在五胡,而在于当时“精英群体”的自私、自恋与短视。 + +## 感想 + +当社会走向沉沦,没有人能置身事外。中国历史上几乎每个最黑暗的时代都是阶层撕裂最严重的时代。这不是巧合。历史早已证明,任何灾难都无法击垮中华民族,我们的文化从未中断,有着全世界最多的古代文献。然而,俗话说“不作不死”,而阶层撕裂正是一个民族的“作死”行为,无可救药。 + +作为程序员,在全国的范围内其实已经是精英了,随着技术的发展,对社会的影响力也会越来越大。你们已经或者迟早会成为中产阶级。但中产阶级的标识不只是财富,更重要的是责任感。在中国文化中,与“中产阶级”最像的是“士” —— 大丈夫立于天地间,铁肩担道义,妙手著文章。 From dc12acd5bfe3bddda174f49854346e9f04e2d567 Mon Sep 17 00:00:00 2001 From: Zhicheng Wang Date: Sat, 15 Oct 2016 20:02:15 +0800 Subject: [PATCH 009/177] =?UTF-8?q?=E6=9A=82=E6=97=B6=E7=A6=81=E7=94=A8?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E6=A3=80=E6=9F=A5=EF=BC=8C=E6=8E=92=E6=9F=A5?= =?UTF-8?q?CI=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/webpack.common.js | 66 ++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/config/webpack.common.js b/config/webpack.common.js index dbe5de4..abae363 100644 --- a/config/webpack.common.js +++ b/config/webpack.common.js @@ -35,14 +35,14 @@ const METADATA = { module.exports = function (options) { isProd = options.env === 'production'; return { - + /* * Static metadata for index.html * * See: (custom attribute) */ metadata: METADATA, - + /* * Cache generated modules and chunks to improve performance for multiple incremental builds. * This is enabled by default in watch mode. @@ -51,7 +51,7 @@ module.exports = function (options) { * See: http://webpack.github.io/docs/configuration.html#cache */ //cache: false, - + /* * The entry point for the bundle * Our Angular.js app @@ -59,39 +59,39 @@ module.exports = function (options) { * See: http://webpack.github.io/docs/configuration.html#entry */ entry: { - + 'polyfills': './src/polyfills.ts', 'vendor': './src/vendor.ts', 'main': './src/main.ts' - + }, - + /* * Options affecting the resolving of modules. * * See: http://webpack.github.io/docs/configuration.html#resolve */ resolve: { - + /* * An array of extensions that should be used to resolve modules. * * See: http://webpack.github.io/docs/configuration.html#resolve-extensions */ extensions: ['', '.ts', '.js', '.json'], - + // An array of directory names to be resolved to the current directory modules: [helpers.root('src'), 'node_modules'], - + }, - + /* * Options affecting the normal modules. * * See: http://webpack.github.io/docs/configuration.html#module */ module: { - + /* * An array of applied pre and post loaders. * @@ -108,9 +108,9 @@ module.exports = function (options) { }, include: [helpers.root('src')] }, - + ], - + /* * An array of automatically applied loaders. * @@ -120,7 +120,7 @@ module.exports = function (options) { * See: http://webpack.github.io/docs/configuration.html#module-loaders */ loaders: [ - + /* * Typescript loader support for .ts and Angular 2 async routes via .async.ts * Replace templateUrl and stylesUrl with require() @@ -132,13 +132,13 @@ module.exports = function (options) { test: /\.ts$/, loaders: [ '@angularclass/hmr-loader?pretty=' + !isProd + '&prod=' + isProd, - 'awesome-typescript-loader', + 'awesome-typescript-loader?doTypeCheck=false', 'angular2-template-loader', 'angular2-router-loader', ], exclude: [/\.(spec|e2e)\.ts$/] }, - + /* * Json loader support for *.json files. * @@ -148,7 +148,7 @@ module.exports = function (options) { test: /\.json$/, loader: 'json-loader' }, - + /* * to string and css loader support for *.css files * Returns file content as string @@ -158,17 +158,17 @@ module.exports = function (options) { test: /\.css$/, loaders: ['to-string', 'css'] }, - + { test: /\.scss$/, loaders: ["to-string", "css?sourceMap", "sass?sourceMap"] }, - + { test: /main\.scss$/, loader: ExtractTextPlugin.extract({ fallbackLoader: 'style-loader', loader: 'css-loader!sass-loader?sourceMap' }) }, - + /* Raw loader support for *.html * Returns file content as string * @@ -179,7 +179,7 @@ module.exports = function (options) { loader: 'html!markup-inline', exclude: [helpers.root('src/index.html')] }, - + {test: /\.(md|markdown)$/, loader: 'html!markup-inline!markdown-it'}, {test: /\.(pug|jade)$/, loader: 'html!markup-inline!jade-html'}, /* File loader for supporting images, for example, in CSS files. @@ -192,7 +192,7 @@ module.exports = function (options) { loader: 'url' } ], - + postLoaders: [ { test: /\.js$/, @@ -205,7 +205,7 @@ module.exports = function (options) { } ] }, - + 'markdown-it': { preset: 'default', typographer: true, @@ -221,7 +221,7 @@ module.exports = function (options) { require('markdown-it-mark'), ] }, - + /* * Add additional plugins to the compiler. * @@ -229,13 +229,13 @@ module.exports = function (options) { */ plugins: [ new ExtractTextPlugin({filename: 'css/[name]_[hash].css', allChunks: true}), - + new AssetsPlugin({ path: helpers.root('dist'), filename: 'webpack-assets.json', prettyPrint: true }), - + /* * Plugin: ForkCheckerPlugin * Description: Do type checking in a separate process, so webpack don't need to wait. @@ -254,7 +254,7 @@ module.exports = function (options) { new webpack.optimize.CommonsChunkPlugin({ name: ['polyfills', 'vendor'].reverse() }), - + /** * Plugin: ContextReplacementPlugin * Description: Provides context to Angular's use of System.import @@ -267,7 +267,7 @@ module.exports = function (options) { /angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/, helpers.root('src') // location of your src ), - + /* * Plugin: CopyWebpackPlugin * Description: Copy files and directories in webpack. @@ -290,7 +290,7 @@ module.exports = function (options) { }, { from: 'src/assets/humans.txt' }]), - + /* * Plugin: HtmlWebpackPlugin * Description: Simplifies creation of HTML files to serve your webpack bundles. @@ -303,7 +303,7 @@ module.exports = function (options) { template: 'src/index.html', chunksSortMode: 'dependency' }), - + /* * Plugin: HtmlHeadConfigPlugin * Description: Generate html tags based on javascript maps. @@ -329,9 +329,9 @@ module.exports = function (options) { new HtmlElementsPlugin({ headTags: require('./head-config.common') }), - + ], - + /* * Include polyfills or mocks for various node stuff * Description: Node configuration @@ -346,6 +346,6 @@ module.exports = function (options) { clearImmediate: false, setImmediate: false } - + }; } From 65a417b4be7e4e03b5745fb4f0ed565657e49ad7 Mon Sep 17 00:00:00 2001 From: Zhicheng Wang Date: Sat, 15 Oct 2016 20:48:44 +0800 Subject: [PATCH 010/177] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BA=86readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +----- .../_readme.md" | 16 +++++++++------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index fd259f7..a2b5e8b 100644 --- a/README.md +++ b/README.md @@ -17,11 +17,7 @@ Angular 2 `cnpm install` -运行`npm start`命令,启动完成后会在启动一个开发服务器。 - -## 工具 - -运行`npm run g c name-action`可以创建`src/app/name/action.*`文件,内含`NameActionComponent`组件,并自动加入NgModule中。 +运行`npm start`命令,启动完成后会在启动一个开发服务器。 ## 重要!!!投稿指南! diff --git "a/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" "b/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" index 287faa6..3b216d0 100644 --- "a/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" +++ "b/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" @@ -2,18 +2,20 @@ ## 历史 -晋朝。某年大旱。 +晋朝某年。大旱。 -老百姓没有粮食吃,被迫吃草根、树皮、观音土充饥。皇宫中照样歌舞升平。当大臣来报告这场饥荒时,晋惠帝真是为老百姓操碎了心:“老百姓都没有粮食吃了?那岂不是要饿死了?他们怎么不吃皮蛋瘦肉粥呢?” +老百姓没有粮食吃,被迫吃草根、树皮、观音土充饥。饿殍遍地。皇宫中照样歌舞升平。当大臣来报告这场饥荒时,晋惠帝真是为老百姓操碎了心:“老百姓都没有粟米吃了?那岂不是要饿死了?”,然后疑惑地问道:“他们怎么不吃肉粥呢?” -别笑。晋惠帝是认真的。在那个门阀分明的时代,晋惠帝可谓是精英中的精英,顶级精英。然而,他自小在深宫长大,无法看见平常人家的生活,无法理解平民的喜怒哀乐。不过,把这些归于晋惠帝的“白痴”、“无良”也不够公允。 +别笑。晋惠帝是认真的。在那个门阀分明的时代,晋惠帝可谓是精英中的精英,顶级精英。然而,他自幼在深宫长大,无法看见平常人家的生活,无法理解平民的喜怒哀乐,甚至都不知道肉是从哪里来的。 -事实上,这是那个时代的常态。语文课上,我们可能学过“王凯与石崇斗富”,这只是晋朝积重难返的一个缩影。其根本原因在于阶层的固化和互不理解。 +不过,把这些归于晋惠帝的“白痴”、“无良”也不够公允。事实上,这是那个时代的常态。语文课上,我们可能学过“王凯与石崇斗富”,这只是晋朝积重难返的一个缩影。其根本原因在于阶层的固化和互不理解。 -这种阶层固化不但让上层大乱斗,成为八王之乱的诱因。但这还只是小问题,更严重的是它撕裂了社会,让晋朝在面对游牧民族入侵时毫无还手之力。底层人民并不认为这是自己的国家,因此连一个“岳飞”也没出过。史家称这段悲剧为“五胡乱华”,但其根本原因并不在五胡,而在于当时“精英群体”的自私、自恋与短视。 +这种阶层固化不但触发了上层大乱斗,成为八王之乱的主因,更严重的是它撕裂了社会,让晋朝在面对游牧民族入侵时毫无还手之力。底层人民受尽了歧视,因此并不认为这是自己的国家,连一个“岳飞”都不曾出过。孟子曰“君视民如草芥,则民视君如寇仇”。史家称这段悲剧为“五胡乱华”,但我认为其根本原因并不在于“五胡”,而源自当时“精英群体”的自私、自恋与短视。 ## 感想 -当社会走向沉沦,没有人能置身事外。中国历史上几乎每个最黑暗的时代都是阶层撕裂最严重的时代。这不是巧合。历史早已证明,任何灾难都无法击垮中华民族,我们的文化从未中断,有着全世界最多的古代文献。然而,俗话说“不作不死”,而阶层撕裂正是一个民族的“作死”行为,无可救药。 +当社会走向沉沦,没有人能置身事外。中国历史上几乎每个最黑暗的时代都是阶层撕裂最严重的时代。这不是巧合。俗话说“不作不死”,阶层撕裂正是一个民族的典型“作死”行为,无可救药。 -作为程序员,在全国的范围内其实已经是精英了,随着技术的发展,对社会的影响力也会越来越大。你们已经或者迟早会成为中产阶级。但中产阶级的标识不只是财富,更重要的是责任感。在中国文化中,与“中产阶级”最像的是“士” —— 大丈夫立于天地间,铁肩担道义,妙手著文章。 +也许你不觉得,但作为程序员,我们在全国范围内其实已经得算是精英了。随着软件技术渗透到社会的每一个角落,我们对社会的影响力也必然越来越大。你们已经或者迟早会成为中产阶级。但中产阶级的标识不只是财富,更重要的是担当和社会责任。在中国传统文化中,与“中产阶级”最像的是“士” —— 大丈夫立于天地间,铁肩担道义,妙手著文章。 + +值得庆幸的是,我们这些人,大多是从底层成长起来的,不至于像晋惠帝一样把“何不食肉糜”当做理所当然的事。睁开你的双眼, From 3c58c53fb42bf722ecc1f306657c1a12e5852104 Mon Sep 17 00:00:00 2001 From: Zhicheng Wang Date: Sat, 15 Oct 2016 21:50:14 +0800 Subject: [PATCH 011/177] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BA=86=E6=9D=82?= =?UTF-8?q?=E8=B0=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_readme.md" | 33 ++++++++++++++---- .../logo.jpg" | Bin 0 -> 26295 bytes src/app/_shared/api/articles/index.ts | 9 +++++ 3 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 "src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/logo.jpg" diff --git "a/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" "b/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" index 3b216d0..43f2276 100644 --- "a/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" +++ "b/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" @@ -1,21 +1,40 @@ # 杂谈:何不食肉糜? +![儒](./logo.jpg) + ## 历史 晋朝某年。大旱。 -老百姓没有粮食吃,被迫吃草根、树皮、观音土充饥。饿殍遍地。皇宫中照样歌舞升平。当大臣来报告这场饥荒时,晋惠帝真是为老百姓操碎了心:“老百姓都没有粟米吃了?那岂不是要饿死了?”,然后疑惑地问道:“他们怎么不吃肉粥呢?” +老百姓没有粮食吃,被迫吃草根、树皮、观音土充饥。饿殍遍地。皇宫中照样歌舞升平。当大臣来报告这场饥荒时,晋惠帝真是为老百姓操碎了心:“老百姓都没有粟米吃了?那岂不是要饿死?”,过了一会儿他又疑惑地问道:“他们怎么不吃肉粥呢?” -别笑。晋惠帝是认真的。在那个门阀分明的时代,晋惠帝可谓是精英中的精英,顶级精英。然而,他自幼在深宫长大,无法看见平常人家的生活,无法理解平民的喜怒哀乐,甚至都不知道肉是从哪里来的。 +别笑。晋惠帝是认真的。在那个门阀分明的时代,晋惠帝可谓是精英中的精英,顶级精英。然而,他自幼在深宫长大,无法看见寻常人家的生活,无法理解平民的喜怒哀乐,甚至都不知道肉是从哪里来的。 -不过,把这些归于晋惠帝的“白痴”、“无良”也不够公允。事实上,这是那个时代的常态。语文课上,我们可能学过“王凯与石崇斗富”,这只是晋朝积重难返的一个缩影。其根本原因在于阶层的固化和互不理解。 +不过,把这些归于晋惠帝的“白痴”、“无良”也有失公允。事实上,这是那个时代的常态。语文课上,我们可能学过“王凯与石崇斗富”,这只是晋朝积重难返的一个缩影。其根本原因在于阶层的固化。 -这种阶层固化不但触发了上层大乱斗,成为八王之乱的主因,更严重的是它撕裂了社会,让晋朝在面对游牧民族入侵时毫无还手之力。底层人民受尽了歧视,因此并不认为这是自己的国家,连一个“岳飞”都不曾出过。孟子曰“君视民如草芥,则民视君如寇仇”。史家称这段悲剧为“五胡乱华”,但我认为其根本原因并不在于“五胡”,而源自当时“精英群体”的自私、自恋与短视。 +这种阶层固化不但触发了上层大乱斗,成为八王之乱的主因,更严重的是它撕裂了社会,让晋朝在面对游牧民族入侵时毫无还手之力。底层人民受尽了歧视,因此并不认为这是自己的国家,连一个“岳飞”都不曾出过。孟子曰“君视民如草芥,则民视君如寇仇”。史家称这段悲剧为“五胡乱华”,但我认为其根本原因并不在于“五胡”,而源自当时“精英群体”的自私、自恋与短视。“旧时王谢堂前燕,飞入寻常百姓家”,活该! -## 感想 +## 现实 当社会走向沉沦,没有人能置身事外。中国历史上几乎每个最黑暗的时代都是阶层撕裂最严重的时代。这不是巧合。俗话说“不作不死”,阶层撕裂正是一个民族的典型“作死”行为,无可救药。 -也许你不觉得,但作为程序员,我们在全国范围内其实已经得算是精英了。随着软件技术渗透到社会的每一个角落,我们对社会的影响力也必然越来越大。你们已经或者迟早会成为中产阶级。但中产阶级的标识不只是财富,更重要的是担当和社会责任。在中国传统文化中,与“中产阶级”最像的是“士” —— 大丈夫立于天地间,铁肩担道义,妙手著文章。 +也许你自己不觉得,但作为程序员,我们大多数人在全国范围内收入其实已经处于前5%了(因为贫富差距过大)。随着软件技术渗透到社会的每一个角落,我们对社会的影响力也会随之越来越大。只要没有意外,那么我们已经或者迟早都会成为中产阶级。但中产阶级并不只意味着财富,更重要的是道义担当与社会责任。在中国传统文化中,讲究的是:大丈夫立于天地间,“铁肩担道义,妙手著文章”。 + +值得庆幸的是,我们这些人大多是从底层成长起来的,不至于像晋惠帝一样把“何不食肉糜”当做理所当然的事。请让自己和后人始终保持睁开眼睛看世界,而不要成为晋惠帝。 + +我们力量有限,但不等于无能为力。 + +首先,不作恶。假如你为生活所迫,不得不为作恶者工作,请至少提高作恶者的成本 —— 对作恶者,请把你的心理价位提高50%,只要所有程序员都有这个共识,那么就能形成一种事实性的爱心罚款。 + +其次,不要歧视。有很多人因为各种原因而无法得到良好的教育,尽力去帮助他们,而不要鄙视或者认为他们只是不学无术。这世上真的曾有人因为一千块钱的学费而放弃了大学梦。 + +最后,Just do IT。是的,只要合理使用,那么信息技术就能让社会变得更加平等。阶层固化的来源往往是信息不畅,请用你的业余时间,去帮助别人消除各种信息的藩篱。 +而这也是我当初每天花三个小时的业余时间去翻译Angular 2官方文档的根本动力。 +限于英语水平,有很多人(包括我)无法顺畅地通过英文获取最新信息。 +也许有人觉得“活该,谁叫你不好好学英语呢?”,但我鄙视这种“何不食肉糜”的心态。 +我相信:任何人,只要他有梦想,就值得我们去帮助。即使他真的曾经荒废学业,也不应该让这些过往成为他现在被歧视的理由。他会去学英语,但他现在急需一份好工作。 +有人说:种一棵树,最好的时间是十年前,其次,是现在。所以,Just do it,从一点一滴开始,从身边开始,让社会变得更美好,这样我们才能不被阶层撕裂导致的黑暗时代所吞噬。 + +我们都是一颗水滴,但我们都有一颗滚滚向前的心。 -值得庆幸的是,我们这些人,大多是从底层成长起来的,不至于像晋惠帝一样把“何不食肉糜”当做理所当然的事。睁开你的双眼, +向每一位志同道合的人致敬。 diff --git "a/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/logo.jpg" "b/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/logo.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..341b4d21be7b4be4d4d02026fee1bf46078d6989 GIT binary patch literal 26295 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 h9V literal 0 HcmV?d00001 diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 1390aab..6f19149 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -210,6 +210,15 @@ const items: Article[] = [ tags: ['ts'], authors: ['袁志'], }, + { + id: '杂谈:何不食肉糜?', + title: '杂谈:何不食肉糜?', + summary: '今天,我们不谈技术。来聊点八卦吧,雪狼的第一重身份其实是儒生,他为什么选择翻译官方文档?因为这源于儒者的信仰。请听我细说从头。', + content: require('./190.杂谈:何不食肉糜?/_readme.md'), + first: true, + tags: ['过去'], + authors: ['雪狼'], + }, ]; @Injectable() From cf5ae97811e570e7047b260f9166acba4ba20fb4 Mon Sep 17 00:00:00 2001 From: Zhicheng Wang Date: Sat, 15 Oct 2016 21:56:27 +0800 Subject: [PATCH 012/177] =?UTF-8?q?=E6=8D=A2=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_readme.md" | 2 +- .../logo.jpg" | Bin 26295 -> 0 bytes .../logo.png" | Bin 0 -> 47552 bytes 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 "src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/logo.jpg" create mode 100644 "src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/logo.png" diff --git "a/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" "b/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" index 43f2276..cb36d8c 100644 --- "a/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" +++ "b/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" @@ -1,6 +1,6 @@ # 杂谈:何不食肉糜? -![儒](./logo.jpg) +![儒](./logo.png) ## 历史 diff --git "a/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/logo.jpg" "b/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/logo.jpg" deleted file mode 100644 index 341b4d21be7b4be4d4d02026fee1bf46078d6989..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26295 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 h9V diff --git "a/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/logo.png" "b/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/logo.png" new file mode 100644 index 0000000000000000000000000000000000000000..f5a7aaa3d8b855140b116747e6a7833f3db151b9 GIT binary patch literal 47552 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 mfx-*r)c@_6Au?$xchwyRZx!XGJn|(2|E_52UMM Date: Sun, 16 Oct 2016 07:57:39 +0800 Subject: [PATCH 013/177] =?UTF-8?q?=E5=86=85=E5=AE=B9=E5=BE=AE=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_readme.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" "b/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" index cb36d8c..c4bae09 100644 --- "a/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" +++ "b/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" @@ -14,10 +14,10 @@ 这种阶层固化不但触发了上层大乱斗,成为八王之乱的主因,更严重的是它撕裂了社会,让晋朝在面对游牧民族入侵时毫无还手之力。底层人民受尽了歧视,因此并不认为这是自己的国家,连一个“岳飞”都不曾出过。孟子曰“君视民如草芥,则民视君如寇仇”。史家称这段悲剧为“五胡乱华”,但我认为其根本原因并不在于“五胡”,而源自当时“精英群体”的自私、自恋与短视。“旧时王谢堂前燕,飞入寻常百姓家”,活该! -## 现实 - 当社会走向沉沦,没有人能置身事外。中国历史上几乎每个最黑暗的时代都是阶层撕裂最严重的时代。这不是巧合。俗话说“不作不死”,阶层撕裂正是一个民族的典型“作死”行为,无可救药。 +## 现实 + 也许你自己不觉得,但作为程序员,我们大多数人在全国范围内收入其实已经处于前5%了(因为贫富差距过大)。随着软件技术渗透到社会的每一个角落,我们对社会的影响力也会随之越来越大。只要没有意外,那么我们已经或者迟早都会成为中产阶级。但中产阶级并不只意味着财富,更重要的是道义担当与社会责任。在中国传统文化中,讲究的是:大丈夫立于天地间,“铁肩担道义,妙手著文章”。 值得庆幸的是,我们这些人大多是从底层成长起来的,不至于像晋惠帝一样把“何不食肉糜”当做理所当然的事。请让自己和后人始终保持睁开眼睛看世界,而不要成为晋惠帝。 From 0c41fb306ae72da74742d0adb640f44fe167d687 Mon Sep 17 00:00:00 2001 From: Zhicheng Wang Date: Sun, 16 Oct 2016 08:00:42 +0800 Subject: [PATCH 014/177] =?UTF-8?q?=E5=86=85=E5=AE=B9=E5=BE=AE=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_readme.md" | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git "a/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" "b/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" index c4bae09..63b0d66 100644 --- "a/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" +++ "b/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" @@ -26,15 +26,13 @@ 首先,不作恶。假如你为生活所迫,不得不为作恶者工作,请至少提高作恶者的成本 —— 对作恶者,请把你的心理价位提高50%,只要所有程序员都有这个共识,那么就能形成一种事实性的爱心罚款。 -其次,不要歧视。有很多人因为各种原因而无法得到良好的教育,尽力去帮助他们,而不要鄙视或者认为他们只是不学无术。这世上真的曾有人因为一千块钱的学费而放弃了大学梦。 +其次,不要歧视。有很多人因为各种原因而无法得到良好的教育,尽力去帮助他们,而不要鄙视或者认为他们只是不学无术。这世上有很多人因为凑不齐学费而放弃了大学梦。 最后,Just do IT。是的,只要合理使用,那么信息技术就能让社会变得更加平等。阶层固化的来源往往是信息不畅,请用你的业余时间,去帮助别人消除各种信息的藩篱。 而这也是我当初每天花三个小时的业余时间去翻译Angular 2官方文档的根本动力。 限于英语水平,有很多人(包括我)无法顺畅地通过英文获取最新信息。 也许有人觉得“活该,谁叫你不好好学英语呢?”,但我鄙视这种“何不食肉糜”的心态。 我相信:任何人,只要他有梦想,就值得我们去帮助。即使他真的曾经荒废学业,也不应该让这些过往成为他现在被歧视的理由。他会去学英语,但他现在急需一份好工作。 -有人说:种一棵树,最好的时间是十年前,其次,是现在。所以,Just do it,从一点一滴开始,从身边开始,让社会变得更美好,这样我们才能不被阶层撕裂导致的黑暗时代所吞噬。 +有人说:种一棵树,最好的时间是十年前,其次,是现在。所以,Just do it!从一点一滴开始,从身边开始,让社会变得更美好,这样我们才能不被阶层撕裂导致的黑暗时代所吞噬。 -我们都是一颗水滴,但我们都有一颗滚滚向前的心。 - -向每一位志同道合的人致敬。 +我们都是水滴,但我们都有一颗滚滚向前的心。 From 977997100d4070a7e3ca8f8e1eff0c68afd65149 Mon Sep 17 00:00:00 2001 From: Zhicheng Wang Date: Sun, 16 Oct 2016 12:34:04 +0800 Subject: [PATCH 015/177] =?UTF-8?q?=E5=86=85=E5=AE=B9=E5=BE=AE=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_readme.md" | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git "a/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" "b/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" index 63b0d66..def6f74 100644 --- "a/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" +++ "b/src/app/_shared/api/articles/190.\346\235\202\350\260\210\357\274\232\344\275\225\344\270\215\351\243\237\350\202\211\347\263\234\357\274\237/_readme.md" @@ -4,9 +4,9 @@ ## 历史 -晋朝某年。大旱。 +晋朝某年。天下大旱。 -老百姓没有粮食吃,被迫吃草根、树皮、观音土充饥。饿殍遍地。皇宫中照样歌舞升平。当大臣来报告这场饥荒时,晋惠帝真是为老百姓操碎了心:“老百姓都没有粟米吃了?那岂不是要饿死?”,过了一会儿他又疑惑地问道:“他们怎么不吃肉粥呢?” +老百姓没有粮食吃,被迫吃草根、树皮、观音土充饥。饿殍遍地。皇宫中照样歌舞升平。当大臣来报告这场饥荒时,晋惠帝真是为老百姓操碎了心:“老百姓都没有粟米吃了?那岂不是要饿死?”,过了一会儿他又疑惑地问道:“他们虽然没粮食,为什么不吃肉粥呢?” 别笑。晋惠帝是认真的。在那个门阀分明的时代,晋惠帝可谓是精英中的精英,顶级精英。然而,他自幼在深宫长大,无法看见寻常人家的生活,无法理解平民的喜怒哀乐,甚至都不知道肉是从哪里来的。 @@ -35,4 +35,4 @@ 我相信:任何人,只要他有梦想,就值得我们去帮助。即使他真的曾经荒废学业,也不应该让这些过往成为他现在被歧视的理由。他会去学英语,但他现在急需一份好工作。 有人说:种一棵树,最好的时间是十年前,其次,是现在。所以,Just do it!从一点一滴开始,从身边开始,让社会变得更美好,这样我们才能不被阶层撕裂导致的黑暗时代所吞噬。 -我们都是水滴,但我们都有一颗滚滚向前的心。 +我们都是水滴,但我们有一颗滚滚向前的心。 From 093d64b44b658e48d7472b0852e2d0abba1d6ed6 Mon Sep 17 00:00:00 2001 From: lhtin Date: Mon, 17 Oct 2016 17:50:06 +0800 Subject: [PATCH 016/177] improve --- .../_index.md" | 77 +++++++++++++------ 1 file changed, 52 insertions(+), 25 deletions(-) diff --git "a/src/app/_shared/api/articles/250.RxJS Overview\351\230\205\350\257\273\347\254\224\350\256\260/_index.md" "b/src/app/_shared/api/articles/250.RxJS Overview\351\230\205\350\257\273\347\254\224\350\256\260/_index.md" index f89e33a..5a0b395 100644 --- "a/src/app/_shared/api/articles/250.RxJS Overview\351\230\205\350\257\273\347\254\224\350\256\260/_index.md" +++ "b/src/app/_shared/api/articles/250.RxJS Overview\351\230\205\350\257\273\347\254\224\350\256\260/_index.md" @@ -4,13 +4,13 @@ ## 前言 -本文是阅读*RxJS Overview*所做的笔记。该概述写的非常之清晰和简洁,是很好的初学RxJS入门资料。概述内容包括:**RxJS涉及到的主要概念及概念相关的必要背景知识**,其中主要概念包括:Observable、Observer、Subscription、Subject、Operator、Scheduler,本文会一一进行介绍。尤其是那些时不时出现的手书斜体格式的总结文字,非常值得认真思考的。本文尝试进行总结,力求把RxJS的核心思想表达清楚。 +本文是我阅读*RxJS Overview*时所做的笔记。该概述(Overview)写得非常之清晰和简洁,是很好的入门RxJS资料。概述内容包括:**RxJS涉及到的主要概念及概念相关的必要背景知识**,其中主要概念包括:Observable、Observer、Subscription、Subject、Operator、Scheduler,本文会一一进行介绍。尤其是那些时不时出现的手书斜体格式的总结文字,非常值得认真思考。本文尝试进行总结,力求把RxJS的核心思想表达清楚。 -用一句话介绍RxJS的话,就是**RxJS将异步抽象为数据流,并提供对数据流进行各种操作的接口**。 +用一句话介绍RxJS的话,就是**RxJS将异步数据抽象为数据流,并提供对数据流进行各种操作的接口**。 ## 数据传输 -数据从生产者传输到消费者那里,有两种方式:一是消费者从生产者那里拉取(**pull**)数据,二是生产者推送(**push**)数据给消费者。前者就是常见的函数调用(消费者调用生产数据的函数),后者则是用于处理异步的回调方式(消费者只定义接受数据的函数,然后供生产者调用),也就是由哪一方去主动调用。如下代码所示: +数据从生产者传输到消费者那里,有两种方式:一是消费者从生产者那里拉取(**pull**)数据,二是生产者推送(**push**)数据给消费者。前者就是常见的函数调用(消费者调用生产数据的函数),后者则是用于处理异步的回调方式(消费者只定义接受数据的函数,然后供生产者调用)。它们的区别在于由哪一方去主动调用。代码如下: ```js // 拉取式 @@ -37,16 +37,16 @@ var producer = function (consumer) { }, 3000) } var consumer = function (data) { - // 可以消费数据了 + // 生产者通过参数把数据推送给消费者函数 } // 等到异步数据准备好时,就会调用消费者 // 调用之后才可以消费数据 producer(consumer); ``` -拉取的方式,常用在获取同步数据上;而推送的方式,则更多用在获取异步数据上。会有异步数据这个说法,是因为有些数据的获取需要等待(比如浏览器通过URL接口获取服务器上的数据)。如果数据消费者在原地傻傻地等着数据,而不去做其他的事情,必然导致效率低下。正确的做法是在数据还没有到的时候去做其他的事情,等数据到了再来通知消费者。 +拉取方式常用在获取同步数据上,而推送方式则更多用在获取异步数据上。会有异步数据这个说法,是因为有些数据的获取需要等待(比如浏览器通过URL接口获取服务器上的数据)。如果数据消费者在原地傻傻地等着数据,而不去做其他的事情,必然导致效率低下。正确的做法是在数据还没有到的时候去做其他的事情,等数据到了再来通知消费者。 -在获取异步数据上面,常见的有事件监听和Promise(都是通过回调)。区别是事件监听可以触发多次回调,一个Promise只能触发一次回调。**一次和多次更深层次的区别,在于生产者可以有多少个返回值**。RxJS是两者的结合,**提供了Promise形式的异步编程方式(看起来像同步),但又有多个返回值**。对比以下代码就很容易理解上一句话了: +在获取异步数据上面,常见的有事件监听和Promise(都是通过回调)。区别是事件监听可以触发多次回调,一个Promise只能触发一次回调。**一次和多次在更深层次上的区别,是生产者函数可以有多少个返回值**。RxJS是两者的结合,**提供了Promise形式的异步编程方式(看起来像同步),但又可以有多个返回值**。对比以下代码就很容易理解上一句话了: ```js // 事件监听 @@ -75,69 +75,96 @@ observable.subscribe(function (event) { ## 基本概念 -**除了拥有对异步处理能力,RxJS还提供了对生产的数据的进行常见操作的接口,以及提供不同的触发回调的策略(比如同步、异步等)**。理解RxJS的概念有利于更好地利用它,接下来介绍RxJS所包含的基本概念。 +**除了拥有异步处理能力,RxJS还提供了对生产的数据进行常见操作的接口,以及提供多种触发回调的策略(比如同步、异步等)**。理解RxJS的概念有利于更好地利用它,接下来介绍RxJS所包含的基本概念。 ### Observable -使用RxJS的第一步就是得到一个Observable,Observable是一个含有数据生产过程的对象。Observable的特点是不主动运行数据生产过程,而是需要被启动(懒运算)。同时它可以被多次启动,并且每次启动得到的对象没有任何关系。 +使用RxJS的第一步就是得到一个Observable,可以把它理解为数据流,**它可以向订阅者(即消费者)推送多个数据**。Observable分两种,分别是Cold Observable和Hot Observable。Cold Observable的特点是每个订阅者独享该Observable推送的数据序列,并且数据生产过程是在添加订阅者(比如执行了`subscribe`方法)的时候才开始启动的;而Hot Observable的订阅者则共享该Observable推送的数据序列,同时一旦启动了数据生产过程(比如执行了`connect`方法),Hot Observable的订阅者就无法接收到它订阅之前的数据序列。 -**没有任何关系**的意思是回调独享一份数据,不同启动中的回调不共享数据。且看如下代码(展示Observable中回调独享数据的特点): +以下代码展示Cold Observable中订阅者独享数据序列的特点: ```js -var observable = Rx.Observable.create(function (observer) { +var coldObservable = Rx.Observable.create(function (observer) { observer.next({ a: 1, b: 2 }); }); -observable.subscribe({ +// 订阅的时候给每一个订阅者形成单独一份返回值序列,并且包含之前的返回值 +coldObservable.subscribe({ next: function (data) { console.log(data.a); // 输出 1 data.a = 3; } }); -observable.subscribe({ +coldObservable.subscribe({ next: function (data) { - console.log(data.a); // 输出 1 + // 输出 1,上一个订阅者的修改不会影响到 + console.log(data.a); data.a = 3; } }); ``` +以下代码展示Hot Observable中订阅者共享数据序列的特点: + +```js +var hotObservable = Rx.Observable.create(function (observer) { + observer.next({ + a: 1, + b: 2 + }); +}).publish();; +hotObservable.subscribe({ + next: function (data) { + // 输出 1 + console.log(data.a); + // 修改属性值 + data.a = 3; + } +}); +hotObservable.subscribe({ + next: function (data) { + // 输出修改后的属性值 3,说明是共享Observable推送的数据序列 + console.log(data.a); + data.a = 3; + } +}); +// 开始形成返回值序列,并且每个订阅者共享这个序列 +hotObservable.connect(); +``` + ### Observer -Observer是一个包含回调函数的对象(可包含`next`、`complete`、`error`三种回调),比较好理解。例如上面在调用`subscribe`时所传入的参数,就是一个Observer。 +Observer是一个包含回调函数的对象(可包含`next`、`complete`、`error`三种不同状态的回调),称之为订阅者,比较好理解。例如上面在调用Observable的`subscribe`方法时所传入的参数,就是一个Observer。 ### Subscription -Subscription是调用Observable的启动生产数据过程的方法(比如`subscribe`)所返回的对象,表示Observable的执行过程。这个过程可以被取掉。 +Subscription表示给Observable添加一个订阅者这个动作对象。对于Cold Observable,`subscribe`方法会返回一个Subscription,并且会启动推送数据的过程,同时这个动作对象通过调用自己的`unsubscribe`进行取消。 ### Subject -Subject是Observable的一个变体,区别是Subject只能启动一次,而Observable可以被多次启动。这就意味着数据在所有的回调中共享。另外一点区别是后添加的回调无法处理生产数据过程之前产生的数据。且看如下代码(展示Subject中回调共享数据的特点): +Subject跟Hot Observable类似,区别是Subject也可以看作一个Observer,同时在创建Subject对象时就默认启动了数据生产过程。因此,Subject可以通过`next`向其订阅者发送数据: ```js var subject = new Rx.Subject(); subject.subscribe({ next: function (data) { - console.log(data.a); // 输出 3 - data.a = 3; + console.log(data); // 输出1和2 } }); +subject.next(1); subject.subscribe({ next: function (data) { - console.log(data.a); // 输出 3 + console.log(data); // 只输出2 } }); -subject.next({ - a: 1, - b: 2 -}); +subject.next(2); ``` ### Operator -Operator是操作异步数据的方法,其返回另一个Observable对象,可链式调用。常见的操作有处理数据(`map`)、过滤数据(`filter`)、累积数据(`reduce`)。例如以下示例代码: +Operator是操作异步数据的方法,返回值是另一个Observable对象,可链式调用。常见的操作有处理数据(`map`)、过滤数据(`filter`)、累积数据(`reduce`)等。例如以下示例代码: ```js Rx.Observable.of(0, 1, 2, 3) @@ -186,4 +213,4 @@ done 本文主要介绍了RxJS中涉及到的基本概念,并提供代码示例。理解这些概念是使用好RxJS的基础,同时RxJS包含了丰富的Operator。在解决实际问题时,对这些Operator的理解会有利于找到快速高效的解决方法。如果你打算继续深入学习RxJS的话,建议从Operator入手,并结合实际问题。 -现遗留下来的问题是:为什么要使用RxJS?RxJS适合哪些问题?这些是下一篇RxJS文章所涉及到的内容,敬请期待。 \ No newline at end of file +接下来的问题是:为什么要使用RxJS?RxJS适合解决哪些问题?这些是下一篇RxJS文章所涉及到的内容,敬请期待。 From 62425aa90bc672206cfd5b9f60792f57fb7abeb6 Mon Sep 17 00:00:00 2001 From: lhtin Date: Tue, 18 Oct 2016 10:03:56 +0800 Subject: [PATCH 017/177] improve --- .../_index.md" | 11 +++++++---- src/app/_shared/api/articles/index.ts | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git "a/src/app/_shared/api/articles/250.RxJS Overview\351\230\205\350\257\273\347\254\224\350\256\260/_index.md" "b/src/app/_shared/api/articles/250.RxJS Overview\351\230\205\350\257\273\347\254\224\350\256\260/_index.md" index 5a0b395..a128312 100644 --- "a/src/app/_shared/api/articles/250.RxJS Overview\351\230\205\350\257\273\347\254\224\350\256\260/_index.md" +++ "b/src/app/_shared/api/articles/250.RxJS Overview\351\230\205\350\257\273\347\254\224\350\256\260/_index.md" @@ -2,11 +2,13 @@ *RxJS Overview*为官方对RxJS的一个概述,点击[这里](http://reactivex.io/rxjs/manual/overview.html)进行原文阅读。 +非常感谢 @雪狼 @trotyl 指出我在概念理解上的问题。 + ## 前言 本文是我阅读*RxJS Overview*时所做的笔记。该概述(Overview)写得非常之清晰和简洁,是很好的入门RxJS资料。概述内容包括:**RxJS涉及到的主要概念及概念相关的必要背景知识**,其中主要概念包括:Observable、Observer、Subscription、Subject、Operator、Scheduler,本文会一一进行介绍。尤其是那些时不时出现的手书斜体格式的总结文字,非常值得认真思考。本文尝试进行总结,力求把RxJS的核心思想表达清楚。 -用一句话介绍RxJS的话,就是**RxJS将异步数据抽象为数据流,并提供对数据流进行各种操作的接口**。 +用一句话介绍RxJS的话,就是**RxJS将异步数据抽象为数据流,并提供对数据流进行各种转换操作的接口**。 ## 数据传输 @@ -79,7 +81,7 @@ observable.subscribe(function (event) { ### Observable -使用RxJS的第一步就是得到一个Observable,可以把它理解为数据流,**它可以向订阅者(即消费者)推送多个数据**。Observable分两种,分别是Cold Observable和Hot Observable。Cold Observable的特点是每个订阅者独享该Observable推送的数据序列,并且数据生产过程是在添加订阅者(比如执行了`subscribe`方法)的时候才开始启动的;而Hot Observable的订阅者则共享该Observable推送的数据序列,同时一旦启动了数据生产过程(比如执行了`connect`方法),Hot Observable的订阅者就无法接收到它订阅之前的数据序列。 +使用RxJS的第一步就是得到一个Observable,可以把它理解为数据流,**它可以向订阅者(即消费者)推送多个数据**。Observable分两种,分别是Cold Observable和Hot Observable。Cold Observable的特点是每个订阅者独享该Observable推送的数据序列,并且数据生产过程是在添加订阅者(比如执行了`subscribe`方法)的时候才开始启动的;而Hot Observable的订阅者则共享该Observable推送的数据序列,启动数据生产过程一般通过特定方法(比如调用`connect`方法)来启动。 以下代码展示Cold Observable中订阅者独享数据序列的特点: @@ -207,10 +209,11 @@ after done ``` -由于目前JS解释器都是单线程运行JS代码,Scheduler的作用局限于提供异步等策略。但是在Rx.NET等服务端的实现中,Scheduler有非常大的作用,比如可以将耗时的任务放到新的线程中,从而提高主线程的响应速度。对这部分感兴趣的同学可以去阅读Rx的服务端实现,比如Rx.NET。 +由于目前JS解释器都是单线程运行JS代码,Scheduler的作用局限于提供异步等策略。但是在Rx.NET、RxJava等Rx +的实现中,Scheduler有非常大的作用,比如可以将耗时的任务放到新的线程中,从而提高主线程的响应速度。对这部分感兴趣的同学可以去阅读Rx的相关实现,比如Rx.NET、RxJava。所有语言和平台的Rx实现在[这里](http://reactivex.io/languages.html)可以看到。 ## 总结 -本文主要介绍了RxJS中涉及到的基本概念,并提供代码示例。理解这些概念是使用好RxJS的基础,同时RxJS包含了丰富的Operator。在解决实际问题时,对这些Operator的理解会有利于找到快速高效的解决方法。如果你打算继续深入学习RxJS的话,建议从Operator入手,并结合实际问题。 +本文主要介绍了RxJS中涉及到的基本概念,并提供代码示例。理解这些概念是使用好RxJS的基础,同时RxJS包含了丰富的Operator。在解决实际问题时,对这些Operator的理解有利于找到快速高效的解决方法。如果你打算继续深入学习RxJS的话,建议从Operator入手,并结合实际问题。 接下来的问题是:为什么要使用RxJS?RxJS适合解决哪些问题?这些是下一篇RxJS文章所涉及到的内容,敬请期待。 diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 801ddec..fb9d783 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -213,7 +213,7 @@ const items: Article[] = [ { id: 'RxJS Overview阅读笔记', title: 'RxJS Overview阅读笔记', - summary: 'RxJS 是事件监听与Promise的组合,同时提供了丰富的操作返回数据的接口。', + summary: 'RxJS将异步数据抽象为可被订阅的数据流,并提供了对数据流进行各种转换操作的接口。本文是我阅读官网RxJS概述的笔记,主要介绍RxJS涉及到的主要概念。', content: require('./250.RxJS Overview阅读笔记/_index.md'), first: true, tags: ['RxJS'], From 8b7c31964a4e9a1ad5119c01bccd2691382b5844 Mon Sep 17 00:00:00 2001 From: Zhicheng Wang Date: Tue, 18 Oct 2016 11:49:15 +0800 Subject: [PATCH 018/177] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E2=80=9C?= =?UTF-8?q?=E5=A6=82=E4=BD=95=E9=80=89=E6=8B=A9=E5=90=88=E9=80=82=E7=9A=84?= =?UTF-8?q?=E6=A1=86=E6=9E=B6=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_readme.md" | 153 ++++++++++++++++++ src/app/_shared/api/articles/index.ts | 9 ++ 2 files changed, 162 insertions(+) create mode 100644 "src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" diff --git "a/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" "b/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" new file mode 100644 index 0000000..edcb679 --- /dev/null +++ "b/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" @@ -0,0 +1,153 @@ +# 如何选择合适的框架 + +## 我为什么从不公开进行比较? + +无论是在公司还是社区,不断有人让我拿Angular和React进行比较。而我的答案只有一个:我没法告诉你。 + +原因有三: + +1. 我不是React的专家。除非我的React水平和Angular的水平相同或更高,否则我没有资格做出比较。 +2. 我无法绝对客观。即使我的React水平和Angular水平一样高,有了比较的资格,我也不愿意公布这些比较。原因很简单,我无法做到绝对客观,而带着主观偏见做出的比较会误导使用者。 +3. 我的情况不适用于你。每个人都有他自己的技术背景,对我来说最好的选择,对你未必最好。 + +如果有一天我把Angular和每一项竞争技术都做了比较,并且让你一看就决定选择Angular而觉得其它技术都很Low,那么只会有一个原因:我被盗号了。 + +作为一个崇尚客观、公正、理性的程序员,我无法容忍自己堕落到那种程度。 + +## 任何刻意的比较,都是诡辩术。 + +事实上,只要剥离了应用场合和使用者背景,宣扬优点并隐瞒一切缺点,那么我很容易就能让新手们相信jQuery胜过一切前端框架。不信?来看这个 。如果你是初出茅庐的新手,而某个骨灰级老鸟给你一个片面的观点,那么你很容易被误导,更何况诡辩者本来就是从你这个阶段走过来的,很容易利用人性的缺点击败你。 + +然而,新手虽菜,却不傻。 + +有一天你会发现: + +- 宣称简单的框架可能扩展性很成问题,而被贬低的框架已经过了很多年的实践检验。 +- 宣称资源丰富的框架可能只有一系列低质量库,而被贬低的框架实际上不需要第三方资源就能完成大部分工作。 +- 宣称代表了技术趋势的框架可能招不到几个可用的人才,而被贬低的框架可以让从刚毕业到资深的团队成员都能充分贡献自己的力量。 +- 宣称轻量级的框架在复杂场景中可能很快会成长为恐龙,而被贬低的框架越是在复杂的场景中越如鱼得水。 + +所以,广告法中明令禁止贬低对手,其实正是为了保护消费者,防止不够知情的消费者被误导和伤害。然而软件业并没有这样的法律,但我们至少要有公共的职业道德和个人的内心操守 —— 我们都是骄傲的程序员,一切靠事实说话,不屑于玩弄诡辩术。 + +## 我们应该怎么做? + +1. 我们可以热情洋溢的宣扬自己喜欢的技术,但是不要对其它技术进行贬低 —— 就算你真是双料专家,你也做不到客观公正。 + +1. 不要玩儿那种“断章取义”或“攻其一点,不及其余”之类的诡辩术。 + +1. 不要撒谎!知道的就说知道,不知道的就说不知道,不要利用语言上的模糊性和歧义去误导他人。论文学,估计没几个程序员赶得上我,但是我在技术文章中总是力求精确表达,不屑于玩弄文字游戏 —— “你没看懂,怎么能怪我”这种话我可说不出口。 + +1. 不要隐瞒!由于侧重点不同,可能不会每一篇文章都面面俱到,既谈论所有优点又谈论所有缺点,但是总体上要平衡。你是某项技术的专家,不可能不了解他的缺点,隐瞒缺点不说,事实上就是在坑新手。这种事情,配不上我高傲的心。 + +1. 场景!场景!场景!任何一项技术都有自己适用的场景,在不同的场景下,其应用效果也不同。包治百病的神药只有大力丸。 + +1. 背景!背景!背景!不同的技术对于不同背景的程序员,其适用程度也不同,如果你觉得某种背景对于你掌握这项技术有加分项,那么请明确说出来,以便别人更加准确的判断它对自己是否同样有参考价值。 + +1. 基于事实而非感觉。这是对专业性的基本要求。感觉是一种主观臆断,如果谈论感觉,那么永远不会有结果,而是会陷入像语言大战那样的“信仰战争”、“口水战”。只有事实才能帮新手们判断“这是否适合我”,而不是“我喜欢这个演讲者,所以我选这项技术”,然后掉在坑里。 + +## 范例:Angular 2技术选型指南 + +### 下列情况下请“不要”选择Angular 2 + +#### 需要支持IE8 + +Angular 2明确放弃了IE8,如果你不得不支持IE8,请选用支持它的技术。 + +#### 内存敏感的应用 + +Angular 2的应用至少需要占用30M内存,更复杂的应用会占用更多。如果在你的应用场景中30M内存已经非常珍贵,请慎用Angular。 + +#### 开发团队缺乏后端背景且缺乏Angular 1背景 + +Angular 2引入了很多来自后端编程领域的实践,这些对于缺乏后端背景并缺乏Angular 1背景的开发团队来说可能会有很高的学习成本。 + +#### 极客团队 + +Angular 2倾向于采用成熟、大众化的技术,虽然也把AoT等技术引入了前端,也算新颖,但是这可能无法满足极客团队的追求与探索欲望。 + +Angular 2在设计上内置了很多最佳实践,这些最佳实践对极客团队来说可能是一种束缚,而如果试图突破束缚可能会导致烂代码。 + +### 下列情况下你不需要有顾虑 + +#### 性能 + +如果你曾用过Angular 1,可能有性能方面的顾虑,但是Angular 2升级了实现原理,主观的说:提高了500%的性能,客观的说,在Table-Report等测试中处于第一梯队,与React等在性能上胜负各半。 + +#### 难度 + +Angular 2大幅简化了Angular 1的概念模型和编码方式。 + +Angular 2引入了AoT等很多新技术,但它们都是Nice to have的,可以等你的产品需要追求极致时再去研究。 + +#### 信仰 + +如果你是Redux的信徒,那么不用担心,Angular 2可以很好地与Redux集成。 + +如果你是ReactNative的信徒,那么不用担心,Angular 2可以很好地与ReactNative集成。 + +### Angular 2适用于下列情况 + +注意:Angular 2适用并不代表其它框架不适用或更差,请自行判断。 + +#### 需要长期保持API稳定的系统 + +事实: + +1. Angular 1保持着良好的语义化版本(semver)维护记录,从1.2可以不需要修改的升级到最新的1.5,而不需要被迫修改代码。 +1. Angular 2开发组给出了关于版本升级策略的明确承诺。他们采用的是在后端世界经过多年检验的最佳实践,参见 [流言终结者!Angular的版本与发布](../流言终结者!Angular的版本与发布)。 + +期待: + +1. 你可以期待Angular 2开发组今后会按照可预测的方式进行升级和维护。 +1. 你可以期待Angular 2的当前主版本会有一个稳定的生态圈。 +1. 你可以期待Angular 2的下一个主版本的生态圈也会同步成长,与Angular版本同步或稍后推出。 + +#### 具有深度后端背景的团队 + +事实: + +1. Angular与后端世界共享了很多概念,如依赖注入、注解/装饰器、强类型、接口、TDD等,具有后端背景的程序员可以很快掌握这些核心概念。 +1. Angular采用了从传统的MVC模型衍生出的MVVM模型,熟悉Spring等框架的程序员可以很快理解它。 + +#### 人员流动性较高的团队 + +事实: + +1. Angular默认采用TypeScript语言,具有强烈的类型约束,可以防止新人提交低质量的代码。 +1. Angular有一份官方发布并维护的风格指南(有中文版),其中包括了一系列最佳实践及其考量,这让Angular程序员很容易达成共识,具有相似的代码风格。 + +#### 由少量高手和较多新手组成的团队 + +事实: + +1. Angular通过依赖注入体系分离了服务和组件,并在架构中广泛使用了AOP风格的设计(如路由器的Guard),这让不同水平的程序员可以很容易的实现分工,实现杠杆效应。 +1. Angular是高度模块化的。不同模块之间隔离得很充分不会相互干扰。除了由高手维护的公用模块之外,应用模块的错误不容易扩散。 +1. Angular是高度局部化的。组件的逻辑和CSS样式封装很严,组件之间不会互相干扰。 +1. Angular的官方文档非常全面,而且有与官方文档同步更新的中文文档,非常适合新手入门或作为参考资料。 + +### 其它信息 + +#### 充满活力的社区 + +事实: + +1. 我们的微信公众号在Angular发布开始的一个月时间内增长了2200多位关注者。 +1. 我们的微信公众号的“查看/关注”比大约是25%,这说明我们推送的文章阅读率很高。 +1. 我们在一个月时间内招募了50位驻站作者及见习作者,这说明我们的社区参与热情很高,可持续性比较强。 + +期待: + +1. 你可以期待Angular中文社区继续茁壮成长。虽然Angular在2016年中秋才正式发布,但是我们有Angular开发组和谷歌技术推广部的大力支持,有充满技术热情的推广者和写手,你可以期待等到它一周年的时候交出一份令人震撼的成绩单。 +1. 你可以期待Angular中文社区的成败不会取决于某一个人。我们已经初步建设了一个社区人才梯队,分工体系也正在形成,未来会逐步脱离个人的推动而实现自动化运营。 + +#### 大量的潜在人才 + +事实: + +1. 我们的Angular中文官网在Angular发布一个月之后达到了每日20000+的PV,这说明有很多人对此项技术感兴趣。 +1. 如前所述,Angular适合传统后端学习,从而转型为全栈工程师,从而增加了团队配置的灵活性。 + +期待: + +1. 你可以期待未来会有大量基于Angular技术栈的新前端。 +1. 你可以期待未来会有大量资深后端转型而来的前端,他们的设计感、架构观等放在前端也同样是资深的。而前后端的API协商成本为零。 diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 6f19149..eca04c6 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -219,6 +219,15 @@ const items: Article[] = [ tags: ['过去'], authors: ['雪狼'], }, + { + id: '如何选择合适的框架', + title: '如何选择合适的框架', + summary: '无论是在社区还是在公司,我都不愿意公开比较两个框架,因为我无法容忍自己公开发表不够专业的意见。那么我在公开发表意见方面恪守着哪些原则呢?请看本文。', + content: require('./200.如何选择合适的框架/_readme.md'), + first: true, + tags: ['现在', '未来'], + authors: ['雪狼'], + }, ]; @Injectable() From e5702f866070fba05360b50a54a4b86f4b0dc2d7 Mon Sep 17 00:00:00 2001 From: Zhicheng Wang Date: Tue, 18 Oct 2016 11:52:20 +0800 Subject: [PATCH 019/177] =?UTF-8?q?=E6=96=87=E5=AD=97=E5=BE=AE=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_readme.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" "b/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" index edcb679..38f29cb 100644 --- "a/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" +++ "b/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" @@ -14,7 +14,7 @@ 作为一个崇尚客观、公正、理性的程序员,我无法容忍自己堕落到那种程度。 -## 任何刻意的比较,都是诡辩术。 +## 任何刻意的比较,都是诡辩术 事实上,只要剥离了应用场合和使用者背景,宣扬优点并隐瞒一切缺点,那么我很容易就能让新手们相信jQuery胜过一切前端框架。不信?来看这个 。如果你是初出茅庐的新手,而某个骨灰级老鸟给你一个片面的观点,那么你很容易被误导,更何况诡辩者本来就是从你这个阶段走过来的,很容易利用人性的缺点击败你。 From 803f2e39307b7bc3db6ca67b7bb5ae24edc1422f Mon Sep 17 00:00:00 2001 From: Zhicheng Wang Date: Tue, 18 Oct 2016 11:54:27 +0800 Subject: [PATCH 020/177] =?UTF-8?q?=E6=96=87=E5=AD=97=E5=BE=AE=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_readme.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" "b/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" index 38f29cb..79aed08 100644 --- "a/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" +++ "b/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" @@ -63,7 +63,7 @@ Angular 2引入了很多来自后端编程领域的实践,这些对于缺乏 #### 极客团队 -Angular 2倾向于采用成熟、大众化的技术,虽然也把AoT等技术引入了前端,也算新颖,但是这可能无法满足极客团队的追求与探索欲望。 +Angular 2倾向于采用成熟、大众化的技术,虽然把AoT等技术引入前端也算新颖,但是这可能无法满足极客团队的追求与探索欲望。 Angular 2在设计上内置了很多最佳实践,这些最佳实践对极客团队来说可能是一种束缚,而如果试图突破束缚可能会导致烂代码。 From 4f7dfd1e601dfce6cb0467967493bfe923b6e672 Mon Sep 17 00:00:00 2001 From: Zhicheng Wang Date: Tue, 18 Oct 2016 12:13:36 +0800 Subject: [PATCH 021/177] =?UTF-8?q?=E6=96=87=E5=AD=97=E5=BE=AE=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_readme.md" | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git "a/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" "b/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" index 79aed08..176754b 100644 --- "a/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" +++ "b/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" @@ -77,9 +77,9 @@ Angular 2在设计上内置了很多最佳实践,这些最佳实践对极客 Angular 2大幅简化了Angular 1的概念模型和编码方式。 -Angular 2引入了AoT等很多新技术,但它们都是Nice to have的,可以等你的产品需要追求极致时再去研究。 +Angular 2也引入了AoT等很多新技术,但它们都是Nice to have的,可以等你的产品需要追求极致时再去研究。 -#### 信仰 +#### 你的“信仰” 如果你是Redux的信徒,那么不用担心,Angular 2可以很好地与Redux集成。 @@ -87,20 +87,20 @@ Angular 2引入了AoT等很多新技术,但它们都是Nice to have的,可 ### Angular 2适用于下列情况 -注意:Angular 2适用并不代表其它框架不适用或更差,请自行判断。 +注意:说“Angular 2适用”并不代表其它框架不适用或更差,请自行判断。 #### 需要长期保持API稳定的系统 事实: -1. Angular 1保持着良好的语义化版本(semver)维护记录,从1.2可以不需要修改的升级到最新的1.5,而不需要被迫修改代码。 -1. Angular 2开发组给出了关于版本升级策略的明确承诺。他们采用的是在后端世界经过多年检验的最佳实践,参见 [流言终结者!Angular的版本与发布](../流言终结者!Angular的版本与发布)。 +1. Angular 1保持着良好的语义化版本(semver)维护记录,从1.2可以不需要修改的升级到最新的1.5,而不会被迫修改代码。 +1. Angular开发组给出了关于版本升级策略的明确承诺。他们采用的是在后端世界经过多年检验的最佳实践,参见 [流言终结者!Angular的版本与发布](../流言终结者!Angular的版本与发布)。 期待: -1. 你可以期待Angular 2开发组今后会按照可预测的方式进行升级和维护。 -1. 你可以期待Angular 2的当前主版本会有一个稳定的生态圈。 -1. 你可以期待Angular 2的下一个主版本的生态圈也会同步成长,与Angular版本同步或稍后推出。 +1. 你可以期待Angular开发组今后会按照可预测的方式进行升级和维护。 +1. 你可以期待Angular的当前主版本会有一个稳定的生态圈。 +1. 你可以期待Angular的下一个主版本的生态圈会同步成长,与Angular的新版本同步或稍后推出。 #### 具有深度后端背景的团队 @@ -131,13 +131,13 @@ Angular 2引入了AoT等很多新技术,但它们都是Nice to have的,可 事实: -1. 我们的微信公众号在Angular发布开始的一个月时间内增长了2200多位关注者。 +1. 我们的微信公众号在Angular刚发布后的这一个月内增长了2000多位关注者。 1. 我们的微信公众号的“查看/关注”比大约是25%,这说明我们推送的文章阅读率很高。 1. 我们在一个月时间内招募了50位驻站作者及见习作者,这说明我们的社区参与热情很高,可持续性比较强。 期待: -1. 你可以期待Angular中文社区继续茁壮成长。虽然Angular在2016年中秋才正式发布,但是我们有Angular开发组和谷歌技术推广部的大力支持,有充满技术热情的推广者和写手,你可以期待等到它一周年的时候交出一份令人震撼的成绩单。 +1. 你可以期待Angular中文社区继续茁壮成长。虽然Angular在2016年中秋才正式发布,但是我们有Angular开发组和谷歌技术推广部的大力支持,有充满技术热情的推广者和写手,你可以期待等到它一周年的时候会交出一份令人震撼的成绩单。 1. 你可以期待Angular中文社区的成败不会取决于某一个人。我们已经初步建设了一个社区人才梯队,分工体系也正在形成,未来会逐步脱离个人的推动而实现自动化运营。 #### 大量的潜在人才 @@ -145,7 +145,7 @@ Angular 2引入了AoT等很多新技术,但它们都是Nice to have的,可 事实: 1. 我们的Angular中文官网在Angular发布一个月之后达到了每日20000+的PV,这说明有很多人对此项技术感兴趣。 -1. 如前所述,Angular适合传统后端学习,从而转型为全栈工程师,从而增加了团队配置的灵活性。 +1. 如前所述,Angular适合传统后端学习,从而转型为全栈工程师,增加了团队配置的灵活性。 期待: From f428f2b98298981ded3e6fc71676ef75385e6a51 Mon Sep 17 00:00:00 2001 From: Zhicheng Wang Date: Tue, 18 Oct 2016 13:41:51 +0800 Subject: [PATCH 022/177] =?UTF-8?q?=E6=96=87=E5=AD=97=E5=BE=AE=E8=B0=83=20?= =?UTF-8?q?=E9=85=8D=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_readme.md" | 4 +++- .../logo.png" | Bin 0 -> 13334 bytes .../_readme.md" | 4 ++++ .../logo.png" | Bin 0 -> 47552 bytes 4 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 "src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/logo.png" create mode 100644 "src/app/_shared/api/articles/210.\346\235\202\350\260\210\357\274\232\345\220\233\345\255\220\344\270\215\345\231\250/_readme.md" create mode 100644 "src/app/_shared/api/articles/210.\346\235\202\350\260\210\357\274\232\345\220\233\345\255\220\344\270\215\345\231\250/logo.png" diff --git "a/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" "b/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" index 176754b..01c140a 100644 --- "a/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" +++ "b/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" @@ -1,8 +1,10 @@ # 如何选择合适的框架 +![公平](./logo.png) + ## 我为什么从不公开进行比较? -无论是在公司还是社区,不断有人让我拿Angular和React进行比较。而我的答案只有一个:我没法告诉你。 +无论是在公司还是社区,都曾有人让我拿Angular和React进行比较。而我的答案只有一个:我没法告诉你。 原因有三: diff --git "a/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/logo.png" "b/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/logo.png" new file mode 100644 index 0000000000000000000000000000000000000000..1dcfe89c1b68c7581232473d871ed024febd42e3 GIT binary patch literal 13334 zcmd6O^;?u%8!n84lypiC(jXmz)X*geNP`TaAPoW{AzjklrHDvLcbBvvB@IfabjMla z-uwF#&N)ADam~EzUGc2@xu2Z(YO3-$SQJ<&C@46J3NjifC=e^H>fBhsreRlCj)y@ORMhB`Qjb%uYRGhkNL^(lg9eWiMcjL z9W5*u6GUFC6Y?)5~L# zTVL#}iB#)Bo>hIPuL4{x=c0$_6I4mA;ir#QAN_3jmVPL)naE)<@$o(-6b5z(M}gpn zM8gj;Y|SVj_&z9qzocSo>{{~qHzIN&1RLypE5MukN75RCrw zBKQ_cmHxkhGO9j4^shVl|C4zIRDKAmK6SP;QyN?H|gzt@4`@g zI|<1JtTY>JXR4ojt`C23s-k6l z6_P-RLQi~r{E1K@_^+xx&kxMmwTo(R7Tf$0q>+V{Kea+ud^RNz2!w=nZ!BZWmtoRz zIuu`GeAuEw8|*g(%0|cSu-NK!vNQAOnILCzXXMj43rY%#Z=AZNiyT?JFTet<%<$Hj z1JrL~81WCd?PhDW?OU!-r2A+K#WvUK-fU|3cO*T3Gv(cK_+5lj`S`sv1{~G|?t4U} z`t4ocSZEL~wR`*5=MCClTDusrW#jf|%erYqUY%@DiRAD^X@SvSp>H_^ztT&$!0-ut zQSaPM&of@~?)R+n$65N}k|t>DZnC%7#w@=~V-B{SOb9N0qji`ALq-zb_6_aw^pCe> z_0#w5%{haIr`uD94IYK32j9?EMywSC&sFbMh+Oj?xFS#Xb8M7M%Ud0hRU%l-N zA?Vipz>x|dXbJ})yXy}pgW(JK{^|&J2WLu%B!a_g)5Y-U+0Y~t;P!|4Y8l$Lhu!6e7}sN#mNWI zNP}ZDsiy0ekQj9bEPp4RI(N+vY}VG%IsGbL^UB6%o9&Wp<8XX>#;WAi=#v4V`?^Lk z1Z)6sWsLAvf|(B=%<#X2x26hM+a(0qcRvU+Q&7Qro+2mvvXyPey;2$7^!GWpGOkW?5E4#}ggr?)dxiuX$DLi4;w5287qrM_a~<j{onAT(Z*~ScvL4DJLce-nq@*&YZXf~-F&N@dP~~~MBaANb&&Er<#-B~C zKR)9==(Vz$Dql&m_?})jlNWA3(dc$4So!M5Z=(gN7Z(Jz=G&8H#n)KT=)Md9xeC9( z{IEbk&~d4RI%-f-yr7u|jc@nuud!;EIiA-a-A^!B(MaT_fp9n*Z1O*4!^Bq*0_+%o z2b<$k%9j11NmvZ!=OdW5&UeQcfl}M75G+!0Mp0Io0t%r2<}dvdiI-x7nj2YNTed}v zL2cc4?YK~wng}4(Dzm5k_#u?OcYYdq6cZd{y(}y#SyKs9Q!s@>Hef)-BON=jF#;rw zyHy^|5eH>-2=W`0bMTvy`=LMypMv@Kr9D-uaC-az5EFTTNcN8_JUZIMd@)^!h19}tS zM?mlR0G2x-(U~uSxz!(tE*~Rayg`=xpt&VMqnr>NW{c!7!H;K7 z$?(gQoj+sf75Wbi93b7ha}B3;bkafT#Fd+^zITRxR8Y#9#8<)n+C5sX8o^WVipGL5 zKX@Z%spz}L?%;VX1vtXTVvFojn0K^U>e>53&X(YU(Im~`eOHEgm#tVvWh3XZAAlyr ztqw60b`~|7Wl}5{OESCQj)l4<`n3+f(im%_@A-BDbEj~H{~HAwN~DJ35CQSwZf?w) zNcwf8%++-CGw|89T#XrEp(JZ0 zo<(4a`N3JB;ZN%9o{Ex(mYqhBuM7`a{mGkaJaDf&DfNpmPnC63JDCJ;#3SLp(fXSd zde67{-6iLE)&i5yH$Hdm5FKR#O?_Phz29lHk z@OS_T)5GYDXF{8Dv)D{a;I{>F?87?KJ@oYn1Ai{ORP4%usu`q% znPMImfz@AdQ87OG0EuDUB>;Aj$#=%Cp}7BhhRCh9@8EO&0FFulZMJoEEntz!3BE+B zBi6B?59qmFHpf;=nog#*E{?rEpU_+!H&uQ8y34^4d~25@z^1662G8e=0~Se$+bm;>0A3O@pnf2k6CT-6-2;gR7P>%2s9i|82lMQyRnvX z93h~3EPmy9x;uw%*L=RZHeG4y6a|TDq3K=Yg0??EIx`igJ2MvZ13V@4wD0J9(*4a5 z&7S93+C{oNdZC54d_{s~cYK8i7eD+Eio|+{71)Zj?rh1rMPV1t_eCjeh{+#Gx+2hM zT7FPcWh*=gUUKQX}~Aw#y}92}mbJ zxJW2>Ds=wi-nb7#{mx{W*_+nK#KAtntwnkjoBS1J@cXu6DdL!^5to^n$3h)>7<%{$ z4}oktajB`fWLpil1q}Aztt2^lovN3b?p9SuX4^p6b-q%4?#p87fTuNioW8csz2~6$ zUc&b^XV3m=D2;il59f(AbkXlM9gFVyS4{oB;-^hEL`bJqWKJo?5H*mCZM~`7??N*W z{t&2E=WE?{%{pl1#Vdp7+q9fDUSH?sNh)WxKj0Kt#J7G{Nn`3cwo9meI&6R`w)rgq zz{XHM$SXm1vFUWaL5JjNrRI%4V@rx(V(a8Ue zZe%R$)Gt`21)+pUd8&8FT3ln?yU*JRrC?gzo55Au-ZCdSi$Tz>xQudX<;=C+MYVu< zoNT+v1kUKP4dj=Uw9IIHgEmEl(}+!*_nQZKVsr+9t=I(lMQSR+^(j_O?LF9y=ReAZ z8R-o3sK3P1pQg%#eQwCTHwBz%<5nM3+RdS8tl(wjq zUC=4~5Im$Q2}cvl_W=T2E3CK0a!(?brR5)FS?8|NT1^`gH!wisSvcrr#)imaZZEXl zdOZFjlB%}s|7n0W6W4cp~W7>j!YvuBE|p39fS0-g>9TKFnq@g zbr!x3Sx^ge?w>}CK9#r*?mAfgp3(5UEySfyUvf~BXqLD_QvVHRI62R6axn`Nb5_qs zgLY5SxlP(Hm5IsX0mXIHBvj_Y>h|{7(3-Nio-C6?6dwS0=hKgmC2ml;NUAAyvP(s` z_p-RoWi9r7@vP{fFQ`>DxOwGiZ#38>lDt0qrKuyt+t)nP3rH~pEb(QT~lrj zx(1wYuRbi&W!llmq&#fxFXL5&)E4)*>*=(4&uK(#ncjvY?h}P4XLpu_ z_dattR3TcP?2F05f#|>3;dgsHy;{uwDE#2dp9%0*3Y)QA$(d~v@loU+JDdjk8|mGB z&yikGB8>jH#M(#otQ^kSv0`c;3c|Ki%WF4bo#L^qrPq?G`JN+uGVrjX6a%{Ahnx}| zgAoh5ef(+S?=FncnkEeR%;o+>itN6!uaFmq{sut`ePoVQRuS~m`l}-zeFH4hkwF!yT=w`=nxr2&?z(QsDm>9o^Mm3FCF z(?TYDe^xvpcUYltt)T0#_P}Zj|H#xI?fwy1?h)k4wv_BVrExZaJ;Cr<;I?$y%B)8v z_!tp*Y6g0eP$$?k4Coj{kPth>i?%S59TAVMa$`e}s(Ww_4*5tC5dn3_J9$!+k+EyG zuX%3*$AyF7|J{ut9qRM#l4sK^fg5Pu@{9x6BgMgBT!^op;^zvu>T*Au>w;#xC<`W8 zuhW#~fQRmPi7#$_(%I$!msUZULH>k2?>$q{k8KPx1L}$$Oqz3+&tKLp=9NC~W@U;d zI)B{p+Y~&>En=QgKbQ^iO-T_K#9%;Dk!et95Pc1IIE~n2K$L*7GZX?s}%Np zM875BvZ?uXsX4wU92-@2tTr5ay~kMkvY+&j&6sRKYA`h+p1Wr3@I`}CW*V#qDot~T z;ZvxOQQ%E9Rek?zy!oSMb*1)M?HX=G?Aod=OWN}JR7vy2W@&ppl{738$mzEb+YxIN zAW5-!Zb7cH9$$6r<2Y_Ejjl(%>IaQsesoDX_utJt;G2iOE|HpXMtCv~_`9#OxqZz( zZBx&YtHQR*I>7%T2Rje6lR)v1q?m9u@gmbkr`JjAN{N%@U=l`m4m}d= zkv;frp2i&6?kLFTb`In?W;xKGsdBr^vYY~xyc&oa~bR|i$&r;XC zLUPGHo7oRiD7}X_b&EZ1Y_hRZ@Dg!v#dkZl8}=|vr!bDE)nHbG_r7SP6o>qB5aH)O-q@Y<#3;;kl1dAM+GmauK1XRC1*`q&`KsN~4?zmG3bfxu8sX@IF7MS(z0(=RG2GCZ?ao1Q`;5pQ4Qq(Ll)RIk?975&o9!!khQq+tOnb6 zSkmpY6LNnQ&JF3|=<6n#VT`4MjTOuLoE&1Tk2mis)iMLTN$LWfcyh@ktdyBm>UL;O z#9zi34c{fPNZVCrAzYQ*henHfE8wM7;~;?+5(}n?cP^t&hVPDx&jj-FV;*KxJ12-H z&3U|Tdp69(f{=!|_b-`QHD?uLnV{x7s5OZGAPMOmaIsJPk#^!bfp+Yp!5ntZi8Q?e9U zn_T{zb5v)vrX|}x`+@c^ z$|VZ2`!2X`GEHy`Yyr*w~!UjKaSmA+7sbJotemsUTpogGM*i{|}8V7NV7ri|TC1JP2 zu}V9@$3SL!lKIO>LRw2rIwIrP^1|TST8smCgg>+cZV@9ke8>33wohK!_~+N>cm;uP z615B1Ozbwom_@+3=$F1lSc7#S&;l6%3Z-nzZ_36X3f?VhIi&My4_T z`ijY98=>~GK=A94-`Yw z7aWZQHX4xBI^X2ck~@|-pWYass+hcX-2My3>~<3({X-qATGf?BJ_ZAGy*Of?_g2<` zs0x^a<6!u$s`Ms{r5=Y+g)EwFvJOp=;@o)eS<~ILy>&j49H_Hq|2Ix1vQvKw2dTzIa zWzzb|hFMi^!d3P|Hs)m{m~-nE+37NKbJ9R^{<2(Dc<#4K5yJq-yJMuT{Io2SNt#ij zxnzI?FC0p>5}RXW3@Owpq4}UhTc#PF0gQ7?<~B;~+5)d+ayJTQ3_iK=>lgBei9!DR zx{ApnM~_Mr0Dgx+P{vfkiw^27;1&ZMc&<@>XWdEUTsx|}GypShw0i=BP-jP6~PGv{JK}23m>&u$FYQs{Jv!iM>XN9 zR|aR|8o&%Qi;#R*d1rSho##(i*JSFL6fD zqzgN(?((LF*pdJPTJb%~<%GFfb)>8lS=AU&W30&0FKPd)P97>RB}74Hmb&`2Vn5(( z`z-9f*j1wk7lk!E%{h_NUtQ$dJ&hhvVGZ{J;RDH--AVq;0)-HjUK8CFR6xVvXUslk z8?Y`t2AK8~BwTe0`@}5H3hvth&BB6d{#UXv%(setoN+6STrrj#FLYA<;EH_W98)Rr zKoVFuD5IR41@Jm3eYxn5RvH)q75z;4>(3oyeK&;WhgQNhcp#Pu++3@L2z?afVTLTd zs(bw5$m#{#2l?j+NaU6lgDQA$<3S2A8kZ~zm(B!43<;8O!qu9B>24dXI2IGT!+dUl z=f;GIbIF57e46eL1h7R69LAtj!su)@1T|uozj$)(lTtF-VHX#N&$94lloyQp@HOEo zCnEEGJhyA7L!~YNSlV&)PIr{{@*SuY(r0<_^OD>moEZt_bMmsOTjHlAPFo0L)+#4*|!=E6{I#h^$764cZ6lPU_+!R-|;% zaopb73fd;IG2Grw+&nwoSmn)hw0QbgqI@;G;ko2fT^Keq)q_R+HXdDkB!sJ7SEtI@ zfL_shog`wH6QltPQ(29%DuScf5tS)L1h^^UGx7pUDB-j0h8ZH>D~x%_BQA?;k*nA~ zyK4Q{zo=8lB#T|D)d1?6K=|oK9U@#c;1S6be-q7yc{pN6irlOC*IG0UWrFB{^A{@u z@qI(NdB7?DUHI1uESH&eSD%o>Q2&?aY=nMFwAA*u{WI9Bte6qtmg$O%F3B)t->_4? zMEyiV2Fj5Bruybyb(=y?K;7WlUtNw{a9g9^vQhtF8%d`Y3N(e4_Y?X9SX(xqrb$4t zhCbtftrr>68E~DfbIR*K_gy6ir6nS z&xx)N-1Q9wu+|L6ze9+15x_G0iazEIrc>H&AkydNAQ=!d)JQT&03vRNV!553aBtROOMR^~e zjwoEWX6Wle$NB*~QLeTR3C-VlQ||-jp+Iv@vLJq@SmUHmu)0Is!to4{BP?_U7__nx z1bgC7hT=e)zLg0hBADkrWR+To&uSS|F;ov{gKR(K4Jam~i%A+X4jrfaDLar=o_8kF zKC&}pAG8x)Uxa^V7@&T;OadS@uTyiv*;hD#3WWgn!axc8NQ>XYF?=$N&dMkOys>dc zr(U5at$ z%>}-e=%|Kp1qd`a|Hez#AH72aIDrdZJZ1LoIbT2FYG&L(ERgMu-rRJBc*RT0(Cu&_ z+@AGTo!@Wl*k)v-*+zlV-v{W*%2^}5KAJ}{`ZIS=*RG~H(h&qxLT&OA5mlrnWR z$&3ngCH;;s<}0>KT&>4b8a#(!i1^uV1O!oB# zi7Fsxba zrdCpcxW57}GLPeB&k5ZkFs+OB?dv~sX3mn8v=S!{h17B9?3}PLoha!%kcotpLhWJ- z;~F_kj7Cs&^XF@O58st+Dywc+NS?u{TS2P&T&?3$(%eI)miUQ7?jc+OT~W#QSx67# z3^4E&RHqi_sODse@#p`EQyN}DdCD?#l1)RnDt^!ZMV(Tnb>foss^mPZI!^ZuNMwtR z{rQ#HOmAX`O3VOK7L9rQZga@s_L19}N`8 z<0dL0hb6@AJaGG}7wKr}l_))Am(K8}M(>Oc>_Af$M2qM7))PhdbtB(xz6b-PSN%<- zv}SdXSgXEYg8+HuuPdBl*RUTRH>~SLjy0Ekw0IQ0E5|NzS0VZGNB+YhS)?2m79$e+ zge*P?qRNxX)j?5JyjJ-89qlPxgg-U>(DI7fJACej z+?`fzMw}?Zs_e%z`=X-?;Iu9QbIj`nIjhThMj}wseqoDT36pLJ2rJE5I4E$~u;__` zYX|tYImIu)?MRxb_waJO&!{DF;9>W{O8<3ebdn=bkNXm+SF=AmLRO1?%&z-hu~A|= zNx(Ugdfr`GwpIQsSJ*A26v&bR;#_8;8tUVFczG{ zVHjX%+A&8`1HX#(sY?a(7+^LZsqg)YnJpU@+GJObUgwIv{b-HVI%U9eA1dy% zZd^NqEZYl^Atz&;)48C<0ebSPmTA7Axz>hoL?KznEgoFRsb1>!C(g4qgT7921Jplc zW4*gx)F6tBQssB!j75ffHP1ypZcu5PAHYGL^m~3!E>#Q=q|ZmSDm?2D%I>=7FTYDjNX4w~#2>3nD~qYktJZU8 zsojLdoIsY|(*uas(iJKN+v5Go$VX%kY34HXYv7{JoF$l5OuKl#8@@C6tZ(RuWpmt%r0rNqe1C&d)tmSI_EP5lb?cb?)s~~H5;^ukq_M~(^ZOj_KymL4 zWrTjN`Fw%YGk$^xsA!=QSU(I^R4fxY1e(W)U${_uZ@g#DSQ9d*2`;=KaCYUt8)3>Irmtf zEXO@pj?S;nY0d5@*)&Ej-*W^8GflUIZuyH| z?EQ7DrVu`$u0m0&;TNAD-IdE1vD77gD5uH(C)6%i6!xKHJi#Ee2JPL4YeTWCytk*k zaZQ(IAg}SK|I?Zfbuy5v@r$VQZIL>Rm=8|obJ|# zO(e$6laHO(9Wuy2d&x0(9x|{!^EkTmY3O%X*e!d(-O@C1Ag>L|Q3bJ)L#lrM2no&+ zIc_`pJ?~F3BNm|Wo04W5E7)z`#CC}XIntqIIH0F@P>>M4yNMp6_a_Jklw2`{($&@X zFnsee-K~PeB|MjtTeOfZL0XPGc%TAht7R)77qOu=RdbwOg!y^=>U+@7v^-$?n(ekSYBORB;VEYFVRZoI4P7j8yCN&B|gUFBN^qZrF2`k=F? zT$6`brr490C2v?KYt`HCZkFUz&97%XSPaQ@v@#fe(rx(M=c1==3{$nsVK{SlzUgvJ zmwd}VhUcTP`{yN%+{QggwyXya_FTna?g@SoYY)n!rtSf4=xK$?Z+zs0OZ*62SE?%G z?0ds&Gb5UPNzL)ub?azj^wd0ATK(ssJG=Ya6N;CdEc!m3+!$BQpj4Bzj`}01gF7hV zUt1o$TE{8V5=XIo&U^Oal^o9tjH2;06rGKe@oV#Aqw3$#fsP7O{wEc-j|!psJY75q zaqbEUG-AhN&m`&`ezgm%kZ0pUQ-LjdrQ|>Kl8DUrVe@d3)GZ&F9?rEF}Und6PAWV|hj>%%z=B#IwMRGrKP) z_Pc4lKlsfhVI2qsz-5s^bG!VCDfGyAN$&a4pNV%16$vdeB2p$@@Rhu4Sw!p|=dER; z`r%uCiLjh(DDfGm$Wl1p_lY!3*Zf@($t{c0#&bvRXM8fW6Supc^eW7E`e1hqBa`77 zs$WS7YJAVbiO9K)Tit*yYk5jOK*^DAf4Y2!e zIwuQ8#7Kkl^9|j!c@KjG3hNn_G{HHS^|r7+H@Fm6n=A^V$N@V1WJD0jvg?6Th#8DL+jt2?~j46 zRJRYx>8|WMaq=U47p_f^xhcY!v_hBIx5I)t%#u}eOp9Lx9jC1YK@*E07PailGt0b; zlP8AeV;TdLKd}IJ5~KVot%u&lr8D0fh*K044RLQ#a5RFP@h-dC#>%-!ya;h8O z8p3|(SmluDWUA=PWs%Hzrfey@34PMc?K((sERS{|2-cHLT?o7go}hSy1K zjY;r5za}bPzOV;2Rkdi=L;FtT=e3`EzdA(zOjm8`XZUC7T&zqt2o6U5TASM(RZi_a z%Qq_Y(yrOQq3RGH$qff>Sv_Z%(a_UDKHAiiW|<0Foi8osJK@+>HKRs_gR|J)(wFwc z##d5gXNb>=?_+#AJoGmv5L`|-tSEwQ!I(Zz_Y(`O`beuzLLuP^)3?tKc3V{2cj^lW zKbB2`JWj}5^e`PIs?+64Zj#YskP>3BNq_d%Yfw+#vFd=NkEpmqwMQIsF{f+rTVOn=;-CJ7UHfsTVvRX;56lH59@2O zFLST(ljlU8%JeQ9uvq4c3kxqBPFgn4!z3sP_;M|*=oeYMYlH9IA5j5)0qe6OWxeMX z-z9UDUoT(rd8-(EBLBHs-g@j_@vSX3U~$gJznz)}-b#v70uJOobM$iXM?ySW^mfMR zG!3uk+JoQk`W6s@zUO9wCwwBH_goDQ+um4%98!T+vVR)OefR#jb`bxs3H>bwcgHVD zDae0q>L%c(Fw$5~VE;CW|LbRf&gs8h>%OHRwGp5~?D5Y>RE)O(if^Mqs`YP=yU%}B z3bB7aqCiCf-H0kE{M+&lhuHvgWkS?N^WSZnX z|7%eDcRinA6x3jJOw9kb6QBZoDVvXz{{J?>w}NQD!#@D}-*(zT±l`ZlsB9J!}O zkeB~|d;H@}kgbX4g-8e8+js-|;NP%1vGcm((ulq_4E(lr7l&f3LW(k_U>+D(j;Esg zo!_1aM^vQHtJQ#xTGEt5ir{BYjX^8)AmZKeco`OdGp9wAN>hhW@?D6x?T?RL*TAiM zo_yD04;2y!tP)0}U-q%JI78WTz|7(m2q`Nq)O;Dd;8? z#pM51VQ_>6SpieBWKj#4DP;p*wePO9cE*ONLMbRHZZG=5A^&$~Q1i@r%JvhRo7OJ;p9tJid43A1^Pb-1ny0Eh5XEqdSC1)I_?^O&OQampG z%JnFLEi@cy7|=c{g7z-{|8(LH(PAQ&#s5_D|G%Gb{NMPYirUY~NnP~2|0ymEpV9Xg a&tk^UV>_NL2mH_nMNw8&=Bt#k-~R!@w=*aJ literal 0 HcmV?d00001 diff --git "a/src/app/_shared/api/articles/210.\346\235\202\350\260\210\357\274\232\345\220\233\345\255\220\344\270\215\345\231\250/_readme.md" "b/src/app/_shared/api/articles/210.\346\235\202\350\260\210\357\274\232\345\220\233\345\255\220\344\270\215\345\231\250/_readme.md" new file mode 100644 index 0000000..fb506d5 --- /dev/null +++ "b/src/app/_shared/api/articles/210.\346\235\202\350\260\210\357\274\232\345\220\233\345\255\220\344\270\215\345\231\250/_readme.md" @@ -0,0 +1,4 @@ +# 杂谈:君子不器 + +![儒](./logo.png) + diff --git "a/src/app/_shared/api/articles/210.\346\235\202\350\260\210\357\274\232\345\220\233\345\255\220\344\270\215\345\231\250/logo.png" "b/src/app/_shared/api/articles/210.\346\235\202\350\260\210\357\274\232\345\220\233\345\255\220\344\270\215\345\231\250/logo.png" new file mode 100644 index 0000000000000000000000000000000000000000..f5a7aaa3d8b855140b116747e6a7833f3db151b9 GIT binary patch literal 47552 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 mfx-*r)c@_6Au?$xchwyRZx!XGJn|(2|E_52UMM Date: Tue, 18 Oct 2016 13:58:32 +0800 Subject: [PATCH 023/177] =?UTF-8?q?=E6=96=87=E5=AD=97=E5=BE=AE=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_readme.md" | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git "a/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" "b/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" index 01c140a..bf6f230 100644 --- "a/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" +++ "b/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" @@ -24,7 +24,7 @@ 有一天你会发现: -- 宣称简单的框架可能扩展性很成问题,而被贬低的框架已经过了很多年的实践检验。 +- 宣称简单的框架可能扩展性很成问题,而被贬低的框架已然经历了很多年的实践检验。 - 宣称资源丰富的框架可能只有一系列低质量库,而被贬低的框架实际上不需要第三方资源就能完成大部分工作。 - 宣称代表了技术趋势的框架可能招不到几个可用的人才,而被贬低的框架可以让从刚毕业到资深的团队成员都能充分贡献自己的力量。 - 宣称轻量级的框架在复杂场景中可能很快会成长为恐龙,而被贬低的框架越是在复杂的场景中越如鱼得水。 @@ -45,7 +45,7 @@ 1. 背景!背景!背景!不同的技术对于不同背景的程序员,其适用程度也不同,如果你觉得某种背景对于你掌握这项技术有加分项,那么请明确说出来,以便别人更加准确的判断它对自己是否同样有参考价值。 -1. 基于事实而非感觉。这是对专业性的基本要求。感觉是一种主观臆断,如果谈论感觉,那么永远不会有结果,而是会陷入像语言大战那样的“信仰战争”、“口水战”。只有事实才能帮新手们判断“这是否适合我”,而不是“我喜欢这个演讲者,所以我选这项技术”,然后掉在坑里。 +1. 基于事实而非“感觉”。这是对专业性的基本要求。“感觉”是一种主观臆断,如果谈论“感觉”,那么永远不会有结果,而是会陷入像语言大战那样的“信仰战争”、“口水战”。只有事实才能帮新手们判断“这是否适合我”,而不是“我喜欢这个演讲者,所以我选这项技术”,然后掉在坑里。 ## 范例:Angular 2技术选型指南 @@ -123,7 +123,7 @@ Angular 2也引入了AoT等很多新技术,但它们都是Nice to have的, 事实: 1. Angular通过依赖注入体系分离了服务和组件,并在架构中广泛使用了AOP风格的设计(如路由器的Guard),这让不同水平的程序员可以很容易的实现分工,实现杠杆效应。 -1. Angular是高度模块化的。不同模块之间隔离得很充分不会相互干扰。除了由高手维护的公用模块之外,应用模块的错误不容易扩散。 +1. Angular是高度模块化的。不同模块之间隔离得很充分,不会相互干扰。除了由高手维护的公用模块之外,应用模块的错误不容易扩散。 1. Angular是高度局部化的。组件的逻辑和CSS样式封装很严,组件之间不会互相干扰。 1. Angular的官方文档非常全面,而且有与官方文档同步更新的中文文档,非常适合新手入门或作为参考资料。 @@ -140,7 +140,7 @@ Angular 2也引入了AoT等很多新技术,但它们都是Nice to have的, 期待: 1. 你可以期待Angular中文社区继续茁壮成长。虽然Angular在2016年中秋才正式发布,但是我们有Angular开发组和谷歌技术推广部的大力支持,有充满技术热情的推广者和写手,你可以期待等到它一周年的时候会交出一份令人震撼的成绩单。 -1. 你可以期待Angular中文社区的成败不会取决于某一个人。我们已经初步建设了一个社区人才梯队,分工体系也正在形成,未来会逐步脱离个人的推动而实现自动化运营。 +1. 你可以期待Angular中文社区的成败不会取决于某一个人。我们已经初步建设了一个社区人才梯队,分工体系也正在形成,未来会逐步脱离个人的推动而实现自主运营。 #### 大量的潜在人才 From 5a5d9c544b429e4200ee91f8ad3930c82bb2d050 Mon Sep 17 00:00:00 2001 From: Zhicheng Wang Date: Tue, 18 Oct 2016 18:49:49 +0800 Subject: [PATCH 024/177] =?UTF-8?q?=E5=BE=AE=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_readme.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" "b/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" index bf6f230..26d9e42 100644 --- "a/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" +++ "b/src/app/_shared/api/articles/200.\345\246\202\344\275\225\351\200\211\346\213\251\345\220\210\351\200\202\347\232\204\346\241\206\346\236\266/_readme.md" @@ -95,7 +95,7 @@ Angular 2也引入了AoT等很多新技术,但它们都是Nice to have的, 事实: -1. Angular 1保持着良好的语义化版本(semver)维护记录,从1.2可以不需要修改的升级到最新的1.5,而不会被迫修改代码。 +1. Angular 1保持着良好的语义化版本(semver)维护记录,从1.2可以轻松升级到最新的1.5,而不会被迫修改代码。 1. Angular开发组给出了关于版本升级策略的明确承诺。他们采用的是在后端世界经过多年检验的最佳实践,参见 [流言终结者!Angular的版本与发布](../流言终结者!Angular的版本与发布)。 期待: From 077f15d93a9542754bc6664a704c51e5d6738158 Mon Sep 17 00:00:00 2001 From: Zhicheng Wang Date: Wed, 19 Oct 2016 13:58:34 +0800 Subject: [PATCH 025/177] =?UTF-8?q?=E5=BE=AE=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 2 +- .../logo.png" | Bin 0 -> 41734 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 "src/app/_shared/api/articles/180.\346\263\250\350\247\243\344\270\216\350\243\205\351\245\260\345\231\250\347\232\204\347\202\271\347\202\271\346\273\264\346\273\264/logo.png" diff --git "a/src/app/_shared/api/articles/180.\346\263\250\350\247\243\344\270\216\350\243\205\351\245\260\345\231\250\347\232\204\347\202\271\347\202\271\346\273\264\346\273\264/_index.md" "b/src/app/_shared/api/articles/180.\346\263\250\350\247\243\344\270\216\350\243\205\351\245\260\345\231\250\347\232\204\347\202\271\347\202\271\346\273\264\346\273\264/_index.md" index b7b2b96..72566d3 100644 --- "a/src/app/_shared/api/articles/180.\346\263\250\350\247\243\344\270\216\350\243\205\351\245\260\345\231\250\347\232\204\347\202\271\347\202\271\346\273\264\346\273\264/_index.md" +++ "b/src/app/_shared/api/articles/180.\346\263\250\350\247\243\344\270\216\350\243\205\351\245\260\345\231\250\347\232\204\347\202\271\347\202\271\346\273\264\346\273\264/_index.md" @@ -1,6 +1,6 @@ # 注解与装饰器的点点滴滴 -原文地址: https://zhuanlan.zhihu.com/p/22277764 +原文地址: 对于很多 Java 开发人员来说,注解(Annotation)已经是一个十分熟悉的概念。而在 JavaScript 中(目前仍然是 Stage 2 的 ES Proposal),引入了一个类似的语法——装饰器(Decorator)。 diff --git "a/src/app/_shared/api/articles/180.\346\263\250\350\247\243\344\270\216\350\243\205\351\245\260\345\231\250\347\232\204\347\202\271\347\202\271\346\273\264\346\273\264/logo.png" "b/src/app/_shared/api/articles/180.\346\263\250\350\247\243\344\270\216\350\243\205\351\245\260\345\231\250\347\232\204\347\202\271\347\202\271\346\273\264\346\273\264/logo.png" new file mode 100644 index 0000000000000000000000000000000000000000..3746f7a523322a16537407844c1b3931fb51efbd GIT binary patch literal 41734 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 i?*`kXN+;lqwdx_KX%=d~ftX7Cr>3N(SR(&C^nU Date: Tue, 25 Oct 2016 20:58:30 +0800 Subject: [PATCH 026/177] =?UTF-8?q?=E5=86=99=E4=BA=86=E5=AE=98=E6=96=B9?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E5=AF=BC=E8=AF=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 +- .../_readme.md" | 13 +++- .../_index.md" | 67 +++++++++++++++++++ src/app/_shared/api/articles/index.ts | 9 +++ 4 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 "src/app/_shared/api/articles/220.Angular 2\345\256\230\346\226\271\346\226\207\346\241\243\345\257\274\350\257\273/_index.md" diff --git a/package.json b/package.json index bfe3834..33fff37 100644 --- a/package.json +++ b/package.json @@ -83,6 +83,7 @@ "@types/webpack": "^1.12.34", "angular2-router-loader": "^0.3.2", "angular2-template-loader": "^0.5.0", + "assets-webpack-plugin": "^3.5.0", "awesome-typescript-loader": "^2.2.1", "codelyzer": "~0.0.28", "copy-webpack-plugin": "^3.0.1", @@ -97,9 +98,9 @@ "html-loader": "^0.4.4", "html-webpack-plugin": "^2.21.0", "imports-loader": "^0.6.5", + "istanbul-instrumenter-loader": "^0.2.0", "jade": "^1.7.0", "jade-html-loader": "^0.0.3", - "istanbul-instrumenter-loader": "^0.2.0", "jasmine-core": "2.4.1", "jasmine-spec-reporter": "2.5.0", "json-loader": "^0.5.4", diff --git "a/src/app/_shared/api/articles/210.\346\235\202\350\260\210\357\274\232\345\220\233\345\255\220\344\270\215\345\231\250/_readme.md" "b/src/app/_shared/api/articles/210.\346\235\202\350\260\210\357\274\232\345\220\233\345\255\220\344\270\215\345\231\250/_readme.md" index fb506d5..f487393 100644 --- "a/src/app/_shared/api/articles/210.\346\235\202\350\260\210\357\274\232\345\220\233\345\255\220\344\270\215\345\231\250/_readme.md" +++ "b/src/app/_shared/api/articles/210.\346\235\202\350\260\210\357\274\232\345\220\233\345\255\220\344\270\215\345\231\250/_readme.md" @@ -1,4 +1,15 @@ -# 杂谈:君子不器 +# 周末杂谈:君子不器 ![儒](./logo.png) +很多程序员会对自己的未来感到困惑,在我十八年的职业生涯中自然也曾想过不止一次。今天的周末杂谈,就和大家谈谈我对这个问题的思考。 + +雪狼言必称孔孟,那么我们就先从《论语》中的一句话开始。 + +> 子曰:君子不器 —— 《论语 - 为政》 + +这句话如果直译,那么意思就是“君子不是东西”,呃,好像有点骂人的味道,那就 …… “君子是东西”?咋还是骂人咧! + +好吧,换回严肃脸。 + +这句话的关键在于这个“器”字。这也是文史界争议比较多的地方。这里我只说一些比较主流的说法。 diff --git "a/src/app/_shared/api/articles/220.Angular 2\345\256\230\346\226\271\346\226\207\346\241\243\345\257\274\350\257\273/_index.md" "b/src/app/_shared/api/articles/220.Angular 2\345\256\230\346\226\271\346\226\207\346\241\243\345\257\274\350\257\273/_index.md" new file mode 100644 index 0000000..456cdcc --- /dev/null +++ "b/src/app/_shared/api/articles/220.Angular 2\345\256\230\346\226\271\346\226\207\346\241\243\345\257\274\350\257\273/_index.md" @@ -0,0 +1,67 @@ +# Angular 2官方文档导读 + +要学习一门技术,第一步应该做什么?听从古老的智慧:“认识你自己”。先盘点一下自己现有的技术背景,然后再决定如何往下走,这样才能事半功倍,达成更高的成就。 + +本文也会这样组织,分别针对几种典型场景:全新手自学,全新手被人带,AngularJS 1熟练工转型,Java/C#后端转型。你可以只读符合自己现状的部分,跳过其它。如果这些你都不属于,也可以给我们留言,如果我们有相关的经验,也会再推文章进行补充。 + +## 全新手自学 + +如果你是个没有前后端开发经验的全新手,而且是自学,那么你需要学的东西确实很多。不过别着急,先为自己定个小目标,比如,先把别人的范例程序跑起来。如果你能翻墙,那就不需要在本地准备任何环境,只要点文档中的任何“live example/在线例子”的链接就可以了,你可以进去修改代码,并且预览效果。如果没法翻墙,那么建议你先不要管《英雄指南》这个例子,而是自己新建一个项目根据文档中的技术点进行练习。不过自建的方式也有其优点:它是完全按照真实的工程配置的,而在线例子中基于SystemJS的方式在现实项目中很少会有人用。 + +要想选择自建的方式,就要先准备一个node环境,如果你使用linux或mac,请通过nvm进行安装。具体的步骤请自己搜索。 + +准备好环境之后,打开命令行窗口,运行`npm i -g angular-cli`命令,来安装一个供你快速入门的工具。安装好之后,你可以到你的联系目录下运行`ng new AppName`命令来创建你的练习项目,然后进入这个`AppName`目录,运行`npm i`(这个过程可能会比较长),然后运行`ng serve`命令,你的开发服务器就算启动完成了。 + +长辈,你可以在浏览器中访问地址`http://localhost:4200`,就会看到一个非常简单的页面,但它实际上已经由Angular 2支撑了。 + +接下来,你就可以用IDE打开这个项目了。强烈推荐你使用WebStorm作为IDE,它价钱很便宜,而且还有一个月的免费试用期,对Angular 2的支持非常全面,物超所值,你在它的帮助下学习会事半功倍的。 + +然后你就可以自由的在IDE中跟着《英雄指南》来创建文件了。当然,如果直接拷贝范例中的代码可能会遇到问题,因为例子中的构建系统使用的是SystemJS,不过也不用担心,大胆试就行了,真遇到问题了先尝试自己解决,不行就再找社区。在这个过程中所学到的东西会让你受用终身的。 + +P.S. 我们正在尝试解决需要翻墙的问题,但是不一定能很快解决,如果解决了我们会群发通知的。 + +等到你可以跟着教程做完英雄指南了,就先放松心态,重新阅读一遍英雄指南,不必再管代码。随时有心得就随时记录,然后跟别人分享和讨论。你在英雄指南中学到的东西,已经够你做一些简单的开发了,去找一些实践项目,比如自己写个博客程序,把自己的心得发上去。 + +再然后,你就可以尝试寻找这方面的专职或兼职工作了。Angular 2还是一片蓝海,找工作还是相对容易的,而且它的天花板比较高,不用担心自己的发展受限。 + +## 全新手被人带 + +如果有人能带你,那就再幸福不过了。因为新手容易遇到的坑都会有人帮你解决,让你可以从一个成功走向另一个成功。这时候,你最主要的任务是理解任务需求,并实现它。Angular 2对新手最大的优点在于直观,只要告诉你拷贝某几个文件然后怎么改,你就能为团队贡献生产力了。如果有条件,可以要求带你的人每周至少做一次Code Review,当然,如果能每天做那是最理想的。在Code Review的过程中,你可以学到很多东西。 + +当你学会通过拷贝粘贴完成简单功能之后,可以尝试自己独立添加路由,然后逐渐扩展到功能区(Angular模块),最后你就可以尝试自己开项目了。 + +在这个过程中,你仍然要通读一遍《英雄指南》教程。但是不用读得特别细,更不用自己去试验那些代码。别忘了,在实战层面有人帮你。你阅读的目的只是对一些重要的技术点有印象,注意,不需要追求全记住。等将来遇到了,再凭记忆到文档中查阅。而带你的人帮你解决问题时,可能也是直接告诉你去查文档的某个位置。 + +## AngularJS 1 熟练工转型 + +如果你对AngularJS 1.x已经到了熟练甚至精通的程度,那么学习Angular 2并不难。请先阅读。了解从1.x到2的变化,以及各个概念之间的对照关系。这样一来,你在AngularJS 1中所了解的知识,会对你学习Angular 2有一定的帮助。之后,你可以通读一遍《英雄指南》教程,不用记住每一个细节,也不用跟着敲代码,你的首要目标是当遇到问题时知道去哪里查。然后可以拿出一个你以前用AngularJS 1写过的小规模程序,尝试改用2来实现它。体验两者之间的差异。 + +阅读完《英雄指南》,建议你深入阅读“开发指南”分类下的一系列文档,这些是对英雄指南中所提概念的深入讲解。也是你从AngularJS 1高手转型为Angular 2高手的重要一步。 + +接下来,最重要的就是实战了,找机会实战,遇到问题就回来查“烹饪宝典”下有没有现成的解决方案,以及查阅API文档来了解技术细节。 + +当然,最重要的是:写作驱动学习,往我们这里投稿,与大家分享你的成果,也让大家帮助你纠正理解上的错误。 + +## Java/C#后端转型 + +如果你是Java或C#后端转过来的,你可以先不用系统的学习JavaScript,了解下基本语法即可,建议直接学习TypeScript。作为Anders的三太子,它和C#的相似度很高,而且填平了JavaScript的很多坑。对于切图师出身的前端,学习TypeScript可能会有难度,但是对你不过是小菜一碟而已。 + +后端转型过来的最大障碍在于开发环境与工具链,如果你在团队中,建议先把构建脚本之类的留给别人去做,它涉及到一系列相关知识,上手成本比较高。如果自己学,那么建议从angular-cli或AngularClass的starter开始,这也是前端开发中的常态。 + +环境准备好之后,就按照《英雄指南》、“开发指南”的顺序通读一遍。如果有实战机会,那就不需要动手跟着文档敲代码,而是先让自己对文档中的各部分有印象,将来遇到问题知道去哪里查就行了。 + +## 其它注意事项 + +### 不要着急深入构建脚本 + +前端的构建体系涉及技术较多,而且文档不够完善。除非你准备马上用,否则初期不要在这上面花费太多精力。等Angular-CLI的正式版出来了,这些细节你可能就不需要管了,先把精力集中在学习Angular上。 + +### 不要着急写CSS + +CSS对于新前端来说过于庞大,建议除非要马上用而且没人能替你做,否则不要过早介入。如果想学,建议先好好学学Chrome开发人员工具,通过它你可以更快掌握CSS。 + +### 善用前端工具 + +前端开发中最重要的工具是NodeJS,但是你不用先学会用它编程,把它看成JavaScript版的JRE/JDK/.NET Framework即可,它是一个运行环境。 + +另一个重要工具是Chrome,它的“开发人员工具(右键点“审查元素”菜单进入)”是你学习各种前端知识(HTML/CSS/JS)的好帮手。工欲善其事,必先利其器。花一两天专门探索它的功能是非常值得的。 diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index f366100..f8f8569 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -237,6 +237,15 @@ const items: Article[] = [ tags: ['RxJS'], authors: ['丁乐华'], }, + { + id: 'Angular 2官方文档导读', + title: 'Angular 2官方文档导读', + summary: '上两周的文章仍然偏深,这周我们写一些入门级的。我们就先从官方文档导读开始。本文将告诉你如何通过阅读官方文档来快速入门。', + content: require('./220.Angular 2官方文档导读/_index.md'), + first: true, + tags: ['现在'], + authors: ['雪狼'], + }, ]; @Injectable() From c2672e363723da8fb4a884c2b02add2579aa9f2b Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Wed, 26 Oct 2016 07:59:41 -0700 Subject: [PATCH 027/177] adds a-simple-rxjs-test-by-timathon --- .../a-simple-rxjs-test-spec/_index.md | 149 ++++++++++++++++++ src/app/_shared/api/articles/index.ts | 9 ++ 2 files changed, 158 insertions(+) create mode 100644 src/app/_shared/api/articles/a-simple-rxjs-test-spec/_index.md diff --git a/src/app/_shared/api/articles/a-simple-rxjs-test-spec/_index.md b/src/app/_shared/api/articles/a-simple-rxjs-test-spec/_index.md new file mode 100644 index 0000000..e5fc6fa --- /dev/null +++ b/src/app/_shared/api/articles/a-simple-rxjs-test-spec/_index.md @@ -0,0 +1,149 @@ +# 一个简单的RxJS Test Spec + +## 写作原因: +Testing除了可以帮助我们远离bug以外,也能帮我们了解小到一段陌生的代码大到一个陌生的库是如何运转的。 +这一点同样适用于RxJS。 +那么,一个RxJS的Test Spec该怎么写?Spec写好了,该怎么运行呢? +关于这个过程官方文档中暂时没有的完整的介绍。 +而本文提到的测试环境搭建与spec编写方法,是笔者通过各种尝试摸索出来的。 +难免出错,仅供参考,并希望以此抛砖引玉。 + +## Testing就是Assertion +Testing要做的事情就是Assertion:比较**我们的代码生成的结果**与**我们期望的结果**。 +比如:`expect(我们的代码生成的结果).toBe(我们期望的结果)`。 +具体到RxJS,我们要测试的其实是Observable,比如: +`expectObservable(我们的Observable$).toBe(一个什么东西)` 。 + +[RxJS Repo的Spec目录][]里,有详尽的Unit Test Spec。 +我们来看一下[interval operator的spec][]: + + describe('Observable.interval', () => { + it('should create an observable emitting periodically', () => { + const e1 = Observable.interval(20, rxTestScheduler) + .take(6) // make it actually finite, so it can be rendered + .concat(Observable.never()); // but pretend it's infinite by not completing + const expected = '--a-b-c-d-e-f-'; + const values = {a: 0, b: 1, c: 2, d: 3, e: 4, f: 5, }; + expectObservable(e1).toBe(expected, values); + }); + // ... + }) + +即使你不知道什么是Observable,也不知道这个interval这个operator是做什么的,但通过上面的代码,你大概能猜到: +expected里面的字符会被values里面的对应的数值替换掉, +同时我们期望*e1*这个Observable与*加载了values的expected*等价。 + +接下来,我们先说相关概念,然后是简略的测试环境搭建,最后是分析上面这段代码。 + +大家也可以下先看一下官方的[Writing Marble Tests][],然后再听我唠叨。 + +## 相关概念 +以下为粗略理解,详情参见[官方文档][]。 +* Observer: + 一个Object,可以有3种callback,形如`{next: nextFn, error: errorFn: complete: completeFn}`。 + 3个callback都不是必要的,`{next: nextFn}`, `{next: undefined, error: errorFn}`甚至`{}`(空object)都是合法的Observer。 +   + +* Observable: + 定义在某个时点(可以根据时钟,也可以根据事件),通过调用observer.callback来向observer推送数据。 + 比如,在Observable启动20 ms之后,调用observer.next('Hello');或者在用户点击鼠标的时候,调用observer.next(event); + 或者在链接服务器出错时,调用observer.error('can not reach server'),等等。 + * Observable.subscribe: + Observable定义好了以后,并不会自己运转起来,而是通过`Observable.subscribe(observer)`来启动,同时指定了observer。 + 这就像是在定义好了一个function以后,function自己不会运行,而是通过`function()`来启动。 +   + +* TestScheduler: + 一个虚拟时间机器,Observable可以挂靠其上。 + 我们定义的Observable在真实环境下可能要跑上一段时间才结束。而在TestScheduler里,就是一个同步的执行。 + 比如`Observable.interval(20).take(20)`,这个observable每隔20 ms推送一个递增数字,一共推20个,需要用时400 ms。 + 通过`Observable.interval(20, testScheduler).take(20)`(testScheduler是TestScheduler的一个instance), + 来设定Observable运行在虚拟时间机器上,在测试环境下,瞬间结束。 + * assertDeepEqual: + 在Spec里面要new一个TestScheduler,此时需要要以一个assertDeepEqual函数作为参数。后面代码部分详解。 +   + +* Marble Diagram: + Observable在不同时点向外推送数据,如果用句子来表达,可以是: + “在0 ms时,推100;在20 ms时推'a';40 ms,{x: 1};60 ms,[3,5],同时complete”等等。 + 这个过程也可以用Marble Diagram画出来,比如`'a-b-c-(d|)', {a: 100, b: 'a', c: {x: 1}, d: [3, 5]}`。 + * `'a-b-c-(d|)'`,这部分我们暂且叫它数据时间轴,它显示的是数据在什么时间被推送, + 一个字符占用10 frames(相当于10 ms),比如,c这个数据是在**第40 frame**时推送的。 + * `{a: 100, b: 'a', c: {x: 1}, d: [3, 5]}`,这部分是注明每个数据具体的值。 + * 另外,`-`代表啥都没发生;`|`代表complete;`()`代表同时,以`(`所在的时刻为准。 + 比如`(d|)`,是说`d`与`complete`同时发生在`(`所对应的时点,上面的数据时间轴里,`(`对应在**第60 frame**。 + + 其他详见[Writing Marble Tests][]。 + +## 测试环境搭建 +坦白一下,我还没弄明白RxJS开发时的测试环境是怎样搭建的,大家有兴趣可以研究一下[interval operator的spec][]的import部分。 +这里要用到的测试环境就是大家在[angular2-wepback-starter][]里看到的,jasmine + karma + webpack,以及其他相关的karma plugins。 +大家可以clone [angular2-wepback-starter][],也可以用我的轻量化的[rxjs-typescript-starter][]。 + +## 代码分析 +除了测试环境不同,还有一些[interval operator的spec][]用到的helper methods我也没找到。 +在粗看了[RxJS Testing源码][]之后(细看也看不懂),知道了TestScheduler有哪些method,就能大概改一改上面的spec,在我们的测试环境里跑起来。 +改过之后的spec如下,保存在index.spec.ts文件中: + + // index.spect.ts + import { Observable, TestScheduler } from 'rxjs'; + + describe('Observable.interval', () => { + it('should create an observable emitting periodically', () => { + const testScheduler = new TestScheduler((a, b) => expect(a).toEqual(b)); // added + const e1 = Observable.interval(20, testScheduler) + .take(6) // make it actually finite, so it can be rendered + .concat(Observable.never()); // but pretend it's infinite by not completing + const expected = '--a-b-c-d-e-f-'; + const values = {a: 0, b: 1, c: 2, d: 3, e: 4, f: 5, }; + testScheduler.expectObservable(e1).toBe(expected, values); // modified + testScheduler.flush(); // added + }); + }) + +逐条分析如下: +1. import TestScheduler +2. describe -> it -> +3. new一个TestScheduler,这里需要一个assertDeepEqual函数,TestScheduler.d.ts源码里是这样的: + `constructor(assertDeepEqual: (actual: any, expected: any) => boolean | void)` + 在网上搜了一下,我们可以用jasmine的expect().toEqual(), 就是`(a, b)=> expect(a).toEqual(b)`。 +4. 定义要被测试的Observable `e1`,挂上testScheduler,挂上testScheduler,挂上testScheduler。 + 至于这个一长串的Observable是个啥,我们稍后在测试输出里就能看到。 +5. 定义期望的Marble Diagram,有两部分,数据时间轴`expected`以及每个数据对应的数值`values`。 +6. 调用expectObserable().toBe(),这个是TestScheduler的method,写出来就是: + `testScheduler.expectObservable(e1).toBe(expected, values);`toBe就够了。 + 表面上看是`e1`被转换成了一个Marble Diagram,然后与*加载了values的expected*进行比较。 + 实际上是`e1`和`expected`都被转化成一个中间状态,然后比较。 +7. `testScheduler.flush();`这一步是启动虚拟时间机器。 + [Writing Marble Tests][]里有这么一句:*The TestScheduler will automatically flush at the end of your jasmine it block.* + 真的*红外遥感,自动冲冲*吗?大家先继续本文。 + +然后我们`npm test`(后面跑的就是`karma start`),看到`Executed 1 of 1 SUCCESS`。这有啥用? +我们改一下values吧,比如`f: 6`,保存,看到Executed 1 of 1 (1 FAILED) ERROR,以及一长串Expected [...] to equal [...]。 +第一个Array(我们的e1)的最后一项: (看不清?试试[js beautifier][]) +`Object({ frame: 120, notification: Notification({ kind: 'N', value: 5, exception: undefined, hasValue: true }) })` +意思就是在frame 120的时候,推送的数据是5。这就是上面第6.点中提到的中间状态。 +第二个Array(加载了values的expected)的最后一项: +`Object({ frame: 120, notification: Notification({ kind: 'N', value: 6, exception: undefined, hasValue: true }) })` +frame 120,推送6。看到区别了吧。 +这样,我们就大概知道了那个一长串的Observable是个啥了。 +然后我们把`testScheduler.flush();`删掉,保存,看到`Executed 1 of 1 SUCCESS`,此时f对应的还是6呢,怎么就SUCCESS了? +看来还是要*手动冲一下*。 + +## 结尾 + +现在,我们可以编写并运行RxJS的测试了。 +本文对`Observable.interval`的测试,可以说是RxJS中最简单的测试了。 +而在实际应用中,我们构建出来的Observable会变得很复杂,对其测试也会更复杂。 +大家可以通过研究TestScheduler的构造,并借助[RxJS Repo的Spec目录][]里spec,来进一步了解RxJS。 + + + +[Writing Marble Tests]: https://github.com/ReactiveX/rxjs/blob/master/doc/writing-marble-tests.md +[官方文档]: http://reactivex.io/rxjs/manual/overview.html +[interval operator的spec]: https://github.com/ReactiveX/rxjs/blob/master/spec/observables/interval-spec.ts +[angular2-wepback-starter]: https://github.com/AngularClass/angular2-webpack-starter +[rxjs-typescript-starter]: https://github.com/rxjs-space/rxjs-typescript-starter +[RxJS Testing源码]: https://github.com/ReactiveX/rxjs/tree/master/src/testing +[js beautifier]: http://jsbeautifier.org +[RxJS Repo的Spec目录]: https://github.com/ReactiveX/rxjs/tree/master/spec diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index f8f8569..bb38836 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -246,6 +246,15 @@ const items: Article[] = [ tags: ['现在'], authors: ['雪狼'], }, + { + id: '一个简单的RxJS Test Spec', + title: '一个简单的RxJS Test Spec', + summary: '简要介绍如何编写并运行RxJS Unit Test Spec', + content: require('./a-simple-rxjs-test-spec/_index.md'), + first: true, + tags: ['RxJS'], + authors: [], + }, ]; @Injectable() From ee019c0e09db7c1a7d44beb8379cf0fc758ab36c Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Thu, 27 Oct 2016 04:44:44 -0700 Subject: [PATCH 028/177] changes the way to query author, so to settle issue #32. --- src/app/_shared/api/articles/index.ts | 4 +- src/app/_shared/api/authors/index.ts | 50 +++++++++++++++++++++++- src/app/library/author/home.component.ts | 8 ++-- src/app/library/author/show.component.ts | 7 +++- 4 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index f8f8569..6cb33ce 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -208,7 +208,7 @@ const items: Article[] = [ content: require('./161.TypeScript的新特性/_index.md'), first: true, tags: ['ts'], - authors: ['袁志'], + authors: ['wike'], }, { id: '杂谈:何不食肉糜?', @@ -235,7 +235,7 @@ const items: Article[] = [ content: require('./250.RxJS Overview阅读笔记/_index.md'), first: true, tags: ['RxJS'], - authors: ['丁乐华'], + authors: ['lhtin'], }, { id: 'Angular 2官方文档导读', diff --git a/src/app/_shared/api/authors/index.ts b/src/app/_shared/api/authors/index.ts index c89b8ab..0007e84 100644 --- a/src/app/_shared/api/authors/index.ts +++ b/src/app/_shared/api/authors/index.ts @@ -1,6 +1,7 @@ import {Injectable} from "@angular/core"; import {Author} from "../../models/author"; import {Observable} from "rxjs/Observable"; +import 'rxjs/add/observable/of'; let age = new Date().getFullYear() - 2009; @@ -53,7 +54,52 @@ const items: Author[] = [ ]; @Injectable() export class AuthorApi { - query(params = {}): Observable { - return Observable.from(items); + // AuthorApi.query可以直接用来模拟从数据库里查找作者信息。 + // 只是返回Observable.from([Authors])有些太含蓄了。 + // 查找作者信息操作结束后,如果找到了,返回Observable.of(author) + // 找不到的话,应该是转到一个404页面,这里暂且返回一个Observable.of(spectreAuthor) + + // query可以分为queryOne以及queryAll,matchById这个有点儿绕 + + + + queryOne(params: {id: string}): Observable { + + let index: number = null; + + // 用for loop来找author,不用Observable.from([]).find() + // 因为find()如果找不到,上一行的Observable就成了Observable.never()了 + // 而Observable.never()不会调用observer的任何callback + for (let i = 0; i < items.length; i++) { + if(items[i].id === params.id) { + index = i // 找到了,index改成i,找不到,index还是null + break; // 找到了,不用接着找了。 + } + } + + let spectreAuthor: Author = { + id: 'spectre', + name: '我叫404', + bio: '数据库里没有我,怎么办?', + description: '你看我不到。', + avatar: require('../articles/50.弯道超车!后端程序员的Angular快速指南/team.jpg'), + columnist: false, + homepage: 'https://wx.angular.cn/library/author' + } + + let author$: Observable; + let item: Author; + + if(index) { + item = items[index]; // 找到了,item改成找到的author + } else { + item = spectreAuthor; // 找不到,item改成spectreAuthor + } + + return Observable.of(item) + } + + queryAll(): Observable { + return Observable.of(items) } } diff --git a/src/app/library/author/home.component.ts b/src/app/library/author/home.component.ts index 454b915..7c47c90 100644 --- a/src/app/library/author/home.component.ts +++ b/src/app/library/author/home.component.ts @@ -18,11 +18,9 @@ export class AuthorHomeComponent extends BasePageComponent { items: Observable; - reload(params: {id: string}): void { - this.items = this.api.query() - .filter(matchById(params.id)) - .map(authorToMenuItem) - .toArray(); + reload(): void { + this.items = this.api.queryAll() + .map(authors => authors.map(authorToMenuItem)); } } diff --git a/src/app/library/author/show.component.ts b/src/app/library/author/show.component.ts index 1c37fcc..5a4eb7d 100644 --- a/src/app/library/author/show.component.ts +++ b/src/app/library/author/show.component.ts @@ -19,9 +19,12 @@ export class AuthorShowComponent extends BasePageComponent { item: Observable; reload(params: {id: string}) { - this.item = this.api.query() - .find(matchById(params.id)) + this.item = this.api.queryOne(params) .do((item: Author)=> { + // 根据api.query,如果没找到的话, + // 会返回一个假的author, spectreAuthor + // 所以就不用`if(item)`来检查item是否是undefined了 + // 这是权宜之计,正常情况下,没找到的话应该转到404 document.title = `${item.name} - 作者 - Angular中文社区`; }); } From 57ece992a866deacd3ff3dcf41f285b4b6212d52 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Thu, 27 Oct 2016 11:02:55 -0700 Subject: [PATCH 029/177] uses isNaN to check matched index when querying author --- src/app/_shared/api/authors/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/_shared/api/authors/index.ts b/src/app/_shared/api/authors/index.ts index 0007e84..2daae6d 100644 --- a/src/app/_shared/api/authors/index.ts +++ b/src/app/_shared/api/authors/index.ts @@ -72,6 +72,7 @@ export class AuthorApi { // 而Observable.never()不会调用observer的任何callback for (let i = 0; i < items.length; i++) { if(items[i].id === params.id) { + console.log(i); index = i // 找到了,index改成i,找不到,index还是null break; // 找到了,不用接着找了。 } @@ -90,7 +91,7 @@ export class AuthorApi { let author$: Observable; let item: Author; - if(index) { + if(!isNaN(index)) { item = items[index]; // 找到了,item改成找到的author } else { item = spectreAuthor; // 找不到,item改成spectreAuthor From 998fa9b59a6ab514c09e0e4f9b85ddf5bdc4bd16 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Thu, 27 Oct 2016 11:16:05 -0700 Subject: [PATCH 030/177] uses index===null to assert notFound --- src/app/_shared/api/authors/index.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/app/_shared/api/authors/index.ts b/src/app/_shared/api/authors/index.ts index 2daae6d..1488a35 100644 --- a/src/app/_shared/api/authors/index.ts +++ b/src/app/_shared/api/authors/index.ts @@ -91,10 +91,12 @@ export class AuthorApi { let author$: Observable; let item: Author; - if(!isNaN(index)) { - item = items[index]; // 找到了,item改成找到的author + if(index === null) { + // author not found, item = spectreAuthor + item = spectreAuthor; } else { - item = spectreAuthor; // 找不到,item改成spectreAuthor + // authoer found, item = author + item = items[index]; } return Observable.of(item) From d704839b3b2636b6a96590580c52aeb9b0cf84a0 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Thu, 27 Oct 2016 11:18:11 -0700 Subject: [PATCH 031/177] removes unnecessary console.log --- src/app/_shared/api/authors/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/_shared/api/authors/index.ts b/src/app/_shared/api/authors/index.ts index 1488a35..830c575 100644 --- a/src/app/_shared/api/authors/index.ts +++ b/src/app/_shared/api/authors/index.ts @@ -72,7 +72,6 @@ export class AuthorApi { // 而Observable.never()不会调用observer的任何callback for (let i = 0; i < items.length; i++) { if(items[i].id === params.id) { - console.log(i); index = i // 找到了,index改成i,找不到,index还是null break; // 找到了,不用接着找了。 } From a5cc89aef34c823809ec3e836b17019d9ae210bf Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Wed, 2 Nov 2016 03:52:34 -0700 Subject: [PATCH 032/177] adds simple-rxjs --- .../api/articles/simple-rxjs/_index.md | 270 ++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 src/app/_shared/api/articles/simple-rxjs/_index.md diff --git a/src/app/_shared/api/articles/simple-rxjs/_index.md b/src/app/_shared/api/articles/simple-rxjs/_index.md new file mode 100644 index 0000000..a70e5ec --- /dev/null +++ b/src/app/_shared/api/articles/simple-rxjs/_index.md @@ -0,0 +1,270 @@ +# 白话RxJS + +## 变量命名Style +(个人约定,非任何best practice) +- `Observable`变量以`$`结尾,如`state$`; +- `Subject`变量以`$$`结尾, 如`state$$`; +- `Subscription`变量以`_`结尾,如`ultimate_`。 + +## 写作目的 +`RxJS`包含许多概念,[RxJS Manual][]在介绍RxJS的时候,引入了更多概念,对于初学者而言,不够直白。 +比如: +> ReactiveX combines the Observer pattern with the Iterator pattern and functional programming with collections to fill the need for an ideal way of managing sequences of events. + +再如: +> Observable: represents the idea of an invokable collection of future values or events. + +本文将尝试用`白话`来解读RxJS。 +比如: +> `Observable`:好似一个`Function`,有很多`return`,定义了在哪个时点`return`什么数据。 + +部分章节使用了`伪代码`,用来说明某个类的特性;其余部分,受限于水平,实在写不出伪代码。 +难免错漏,敬请指正。 + +## `Observer`:一个`Object`,有3种`callback` +`Observer`最平易近人,就是一个`Object`,里面有3种`callback`,形如: + +```js +const observer = { + next: (value) => console.log(value), + error: (error) => console.log(error), + complete: () => console.log('completed') +} +``` + +## `Observable`:好似一个`Function`,有很多`return`,定义了在哪个时点`return`什么数据 +可以对照`Function`来看`Observable`。 +`Function`是这样: + +```js +const funcX = () => { + 在处理处理处理以后: + return 'gogogo, but only once'; +} +``` +`Observable`就是这样: + +```js +const x$ = () => { + (无条件的): + return 'I\'m the 1st go'; + 在'500 ms'以后: + return 'I\'m the 2nd go'; + ... + 在http请求出错时: + return 'something went wrong'; + // 然后就没有然后了 +} +``` +`Observable`可以`return`很多次,任意多次,每次`return`可能需要满足一定条件,比如“鼠标点击的时候”。 +可是,怎么可能`return`多于1次呢? +这是伪代码,其实`Observable`应该是这样: + +```js +const x$ = (observer) => { + (无条件的): + observer.next('I\'m the 1st go'); + 在'500 ms'以后: + observer.next('I\'m the 2nd go'); + ... + 在http请求出错时: + observer.error('something went wrong'); + // 然后就没有然后了 +} +``` +我们需要一个`Observer`,并用`observer.callback`来代替`return`。 + + +## 启动`Observable`:用`Observable.subscribe(observer)` +`Function`在定义好以后,不会自动运行,`Observable`也是一样。 +我们可以通过`funX()`(即在函数名后加上括号)来调用`funX`。 +怎样调用`Observable`呢?看这里: + +```js +const FakeObservableClass = function() { + this.execution = (observer) => { + observer.next('I\'m the 1st go'); + observer.next('I\'m the 2nd go'); + } +} + +FakeObservableClass.prototype.subscribe = function(observer) { + const that = this; + that.execution(observer); +} + +const x$ = new FakeObservableClass(); +const observer = {next: (value) => console.log(value)}; +x$.subscribe(observer); // 启动x$的运行 +``` +我们是通过`subscribe`方法,即`x$.subscribe(observer)`来启动`x$`的运行的。 + + +## `Subscription`:一个`Object`,有一个方法`unsubscribe`,可以停掉运行中的`Observable` +`Function`在启动以后是停不下来的,直到`return`。 +`Observable`在`subscribe`以后,如果`execution`的内容是`async`的(比如`setInterval`、`dom events`、`http response`),它是可以停下来的。 +以`IntervalObservable`为例: + +```js +const FakeIntervalObservableClass = function(interval) { + this.intervalId = null; + + this.execution = (observer) => { + let state = 0; + let execute = (state) => { + this.intervalId = setInterval(() => { + observer.next(++state); + }, interval); + } + execute(state); + } +} + +FakeIntervalObservableClass.prototype.subscribe = function(observer) { + const that = this; + that.execution(observer); // subscribe的时候会执行setInterval + // 接下来return一个Obeject,这个Object就是Subscription + return { + unsubscribe: () => { + clearInterval(that.intervalId); // unsubscribe时执行clearInterval + } + } +} + +const x$ = new FakeIntervalObservableClass(500); +const observer = {next: (value) => console.log(value)}; +const x_ = x$.subscribe(observer); +x_.unsubscribe(); +``` +`subscribe`方法返回一个`Object`,这个`Object`就是`Subscription`(即`x_`),它唯一的用途就是`unsubsribe`。 +`unsubscribe`会停下`Observable`的运行,并释放其占用的资源。 +上面的例子中,当我们调用`x_.unsubscribe()`的时候,触发了`clearInterval`,后面的execution就不再进行下去了。 +如果是`dom事件触发的Observable`,`subscribe`时会`addEventListener`,`unsubscribe`时会`removeEventListener`。 +如果是`XMLHttpRequest触发的Observable`,就是`send`和`abort`,等等。 + +## `Subject`:有`next`和`subscribe`方法,有一个observers列表 +`Subject`是一个`Observable`,因为它有`subscribe`方法;`Subject`又是一个`Observer`,因为它有`next`方法。 +它维护一个observers列表,当运行`subject.subscribe(observerX)`的时候,这个`observerX`就被加到列表里,`unsubscribe`时从列表中删掉。 +`Subject`像是一个proxy,外部可以调用`subject.next(value)`时,这个`value`会`forEach`给`Subject`的`observers`。 + +```js +const FakeSubjectClass = function() { + this.observers = []; +} + +FakeSubjectClass.prototype.subscribe = function(observer) { + let that = this; + // 添加新observer,获取其所在的index;添加之前会检查是否observers已经有了这个observer,这里偷懒了没写 + let indexA = (that.observers.push(observer) - 1); + return { + unsubscribe: () => { + // 从observers列表里将这个位置在indexA的observer删除 + that.observers = that.observers.filter((observer, index) => index !== indexA) + } + } +} + +FakeSubjectClass.prototype.next = function(value) { + let that = this; + that.observers.forEach(observer => observer.next(value)); // 外部调用subject.next,subject.next马上forEach转出去;这个就是multicast +} + +let x$$ = new FakeSubjectClass(); // Subject以$$结尾,Observable以$结尾 + +let observerB = {next: (value) => {console.log(`另一个logger说:${value}`)}} +x$$.subscribe(observerB); // 这个observerB被加到了x$$的observers列表里。 + +x$.subscribe(x$$); // 当x$向外推送时,调用的是x$$.next;x$$.next转身马上就forEach转给它的observers。 +``` +顺带提一下`unicast`和`multicast`的资源消耗。 +说`Observable`是`unicast`,而`Subject`是`multicast`,就是因为这个`observers列表` -- 在`Observable`里是没有的这个列表的。 +每次运行`Observable.subscribe()`都相当于一个`Function.call()`,是一个独立的运行,需要单独消耗资源。 +而`Subject.subscribe()`消耗资源很少。 +比如: + +```js +let y$ = Observable.whatever() // 创建新的Observable +let y1_ = y$.subscribe(observerA); // 运行一次y$里的execution,消耗资源 +let y2_ = y$.subscribe(observerB); // 又运行一次... +let y3_ ... // 又... +// =========== + +let z$ = Observable.whatever(); +let z$$ = new Subject(); +let z1_ = z$$.subscribe(observerX) // observers列表里加一项,基本不消耗什么资源 +let z2_ = z$$.subscribe(observerY) // observers列表里加一项 +let z0_ = z$.subscribe(z$$) // 运行一次z$里的execution,仅此一次,然后z$推给z$$,z$$用forEach推给后面 + +``` + +## `Operator`:一半AllSpark(创建`Observable`),一半滤镜(变更推送时点和推送内容) +在`Observable类`上调用的`Operator`是`Static Operator`, 比如: + +```js +Observable.interval(500); // 每隔500ms,推送一个递增整数,从0开始 +Observable.from([1, 2]); // 连续推送1, 2 +Observable.fromEvent(document, 'click'); +Observable.fromPromise(fetch('http://github.com/users')); +Observable.merge(x$, y$); // 将x$与y$的推送混合在一起 +Observable.concat(x$, y$); // 先运行x$,等x$推送observer.complete(),再运行y$ +... +``` +`Static Operator`可以从无到有创建一个`Observable`(像是变形金刚里的AllSpark),也可以把互不干预的`Observable`组合起来。 +前面的伪代码中用到`const x$ = new FakeObservableClass();`。 +实际生活中`new Observable()`都是由Static Operator来处理的,所以在代码中不会看到`new Observable()`。 + +===== 分割线 ===== + +在`Observable的实例`上调用的`Operator`是`Instance Operator`, 比如: + +```js +const x$ = Observable.interval(500); // 创建一个Observable实例 +const y$ = x$ + .map(v => v*3) // 每个推送的数值乘以3 + .filter(w => w%5 === 1) // 只推送除以5余数为1的数值 + .delay(1000) // 等待1秒再推送 + .take(10) // 推送10个数值以后,调用observer.complete()结束 +x$ !== y$ // x$还是那个x$ +... +``` +如果`Observable`是一幅画,`Instance Operator`就是滤镜。 +经过滤镜处理,我们拿到的一幅新的画,原来的画还在。 + + +## `Scheduler`:控制并发事件 +`Scheduler`的职能是控制并发事件。本人开发经验接近0,实在想不出实际生活中何时会用到`Scheduler`,也确实在实践中没用过。 +如果要观察每种`Scheduler`对数据推送的影响,可以打开[RxJS Manual][],开启`console`,贴入下面的代码,回车。 + +```js +const x$ = Rx.Observable.create((observer) => { + observer.next(0); + observer.next(1); +}) // 这个用的是null Scheduler +const xOnQueue$ = x$.map(v=>'onQueue'+v).observeOn(Rx.Scheduler.queue); +const xOnAsync$ = x$.map(v=>'onAsync'+v).observeOn(Rx.Scheduler.async); +const xOnAsap$ = x$.map(v=>'onAsap'+v).observeOn(Rx.Scheduler.asap); +const xOnAnimationFrame$ = x$.map(v=>'onAnimationFrame'+v).observeOn(Rx.Scheduler.animationFrame); +const merged$ = Rx.Observable.merge(xOnAnimationFrame$, xOnAsync$, xOnAsap$, xOnQueue$, x$); +// 注意Observable.merge时的顺序,再对照console.log中的输出顺序 +const merged_ = merged$.subscribe(console.log); +``` + +## `TestScheduler`:虚拟时间机器 +TestScheduler是测试RxJS代码时用到的一个虚拟时间机器,Observable可以挂靠其上。 +我们定义的Observable在真实环境下可能要跑上一段时间才结束。而在TestScheduler里,就是一个同步的执行。 +比如`Observable.interval(20).take(20)`,这个`observable`每隔20 ms推送一个递增数字,一共推20个,需要用时400 ms。 +通过`Observable.interval(20, testScheduler).take(20)`,来设定`Observable`运行在虚拟时间机器上,在测试环境下,瞬间结束。 +其中的`testScheduler`是`TestScheduler`的一个实例。 +关于如何使用TestScheduler,后续文章中会提到。 + +## 总结 +提到`Observable`的时候,就想想`Function`,一个有随意数量`return`的`Function`。 + +Happy coding! + +## 参考 +[RxJS Source Code][] +[RxJS Manual][] + +[RxJS Source Code]: https://github.com/ReactiveX/rxjs +[RxJS Manual]: http://reactivex.io/rxjs/manual/index.html From e29b17a6e1884436006801f131f3924a8eeab08f Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Wed, 2 Nov 2016 06:50:43 -0700 Subject: [PATCH 033/177] corrects some typo and deletes testScheduler part --- src/app/_shared/api/articles/simple-rxjs/_index.md | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/app/_shared/api/articles/simple-rxjs/_index.md b/src/app/_shared/api/articles/simple-rxjs/_index.md index a70e5ec..3b0e37e 100644 --- a/src/app/_shared/api/articles/simple-rxjs/_index.md +++ b/src/app/_shared/api/articles/simple-rxjs/_index.md @@ -1,5 +1,7 @@ # 白话RxJS +初稿日期:2016-11-02 + ## 变量命名Style (个人约定,非任何best practice) - `Observable`变量以`$`结尾,如`state$`; @@ -145,7 +147,7 @@ x_.unsubscribe(); ## `Subject`:有`next`和`subscribe`方法,有一个observers列表 `Subject`是一个`Observable`,因为它有`subscribe`方法;`Subject`又是一个`Observer`,因为它有`next`方法。 它维护一个observers列表,当运行`subject.subscribe(observerX)`的时候,这个`observerX`就被加到列表里,`unsubscribe`时从列表中删掉。 -`Subject`像是一个proxy,外部可以调用`subject.next(value)`时,这个`value`会`forEach`给`Subject`的`observers`。 +`Subject`像是一个proxy,外部调用`subject.next(value)`时,这个`value`会被`forEach`给`Subject`的`observers`。 ```js const FakeSubjectClass = function() { @@ -228,7 +230,7 @@ x$ !== y$ // x$还是那个x$ ... ``` 如果`Observable`是一幅画,`Instance Operator`就是滤镜。 -经过滤镜处理,我们拿到的一幅新的画,原来的画还在。 +经过滤镜处理,我们拿到了一幅新的画,原来的画还在。 ## `Scheduler`:控制并发事件 @@ -249,13 +251,6 @@ const merged$ = Rx.Observable.merge(xOnAnimationFrame$, xOnAsync$, xOnAsap$, xOn const merged_ = merged$.subscribe(console.log); ``` -## `TestScheduler`:虚拟时间机器 -TestScheduler是测试RxJS代码时用到的一个虚拟时间机器,Observable可以挂靠其上。 -我们定义的Observable在真实环境下可能要跑上一段时间才结束。而在TestScheduler里,就是一个同步的执行。 -比如`Observable.interval(20).take(20)`,这个`observable`每隔20 ms推送一个递增数字,一共推20个,需要用时400 ms。 -通过`Observable.interval(20, testScheduler).take(20)`,来设定`Observable`运行在虚拟时间机器上,在测试环境下,瞬间结束。 -其中的`testScheduler`是`TestScheduler`的一个实例。 -关于如何使用TestScheduler,后续文章中会提到。 ## 总结 提到`Observable`的时候,就想想`Function`,一个有随意数量`return`的`Function`。 From 83d054ec4cdbb25394a87d620ff2249df454d1f5 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Mon, 24 Oct 2016 22:46:15 -0700 Subject: [PATCH 034/177] adds mock-redux-with-rxjs --- src/app/_shared/api/articles/index.ts | 9 + .../articles/mock-redux-with-rxjs/_index.md | 179 ++++++++++++++++++ 2 files changed, 188 insertions(+) create mode 100644 src/app/_shared/api/articles/mock-redux-with-rxjs/_index.md diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 6cb33ce..12bd9fb 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -246,6 +246,15 @@ const items: Article[] = [ tags: ['现在'], authors: ['雪狼'], }, + { + id: '应用RxJS模拟Redux', + title: '应用RxJS模拟Redux', + summary: '参考RxJS Doc中的state store示例,加入Subject,模拟Redux。', + content: require('./mock-redux-with-rxjs/_index.md'), + first: true, + tags: ['RxJS'], + authors: [], + }, ]; @Injectable() diff --git a/src/app/_shared/api/articles/mock-redux-with-rxjs/_index.md b/src/app/_shared/api/articles/mock-redux-with-rxjs/_index.md new file mode 100644 index 0000000..6ce6a06 --- /dev/null +++ b/src/app/_shared/api/articles/mock-redux-with-rxjs/_index.md @@ -0,0 +1,179 @@ +初稿日期:2016年10月25日 + +## 写作原因/目的 +大家可能听过或是正在用[Redux][]这个库。 +应用Redux,我们不再直接修改app state,而是把app state存放在一个store里面,通过store.dispatch(action)来发送action,而后触发一个reducer函数(reducer是一个pure function),这个reducer函数依据action来改变app state,再用store.subscribe()把app state推送出去。 + +这里有个subscribe()哦。看看redux的package.json,里面有rxjs哦。 + +那么如何用rxjs来直接实现state store的功能呢? +rxjs的文档里就有答案,不过在reactivex.io/rxjs里面找不到,而是在github的repo里。 +[RxJS官方教程 - State Stores][] +本文将尝试通过引入Subject来扩展文档示例中的state store的功能。 + +这里先吐槽一下,[RxJS Doc在github上的源码][]里有这么一句: +> These files are not meant for reading directly in GitHub, ... You should find the docs at http://reactivex.io/rxjs/, ... + +但是呢,有几个非常有用的.md文件,在reactivex.io/rxjs里是找不到的。 +其中一个.md里面就有这个state store。 +强烈建议大家翻阅一下[RxJS Doc在github上的源码][]。 + + +## 相关概念 +以下为粗略理解,具体参见[官方文档][]。 +1. Observer:一个Object,里面有3个callback,形如{next: nextFn, error: errorFn, complete: completeFn},3个callback都不是必须的。 +2. Observable:定义某个时点通过调用observer.callback(v)来推送数据v,可以推无数个数据,通过subscribe()来启动执行,即使不给subscribe()传入任何参数。 +3. Subject:既是一个Observer(有next callback),又是一个Observable(将数据转推出去)。 +4. BehaviorSubject:是一个Subject,能留存最后一个数据;创建时需指定初始数据;可以通过getValue()获取留存的最后一个数据。(RxJS version 5文档中没提getValue()) +5. [scan operator][]:如果把Observable推送的数据流类比成Array的话,scan operator就是Array.reduce。 + +示例: +```js +const observer = {next: (v) => console.log(v)} // 一个Observer,只有next callback。 +const observable$ = Observable.create((observer) => { + observer.next(0); + setTimeout(()=>observer.next(1), 10) + // ... +} // 创建一个Observable,在time 0的时候推送数据0, 并调用observer.next;在time 10的时候推送数据1,...。 +observerable$.subscribe(observer) // 启动observable,并指定数据传给observer。 + +const subject$$ = new Subject() // 创建一个Subject +observable$.subscribe(subject$$) // 因为subject$$是一个observer +subject$$.subscribe(observer) // 因为subject$$也是一个observable + +const subjectB$$ = new BehaviorSubject(9) // 创建一个BehaviorSubject, 需要一个初始值 +subjectB$$.subscribe(observable) // 订阅一个BehaviorSubject,会把当前数据立即推送给observer +console.log(subjectB$$.getValue()) // getValue()获取留存的最后一个数据 + +observable$.scan((accumulated, current) => accumulated + current, 0) +// 类似Array的reduce,如[1, 2, 3].reduce((acc, curr) => acc + curr, 0) +``` + + +## 编写代码 + +变量命名规则: +Observable以`$`结尾,如`state$`; +Subject以`$$`结尾, 如`state$$`: +Subscription以`_`结尾,如`ultimate_`。 + +故事梗概: +(action$$和state$$都是Subject,在外部推送数据给他们后,他们会转发出去。) +外部推action给action$$,action被映射(即map)成changeFn,changeFn被递归(即scan)成state,state再被推给state$$,再转推给console.log。 +比如,外部推`INCREASE`给action$$,`INCREASE`被map成一个fn`(state)=>state+1`,这个fn被scan成一个新的state,如果上一个state是0的话,这个新的state就是1,这个state再被推给state$$,再转推给console.log。 + +为什么不直接将action映射成state,而是将action映射成changeFn呢? +如果要把action映射成state,每次映射操作都要通过`state$$.getValue()`来获取currentState,这就像在一个function里面使用一个global变量。 +而将action映射成changeFn,映射过程没有外部变量,更容易测试。 + + +代码: + +```js +/* + 定义interfaces, types; + 定义INCREASE, DECREASE两个常数,这样,后面可以用INCREASE变量来代替'INCREASE'字符串; +*/ +type ActionType = 'INCREASE' | 'DECREASE' +interface Action { + type: ActionType +} +const INCREASE: ActionType = 'INCREASE'; +const DECREASE: ActionType = 'DECREASE'; +type State = number; +type ChangeFn = (state: State) => State; + +/* + 创建action$$,负责转发action。 + 创建state$$,负责转发state,并留存最近的state,初始值为0。 + 立即用console.log订阅到state$$,这样避免漏数据。 + 在console.log订阅到state$$之后,state$$会立即将留存的state推给console.log,在console上看到0。 +*/ +const action$$: Subject = new Subject() +const state$$: BehaviorSubject = new BehaviorSubject(0) +const ultimate_: Subscription = state$$.subscribe(console.log); // will log 0 immediately + +/* + changeFn$将action映射(map)成changeFn。 +*/ +const changeFn$: Observable = action$$ + .map((action: Action) => { + switch (action.type) { + case INCREASE: + return (state: State) => state + 1; + case DECREASE: + return (state: State) => state - 1; + default: + return (state: State) => state; + } + }) + +/* + state$将changFn递归(scan)成state,state初始为0。 +*/ +const state$: Observable = changeFn$ + .scan((state, changeFn) => changeFn(state), 0) + +/* + 用state$$订阅state$,state$开始向state$$推送数据 +*/ +const intermediate_: Subscription = state$.subscribe(state$$) + +/* + 用action$$.next()来向action$$推送action; + 这个action会经过map,scan变成一个state,然后被推给state$$,然后推给console.log +*/ +action$$.next({type: INCREASE}) // 1 +action$$.next({type: INCREASE}) // 2 +action$$.next({type: DECREASE}) // 1 + +/* + 获取最近的state,用BehaviorSubject.getValue() +*/ +console.log(state$$.getValue()) // current state is 1 + +// 在页面上创建两个按钮 +const section = document.createElement('section') +document.body.appendChild(section); +const incButton = document.createElement('button'); +incButton.innerText = INCREASE; +section.appendChild(incButton); +const decButton = document.createElement('button'); +decButton.innerText = DECREASE; +section.appendChild(decButton); + + +/* + 创建click事件Observable,每次点按会推送一个action给action$$。 + 立即调用subscribe(),以启动Observable,这里不必指定任何observer。 +*/ +Observable.fromEvent(incButton, 'click') + .map(() => action$$.next({type: INCREASE})).subscribe() +Observable.fromEvent(decButton, 'click') + .map(() => action$$.next({type: DECREASE})).subscribe() +``` + +## repo +以上源码可以在这个[repo][]里找到。 + +## 总结 +这样,可以少一个dependency了。 +希望通过此文,可以帮助大家进一步了解RxJS,尤其是其中的Subject和scan operator。 + + +## 参考 +[Redux][] +[RxJS官方教程 - State Stores][] +[RxJS Doc在github上的源码][] +[官方文档][] +[scan operator][] + + +Happy coding! + +[RxJS官方教程 - State Stores]: https://github.com/ReactiveX/rxjs/blob/master/doc/tutorial/applications.md#state-stores +[Redux]: https://github.com/reactjs/redux#the-gist +[RxJS Doc在github上的源码]: https://github.com/ReactiveX/rxjs/tree/master/doc#rxjs-official-docs-at-httpreactivexiorxjs +[repo]: https://github.com/rxjs-space/rxjs-typescript-starter +[官方文档]: http://reactivex.io/rxjs/manual/overview.html +[scan operator]: http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-scan From d0d6e54c6e19a2c3a62e7a6d2302f06932fff071 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Thu, 27 Oct 2016 10:15:50 -0700 Subject: [PATCH 035/177] redux-mock article v2 --- src/app/_shared/api/articles/index.ts | 8 +- .../articles/mock-redux-with-rxjs/_index.md | 237 +++++++++++------- 2 files changed, 156 insertions(+), 89 deletions(-) diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 12bd9fb..cfa8267 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -247,13 +247,13 @@ const items: Article[] = [ authors: ['雪狼'], }, { - id: '应用RxJS模拟Redux', - title: '应用RxJS模拟Redux', - summary: '参考RxJS Doc中的state store示例,加入Subject,模拟Redux。', + id: '应用RxJS模拟redux', + title: '应用RxJS模拟redux', + summary: '参照RxJS Doc中的state store示例,加入Subject,模拟redux。', content: require('./mock-redux-with-rxjs/_index.md'), first: true, tags: ['RxJS'], - authors: [], + authors: ['Tim刘'], }, ]; diff --git a/src/app/_shared/api/articles/mock-redux-with-rxjs/_index.md b/src/app/_shared/api/articles/mock-redux-with-rxjs/_index.md index 6ce6a06..de6782f 100644 --- a/src/app/_shared/api/articles/mock-redux-with-rxjs/_index.md +++ b/src/app/_shared/api/articles/mock-redux-with-rxjs/_index.md @@ -1,82 +1,135 @@ 初稿日期:2016年10月25日 +## 变量名Style约定 +(这是我个人的Style约定,并非任何Best Practice。) +* `Observable`变量以`$`结尾,如`state$`; +* `Subject`变量以`$$`结尾, 如`state$$`; +* `Subscription`变量以`_`结尾,如`ultimate_`。 + ## 写作原因/目的 -大家可能听过或是正在用[Redux][]这个库。 -应用Redux,我们不再直接修改app state,而是把app state存放在一个store里面,通过store.dispatch(action)来发送action,而后触发一个reducer函数(reducer是一个pure function),这个reducer函数依据action来改变app state,再用store.subscribe()把app state推送出去。 +大家可能听过或是正在用[redux][]这个库。 +示例(拷贝过来的,他们不打";"): +```js +import { createStore } from 'redux' + +// 这个是Reducer函数,a pure function +function counter(state = 0, action) { + switch (action.type) { + case 'INCREMENT': + return state + 1 + case 'DECREMENT': + return state - 1 + default: + return state + } +} -这里有个subscribe()哦。看看redux的package.json,里面有rxjs哦。 +let store = createStore(counter) -那么如何用rxjs来直接实现state store的功能呢? -rxjs的文档里就有答案,不过在reactivex.io/rxjs里面找不到,而是在github的repo里。 -[RxJS官方教程 - State Stores][] -本文将尝试通过引入Subject来扩展文档示例中的state store的功能。 +store.subscribe(() => + console.log(store.getState()) +) -这里先吐槽一下,[RxJS Doc在github上的源码][]里有这么一句: -> These files are not meant for reading directly in GitHub, ... You should find the docs at http://reactivex.io/rxjs/, ... +store.dispatch({ type: 'INCREMENT' }) // will log 1 on the console +``` +应用redux,我们不再直接修改`state`,而是把`state`存放在一个`store`里面,通过`store.dispatch(action)`来发送`action`, +这个`action`会触发一个`Reducer`函数,这个`Reducer`函数依据`action`来改变`state`, +而后,再用`store.subscribe(responseFn)`启动store的运转, +每次state变化,都会触发`responseFn`,上面示例中,每次`state`变化,都会触发`() => console.log(store.getState()`, +而`store.getState()`就是最新的`state`。 -但是呢,有几个非常有用的.md文件,在reactivex.io/rxjs里是找不到的。 -其中一个.md里面就有这个state store。 -强烈建议大家翻阅一下[RxJS Doc在github上的源码][]。 +注意:这里有个`subscribe()`哦,那么,`store`是不是一个`Observable`呢? +再来看看redux的`package.json`,里面有RxJS哦。 +如此,可以大体断定,redux在实现State Store功能的过程中,用到了RxJS。 + +那么我们能不能直接用RxJS来直接实现State Store的功能呢? +RxJS的文档里就有答案,不过不是在[reactivex.io/rxjs][],而是在Github的Repo里。 +就在这里:[RxJS官方教程 - State Stores][]。 +本文将先介绍一些RxJS的基本概念, 而后,依据官方State Stores示例,并引入`Subject`,来实现开头部分redux示例中的功能。 +水平所限,难免有错漏,请大家多指教。另外,我写的比较啰嗦,请大家多包涵。 ## 相关概念 以下为粗略理解,具体参见[官方文档][]。 -1. Observer:一个Object,里面有3个callback,形如{next: nextFn, error: errorFn, complete: completeFn},3个callback都不是必须的。 -2. Observable:定义某个时点通过调用observer.callback(v)来推送数据v,可以推无数个数据,通过subscribe()来启动执行,即使不给subscribe()传入任何参数。 -3. Subject:既是一个Observer(有next callback),又是一个Observable(将数据转推出去)。 -4. BehaviorSubject:是一个Subject,能留存最后一个数据;创建时需指定初始数据;可以通过getValue()获取留存的最后一个数据。(RxJS version 5文档中没提getValue()) -5. [scan operator][]:如果把Observable推送的数据流类比成Array的话,scan operator就是Array.reduce。 - -示例: -```js -const observer = {next: (v) => console.log(v)} // 一个Observer,只有next callback。 -const observable$ = Observable.create((observer) => { - observer.next(0); - setTimeout(()=>observer.next(1), 10) - // ... -} // 创建一个Observable,在time 0的时候推送数据0, 并调用observer.next;在time 10的时候推送数据1,...。 -observerable$.subscribe(observer) // 启动observable,并指定数据传给observer。 - -const subject$$ = new Subject() // 创建一个Subject -observable$.subscribe(subject$$) // 因为subject$$是一个observer -subject$$.subscribe(observer) // 因为subject$$也是一个observable - -const subjectB$$ = new BehaviorSubject(9) // 创建一个BehaviorSubject, 需要一个初始值 -subjectB$$.subscribe(observable) // 订阅一个BehaviorSubject,会把当前数据立即推送给observer -console.log(subjectB$$.getValue()) // getValue()获取留存的最后一个数据 - -observable$.scan((accumulated, current) => accumulated + current, 0) -// 类似Array的reduce,如[1, 2, 3].reduce((acc, curr) => acc + curr, 0) -``` - +1. `Observer`:是一个Object,里面有3个Callback,形如`{next: nextFn, error: errorFn, complete: completeFn}`。 + 3个Callback都不是必须的,但要按顺序写,比如`{next: null, error: null, complete: completeFn}`。 + 示例: + ```js + const observer = {next: (v) => console.log(v)}; // 这个Observer只有next callback + ``` +2. `Observable`:定义在某个时点通过调用`observer.callback(v)`(比如`observer.next(v)`)将数据`v`推送给`observer`; + `Observable`不会自动运行,而是要通过`subscribe`方法来启动, + 比如,`observable.subscribe(observer)`就是启动`observable`,同时指定`observer`为数据推送对象; + 注意:即使不向`subscribe`传送任何参数,也是可以启动`observable`的,即`observable.subscribe()`就能启动`observable`。 + 示例: + ```js + const observable$ = Observable.create((observer) => { + observer.next(0); + setTimeout(()=>observer.next(1), 10); + // ... + } // 创建一个Observable,在observable$启动后,time 0的时候推送数据0, 并调用observer.next;在time 10的时候推送数据1,...。 + // 创建Observable的方式有很多,Observable.create只是其中一种。 + + observable$.subscribe(observer); // 启动observable,并指定数据传给observer。 + // observable$.subscribe({next: nextFn}) 可以简写成 observable$.subscribe(nextFn) + ``` +3. `Subject`:既是一个`Observer`(有`next` Callback,即`subject.next(v)`),又是一个`Observable`(有`subscribe`方法,即`subject.subcribe(observer)`)。 + 示例: + ```js + const subject$$ = new Subject(); // 创建一个Subject + observable$.subscribe(subject$$); // 因为subject$$是一个observer,我们可以用subject$$来订阅observable$ + subject$$.subscribe(observer); // 因为subject$$也是一个observable,它可以被别的observer订阅 + ``` +4. `BehaviorSubject`:是一个`Subject`,能留存最后一个数据;创建时需指定初始数据; + 可以通过`getValue()`获取留存的最后一个数据。(RxJS version 5文档中没提`getValue`方法) + 示例: + ```js + const subjectB$$ = new BehaviorSubject(9); // 创建一个BehaviorSubject, 需要一个初始值 + subjectB$$.subscribe(observable); // 订阅一个BehaviorSubject,会把当前数据立即推送给observer + console.log(subjectB$$.getValue()); // getValue()获取留存的最后一个数据 + ``` +5. [scan运算符][]:如果把`Observable`推送的数据流类比成`Array`的话,那么`Observable.scan`运算符就是`Array.reduce`。 + (可是`Observable.scan`该怎么翻译呢?`Array.reduce`呢?) + 示例: + ```js + observable$.scan((accumulated, current) => accumulated + current, 0); + // 类似Array的reduce,比如:[1, 2, 3].reduce((acc, curr) => acc + curr, 0); + ``` ## 编写代码 -变量命名规则: -Observable以`$`结尾,如`state$`; -Subject以`$$`结尾, 如`state$$`: -Subscription以`_`结尾,如`ultimate_`。 +Repo: +以下代码可以在这个[repo][]里找到。 + +主演: +1. `action$$`:一个`Subject`,负责转推`action`(转推,就是外部推给它,它再推出去)。 +2. `state$$`:一个`BehaviorSubject`,负责转推`state`,并存储最后一个`state`,即最近跟新的`state`。 故事梗概: -(action$$和state$$都是Subject,在外部推送数据给他们后,他们会转发出去。) -外部推action给action$$,action被映射(即map)成changeFn,changeFn被递归(即scan)成state,state再被推给state$$,再转推给console.log。 -比如,外部推`INCREASE`给action$$,`INCREASE`被map成一个fn`(state)=>state+1`,这个fn被scan成一个新的state,如果上一个state是0的话,这个新的state就是1,这个state再被推给state$$,再转推给console.log。 +1. 外部通过`action$$.next(action)`将`action`推送给`action$$`,这个“外部”可以是个定时器、DOM事件或是Http请求的返回; +2. `action$$`在转推的时候,`action`被映射(“映射”指的就是`map`)成`changeFn`; +3. `changeFn`被那啥(“那啥”指的就是`scan`)成`state`; +4. `state`再被推给`state$$`; +5. `state$$`再将`state`转推给`console.log`。 + +比如,外部推`INCREASE`给`action$$`,`INCREASE`被`map`成一个`changeFn`,即`(state)=>state+1`,这个`changeFn`被`scan`成一个新的`state`, +如果上一个`state`是`0`的话,根据`changeFn`,这个新的`state`就是`1`,这个`state`再被推给`state$$`,再转推给`console.log`。 -为什么不直接将action映射成state,而是将action映射成changeFn呢? -如果要把action映射成state,每次映射操作都要通过`state$$.getValue()`来获取currentState,这就像在一个function里面使用一个global变量。 -而将action映射成changeFn,映射过程没有外部变量,更容易测试。 +为什么不直接将`action`映射成`state`,而是将`action`映射成`changeFn`呢? +如果要把`action`映射成`state`,每次映射操作都要通过`state$$.getValue()`来获取`currentState`,这就像在一个`function`里面使用一个全局变量。 +而将`action`映射成`changeFn`,映射过程没有外部变量,更容易测试。 代码: ```js /* - 定义interfaces, types; - 定义INCREASE, DECREASE两个常数,这样,后面可以用INCREASE变量来代替'INCREASE'字符串; + 定义interfaces, types。 + 定义INCREASE, DECREASE两个常数,这样,后面可以用INCREASE变量来代替'INCREASE'字符串,避免typo。 */ -type ActionType = 'INCREASE' | 'DECREASE' +type ActionType = 'INCREASE' | 'DECREASE'; interface Action { - type: ActionType + type: ActionType; } const INCREASE: ActionType = 'INCREASE'; const DECREASE: ActionType = 'DECREASE'; @@ -84,17 +137,18 @@ type State = number; type ChangeFn = (state: State) => State; /* - 创建action$$,负责转发action。 - 创建state$$,负责转发state,并留存最近的state,初始值为0。 + 创建action$$,负责转推action。 + 创建state$$,负责转推state,并留存最近的state,初始值为0。 立即用console.log订阅到state$$,这样避免漏数据。 在console.log订阅到state$$之后,state$$会立即将留存的state推给console.log,在console上看到0。 */ -const action$$: Subject = new Subject() -const state$$: BehaviorSubject = new BehaviorSubject(0) +const action$$: Subject = new Subject(); +const state$$: BehaviorSubject = new BehaviorSubject(0); const ultimate_: Subscription = state$$.subscribe(console.log); // will log 0 immediately /* - changeFn$将action映射(map)成changeFn。 + changeFn$将action "map成" changeFn。 + changeFn$不会自动运行。 */ const changeFn$: Observable = action$$ .map((action: Action) => { @@ -109,31 +163,35 @@ const changeFn$: Observable = action$$ }) /* - state$将changFn递归(scan)成state,state初始为0。 + state$将changeFn "scan成" state,state初始为state$$的当前数值,即state$$.getValue()。 + state$不会自动运行。 */ const state$: Observable = changeFn$ - .scan((state, changeFn) => changeFn(state), 0) + .scan((state, changeFn) => changeFn(state), 0); /* - 用state$$订阅state$,state$开始向state$$推送数据 + 用state$$订阅state$,state$开始运行,并向state$$推送数据,state$$再转推给console.log */ -const intermediate_: Subscription = state$.subscribe(state$$) +const intermediate_: Subscription = state$.subscribe(state$$); /* 用action$$.next()来向action$$推送action; 这个action会经过map,scan变成一个state,然后被推给state$$,然后推给console.log */ -action$$.next({type: INCREASE}) // 1 -action$$.next({type: INCREASE}) // 2 -action$$.next({type: DECREASE}) // 1 +action$$.next({type: INCREASE}); // 1 +action$$.next({type: INCREASE}); // 2 +action$$.next({type: DECREASE}); // 1 /* 获取最近的state,用BehaviorSubject.getValue() */ -console.log(state$$.getValue()) // current state is 1 +console.log(state$$.getValue()); // current state is 1 -// 在页面上创建两个按钮 -const section = document.createElement('section') +/* + 我们再用DOM事件来向action$$推送action。 + 先创建两个按钮。 +*/ +const section = document.createElement('section'); document.body.appendChild(section); const incButton = document.createElement('button'); incButton.innerText = INCREASE; @@ -144,36 +202,45 @@ section.appendChild(decButton); /* - 创建click事件Observable,每次点按会推送一个action给action$$。 - 立即调用subscribe(),以启动Observable,这里不必指定任何observer。 + 创建click事件Observable,定义每次点按会推送一个action给action$$。 + 而后合并所有的click$至一个observable,并用subscribe()启动运行。 */ -Observable.fromEvent(incButton, 'click') - .map(() => action$$.next({type: INCREASE})).subscribe() -Observable.fromEvent(decButton, 'click') - .map(() => action$$.next({type: DECREASE})).subscribe() -``` +const incButtonClick$ = Observable.fromEvent(incButton, 'click') + .map(() => action$$.next({type: INCREASE})); +const decButtonClick$ = Observable.fromEvent(decButton, 'click') + .map(() => action$$.next({type: DECREASE})); -## repo -以上源码可以在这个[repo][]里找到。 +const clicks_ = Observable.merge(incButtonClick$, decButtonClick$) + .subscribe(); // 这里不需要像subscribe()传递任何参数 +``` ## 总结 -这样,可以少一个dependency了。 -希望通过此文,可以帮助大家进一步了解RxJS,尤其是其中的Subject和scan operator。 +这样,是不是就可以不用装redux了? + +希望通过此文,能够帮助大家进一步了解RxJS,尤其是其中的Subject和scan运算符。 ## 参考 -[Redux][] +[redux][] [RxJS官方教程 - State Stores][] [RxJS Doc在github上的源码][] [官方文档][] -[scan operator][] +[scan运算符][] + +## 吐槽 +[RxJS Doc在github上的源码][]里有这么一句: +> These files are not meant for reading directly in GitHub, ... You should find the docs at http://reactivex.io/rxjs/, ... +但是呢,有几个非常有用的.md文件,在reactivex.io/rxjs里是找不到的。 +其中一个.md里面就有这个State Store。 +强烈建议大家翻阅一下[RxJS Doc在github上的源码][]。 -Happy coding! +**Happy coding!** +[reactivex.io/rxjs]: http://reactivex.io/rxjs [RxJS官方教程 - State Stores]: https://github.com/ReactiveX/rxjs/blob/master/doc/tutorial/applications.md#state-stores -[Redux]: https://github.com/reactjs/redux#the-gist +[redux]: https://github.com/reactjs/redux#the-gist [RxJS Doc在github上的源码]: https://github.com/ReactiveX/rxjs/tree/master/doc#rxjs-official-docs-at-httpreactivexiorxjs [repo]: https://github.com/rxjs-space/rxjs-typescript-starter [官方文档]: http://reactivex.io/rxjs/manual/overview.html -[scan operator]: http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-scan +[scan运算符]: http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-scan From 532b164f52e6888246bfcb2c365dfd99fffd79f1 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Wed, 2 Nov 2016 21:43:01 -0700 Subject: [PATCH 036/177] removes back-ticks in the sub-titles --- src/app/_shared/api/articles/index.ts | 9 ++++++ .../api/articles/simple-rxjs/_index.md | 28 +++++++++++-------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index cfa8267..e5459d3 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -255,6 +255,15 @@ const items: Article[] = [ tags: ['RxJS'], authors: ['Tim刘'], }, + { + id: '白话RxJS', + title: '白话RxJS', + summary: '尝试使用“白话”来介绍RxJS。', + content: require('./simple-rxjs/_index.md'), + first: true, + tags: ['RxJS'], + authors: ['Tim刘'], + }, ]; @Injectable() diff --git a/src/app/_shared/api/articles/simple-rxjs/_index.md b/src/app/_shared/api/articles/simple-rxjs/_index.md index 3b0e37e..c3f52e0 100644 --- a/src/app/_shared/api/articles/simple-rxjs/_index.md +++ b/src/app/_shared/api/articles/simple-rxjs/_index.md @@ -20,10 +20,10 @@ 比如: > `Observable`:好似一个`Function`,有很多`return`,定义了在哪个时点`return`什么数据。 -部分章节使用了`伪代码`,用来说明某个类的特性;其余部分,受限于水平,实在写不出伪代码。 +部分章节使用了`伪代码`,用来说明某个类的特性;其余部分,受限于水平,实在写不出伪代码。 难免错漏,敬请指正。 -## `Observer`:一个`Object`,有3种`callback` +## Observer:一个Object,有3种callback `Observer`最平易近人,就是一个`Object`,里面有3种`callback`,形如: ```js @@ -34,7 +34,7 @@ const observer = { } ``` -## `Observable`:好似一个`Function`,有很多`return`,定义了在哪个时点`return`什么数据 +## Observable:好似一个Function,有很多return,定义了在哪个时点return什么数据 可以对照`Function`来看`Observable`。 `Function`是这样: @@ -77,7 +77,7 @@ const x$ = (observer) => { 我们需要一个`Observer`,并用`observer.callback`来代替`return`。 -## 启动`Observable`:用`Observable.subscribe(observer)` +## 启动Observable:用Observable.subscribe(observer) `Function`在定义好以后,不会自动运行,`Observable`也是一样。 我们可以通过`funX()`(即在函数名后加上括号)来调用`funX`。 怎样调用`Observable`呢?看这里: @@ -102,7 +102,7 @@ x$.subscribe(observer); // 启动x$的运行 我们是通过`subscribe`方法,即`x$.subscribe(observer)`来启动`x$`的运行的。 -## `Subscription`:一个`Object`,有一个方法`unsubscribe`,可以停掉运行中的`Observable` +## Subscription:一个Object,有一个方法unsubscribe,可以停掉运行中的Observable `Function`在启动以后是停不下来的,直到`return`。 `Observable`在`subscribe`以后,如果`execution`的内容是`async`的(比如`setInterval`、`dom events`、`http response`),它是可以停下来的。 以`IntervalObservable`为例: @@ -144,7 +144,7 @@ x_.unsubscribe(); 如果是`dom事件触发的Observable`,`subscribe`时会`addEventListener`,`unsubscribe`时会`removeEventListener`。 如果是`XMLHttpRequest触发的Observable`,就是`send`和`abort`,等等。 -## `Subject`:有`next`和`subscribe`方法,有一个observers列表 +## Subject:有next和subscribe方法,有一个observers列表 `Subject`是一个`Observable`,因为它有`subscribe`方法;`Subject`又是一个`Observer`,因为它有`next`方法。 它维护一个observers列表,当运行`subject.subscribe(observerX)`的时候,这个`observerX`就被加到列表里,`unsubscribe`时从列表中删掉。 `Subject`像是一个proxy,外部调用`subject.next(value)`时,这个`value`会被`forEach`给`Subject`的`observers`。 @@ -199,14 +199,18 @@ let z0_ = z$.subscribe(z$$) // 运行一次z$里的execution,仅此一次, ``` -## `Operator`:一半AllSpark(创建`Observable`),一半滤镜(变更推送时点和推送内容) +## Operator:一半AllSpark(创建Observable),一半滤镜(变更推送时点和推送内容) 在`Observable类`上调用的`Operator`是`Static Operator`, 比如: ```js Observable.interval(500); // 每隔500ms,推送一个递增整数,从0开始 Observable.from([1, 2]); // 连续推送1, 2 -Observable.fromEvent(document, 'click'); -Observable.fromPromise(fetch('http://github.com/users')); +Observable.fromEvent(document, 'click'); // 每次点击,推送一个event Object +Observable.fromPromise(fetch('http://github.com/users')); // resolve或reject时,推送给Observer +Observable.ajax('/users') // http 'GET' /users,response或error时,推送给Observer +const ws$$ = Observable.webSocket('ws://echo.websocket.org/') // 这个ws$$是个Subject +// 通过ws$$.next(JSON.stringify(value))向websocket发送信息 +// 通过ws$$.subscribe(observer)来接收信息 Observable.merge(x$, y$); // 将x$与y$的推送混合在一起 Observable.concat(x$, y$); // 先运行x$,等x$推送observer.complete(),再运行y$ ... @@ -233,7 +237,7 @@ x$ !== y$ // x$还是那个x$ 经过滤镜处理,我们拿到了一幅新的画,原来的画还在。 -## `Scheduler`:控制并发事件 +## Scheduler:控制并发事件 `Scheduler`的职能是控制并发事件。本人开发经验接近0,实在想不出实际生活中何时会用到`Scheduler`,也确实在实践中没用过。 如果要观察每种`Scheduler`对数据推送的影响,可以打开[RxJS Manual][],开启`console`,贴入下面的代码,回车。 @@ -253,9 +257,9 @@ const merged_ = merged$.subscribe(console.log); ## 总结 -提到`Observable`的时候,就想想`Function`,一个有随意数量`return`的`Function`。 +提到`Observable`的时候,就想想`Function`,一个脱离了低级趣味的(有随意数量`return`的)`Function`,一个有益于人民的(定义了在某个时点`return`什么数据的)`Function`。 -Happy coding! +**Happy coding!** ## 参考 [RxJS Source Code][] From 92391a764ab6820ea034f594581aaf2145448882 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Thu, 3 Nov 2016 00:04:53 -0700 Subject: [PATCH 037/177] =?UTF-8?q?modifies=20mock-redux-with-rxjs,=20adds?= =?UTF-8?q?=20author=20Tim=E5=88=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../articles/mock-redux-with-rxjs/_index.md | 23 ++++++------------ .../_shared/api/authors/Tim\345\210\230.md" | 1 + .../api/authors/_images/Tim\345\210\230.png" | Bin 0 -> 10259 bytes src/app/_shared/api/authors/index.ts | 9 +++++++ 4 files changed, 17 insertions(+), 16 deletions(-) create mode 100644 "src/app/_shared/api/authors/Tim\345\210\230.md" create mode 100644 "src/app/_shared/api/authors/_images/Tim\345\210\230.png" diff --git a/src/app/_shared/api/articles/mock-redux-with-rxjs/_index.md b/src/app/_shared/api/articles/mock-redux-with-rxjs/_index.md index de6782f..d84358c 100644 --- a/src/app/_shared/api/articles/mock-redux-with-rxjs/_index.md +++ b/src/app/_shared/api/articles/mock-redux-with-rxjs/_index.md @@ -43,8 +43,7 @@ store.dispatch({ type: 'INCREMENT' }) // will log 1 on the console 如此,可以大体断定,redux在实现State Store功能的过程中,用到了RxJS。 那么我们能不能直接用RxJS来直接实现State Store的功能呢? -RxJS的文档里就有答案,不过不是在[reactivex.io/rxjs][],而是在Github的Repo里。 -就在这里:[RxJS官方教程 - State Stores][]。 +RxJS的文档里就有答案,就在这里:[RxJS官方教程 - State Stores][]。 本文将先介绍一些RxJS的基本概念, 而后,依据官方State Stores示例,并引入`Subject`,来实现开头部分redux示例中的功能。 水平所限,难免有错漏,请大家多指教。另外,我写的比较啰嗦,请大家多包涵。 @@ -52,7 +51,7 @@ RxJS的文档里就有答案,不过不是在[reactivex.io/rxjs][],而是在G ## 相关概念 以下为粗略理解,具体参见[官方文档][]。 1. `Observer`:是一个Object,里面有3个Callback,形如`{next: nextFn, error: errorFn, complete: completeFn}`。 - 3个Callback都不是必须的,但要按顺序写,比如`{next: null, error: null, complete: completeFn}`。 + 3个Callback都不是必须的。 示例: ```js const observer = {next: (v) => console.log(v)}; // 这个Observer只有next callback @@ -88,12 +87,11 @@ RxJS的文档里就有答案,不过不是在[reactivex.io/rxjs][],而是在G subjectB$$.subscribe(observable); // 订阅一个BehaviorSubject,会把当前数据立即推送给observer console.log(subjectB$$.getValue()); // getValue()获取留存的最后一个数据 ``` -5. [scan运算符][]:如果把`Observable`推送的数据流类比成`Array`的话,那么`Observable.scan`运算符就是`Array.reduce`。 - (可是`Observable.scan`该怎么翻译呢?`Array.reduce`呢?) - 示例: +5. [scan运算符][]:如果把Observable推送的数据流类比成Array的话,那么Observable.prototype.scan运算符就类似Array.prototype.reduce, + 不同在于Array.prototype.reduce是把Array中所有的数值累积后形成一个值,而Observable.prototype.scan是把当前值和之前的累积值再次累积形成一个值,参见示例: ```js observable$.scan((accumulated, current) => accumulated + current, 0); - // 类似Array的reduce,比如:[1, 2, 3].reduce((acc, curr) => acc + curr, 0); + // 类似Array.prototype.reduce,比如:[1, 2, 3].reduce((acc, curr) => acc + curr, 0); ``` ## 编写代码 @@ -227,20 +225,13 @@ const clicks_ = Observable.merge(incButtonClick$, decButtonClick$) [官方文档][] [scan运算符][] -## 吐槽 -[RxJS Doc在github上的源码][]里有这么一句: -> These files are not meant for reading directly in GitHub, ... You should find the docs at http://reactivex.io/rxjs/, ... -但是呢,有几个非常有用的.md文件,在reactivex.io/rxjs里是找不到的。 -其中一个.md里面就有这个State Store。 -强烈建议大家翻阅一下[RxJS Doc在github上的源码][]。 **Happy coding!** -[reactivex.io/rxjs]: http://reactivex.io/rxjs -[RxJS官方教程 - State Stores]: https://github.com/ReactiveX/rxjs/blob/master/doc/tutorial/applications.md#state-stores + [redux]: https://github.com/reactjs/redux#the-gist -[RxJS Doc在github上的源码]: https://github.com/ReactiveX/rxjs/tree/master/doc#rxjs-official-docs-at-httpreactivexiorxjs [repo]: https://github.com/rxjs-space/rxjs-typescript-starter [官方文档]: http://reactivex.io/rxjs/manual/overview.html [scan运算符]: http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-scan +[RxJS官方教程 - State Stores]: http://reactivex.io/rxjs/manual/tutorial.html#state-stores diff --git "a/src/app/_shared/api/authors/Tim\345\210\230.md" "b/src/app/_shared/api/authors/Tim\345\210\230.md" new file mode 100644 index 0000000..4140fd7 --- /dev/null +++ "b/src/app/_shared/api/authors/Tim\345\210\230.md" @@ -0,0 +1 @@ +翻滚翻滚翻滚 \ No newline at end of file diff --git "a/src/app/_shared/api/authors/_images/Tim\345\210\230.png" "b/src/app/_shared/api/authors/_images/Tim\345\210\230.png" new file mode 100644 index 0000000000000000000000000000000000000000..b4066e8a9bb70814bb1236a0f00ff48e0caaf521 GIT binary patch literal 10259 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 Date: Thu, 3 Nov 2016 16:08:51 +0800 Subject: [PATCH 038/177] =?UTF-8?q?+=20=E6=96=B0=E4=BA=BA=E4=BD=9C?= =?UTF-8?q?=E8=80=85=E7=8E=8B=E9=96=8B=E5=AF=A7=20+=20=E9=A6=96=E7=AF=87?= =?UTF-8?q?=E6=96=87=E7=AB=A0=E3=80=8A=E4=BB=8Eng1=E5=88=B0ng2=E7=9A=84?= =?UTF-8?q?=E5=B9=B3=E6=BB=91=E5=8D=87=E7=BA=A7[1]=E3=80=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 377 ++++++++++++++++++ src/app/_shared/api/articles/index.ts | 9 + ...0.\347\216\213\351\226\213\345\257\247.md" | 3 + ....\347\216\213\351\226\213\345\257\247.jpg" | Bin 0 -> 50588 bytes src/app/_shared/api/authors/index.ts | 11 +- 5 files changed, 399 insertions(+), 1 deletion(-) create mode 100644 "src/app/_shared/api/articles/260.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[1]/_index.md" create mode 100644 "src/app/_shared/api/authors/260.\347\216\213\351\226\213\345\257\247.md" create mode 100644 "src/app/_shared/api/authors/_images/260.\347\216\213\351\226\213\345\257\247.jpg" diff --git "a/src/app/_shared/api/articles/260.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[1]/_index.md" "b/src/app/_shared/api/articles/260.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[1]/_index.md" new file mode 100644 index 0000000..063cb96 --- /dev/null +++ "b/src/app/_shared/api/articles/260.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[1]/_index.md" @@ -0,0 +1,377 @@ +如果你想了解如何将现有的AngularJs 1.X(简称ng1)的项目平滑升级至Angular 2.X(简称ng2),这篇文章或许会对你有帮助。 + +本文假设你原有的ng1项目有如下属性: + +1. 使用的ng1版本为1.2.X+; +2. 使用的Javascript版本为es3或少量es5特性; +3. 暂时不考虑其他外部依赖,例如第三方ng1插件等; +4. 如果你有一些es6的知识,阅读本文将会更加轻松。 + +本文的目标是: + +1. 将ng1升级至ng2,为了实现平滑升级,我们还将尽量使升级后的代码兼容ng1,从而在升级过程中不影响当前项目的正常开发和发布; +2. 将Javascript升级至Typescript,平滑升级过程中的ng1兼容代码将提供Javascript es6版本和typescript版本; +3. 尽量尝试使用最佳实践。 + +让我们开始吧! + +# 〇、一个典型的ng1项目 + +我们先来定义一个在本文中一直会使用到的ng1项目基础代码,后面的代码实例都基于这个基础代码开发。 + +``` +// app.js +/* 定义一个ng1 module,并假设该module为ng1项目的启动module,例如在html标签中添加 ng-app="app" */ + +var app = angular.module('app', []); +``` + +这个项目至少还要有一个controller + +``` +// index.controller.js +/* 一个简单的controller */ + +app.controller('IndexCtrl', ['$scope', function ($scope) { + $scope.info = 'hello world'; + + console.log($scope.info); +}]); +``` + +我们还要有一个html页面。 + +``` + + +... +
+
+ +
+
+... +``` + +这样,一个最简单的ng1项目就完成了。 + +# 一、从一个最简单的Controller开始 + +我们从最常使用的controller开始下手。首先回顾一下刚才定义的controller。 + +``` +// index.controller.js +/* 一个简单的controller */ + +app.controller('IndexCtrl', ['$scope', function ($scope) { + $scope.info = 'hello world'; + + console.log($scope.info); +}]); +``` + +仔细查看代码,我们可以发现,我们定义controller的方式使用的是angular.Module.controller方法,这样的定义方式与ng1完全耦合在一起,无法脱离ng1的依赖,因此,第一步我们现在将controller实体function从该方法中剥离出来。 + +## 1、分离controller的实体function + +分离的方式很简单,我们定义一个function变量,再将该function变量写在angular.Module.controller方法中。 + +``` +// index.controller.js +/* 一个简单的controller */ + +app.controller('IndexCtrl', ['$scope', indexCtrl]); + +var indexCtrl = function ($scope) { + $scope.info = 'hello world'; + + console.log($scope.info); +}; +``` + +但是这样做还是不够,因为Index.controller.js文件中还是调用了app.controller方法,这个方法是ng1专有的,因此这个文件还是在依赖ng1,因此我们可以将所有使用app.controller方法注册controller的代码集中到一个app-controller.js中。 + +这样,我们将index.controller.js文件拆分成两个文件。 + +``` +// app-controller.js + +app.controller('IndexCtrl', ['$scope', indexCtrl]) + .controller('LoginCtrl', ['$scope', loginCtrl]) + .controller(...); +``` + +``` +// index.controller.js + +var indexCtrl = function ($scope) { + $scope.info = 'hello world'; + + console.log($scope.info); +}; +``` + +修改之后的代码就清晰多了,app-controller.js专门负责注册项目中所有用到的controller,index.controller.js以及其他的类似login.controller.js等专门负责完成controller中的业务逻辑和交互逻辑。 + +> 这里有一个问题要注意,因为app-controller.js中要调用indexCtrl这个变量,因此一定要在调用之前定义这个变量,否则调用时indexCtrl为undefined。避免这个问题的方法,一种是在html中引用js文件时首先引用定义indexCtrl的js文件,最后引用app-controller.js文件;第二种是使用es6或typescript中的模块管理功能管理相互之间的依赖。本文最终会形成es6和typescript版本的代码,所以这个问题仅在改动过程中出现。 + +## 2、不再使用丑陋的$scope + +index.controller.js中的代码使用了$scope,而$scope是使用DI的方式注入到方法中,因此这里并没有对ng1产生直接的依赖,这也是依赖注入的一大好处。 + +但是controller方法中到处充满了$scope,不得不说代码会显得很混乱和丑陋。如果你对ng2有一些了解,那么应该知道ng2中是没有$scope概念的。为了升级至ng2,我们从现在开始对$scope说NO! + +ng1中提供了一种可以避免使用$scope的方式,那就是as语法,我们先来看一下如何使用。 + +``` + + +... +
+
+ +
+
+... +``` + +``` +// index.controller.js + +var indexCtrl = function () { + this.info = 'hello world'; + + console.log(this.info); +}; +``` + +``` +// app-controller.js + +app.controller('IndexCtrl', [indexCtrl]) + .controller('LoginCtrl', [loginCtrl]) + .controller(...); +``` + +使用as语法,相当于在$scope中定义了一个属性$ctrl,并将这个属性指向indexCtrl方法作用域的this上,具体可以参见官方文档([https://docs.angularjs.org/api/ng/directive/ngController](https://docs.angularjs.org/api/ng/directive/ngController))。 + +因此,使用as语法后,controller方法就可以使用this来操作其中的变量,这样几乎与ng2中Component类的操作方法一致,在注册controller时也不用注入$scope依赖了。 + +同时在html中,调用controller方法中的变量时,需要使用$ctrl.foobar来实现(因为$ctrl为$scope的一个属性)。 + +> 这里使用的$ctrl属性可以根据需要调整名称,如ctrl、indexCtrl等,但统一使用$ctrl是最佳实践,一方面可以在所有html的controller中统一使用相同的属性名调用controller中的变量,另一方面使用$前缀可以作为ng1的一个标记,避免出现变量名冲突的情况。 + +这时我们再重新观察一下index.controller.js文件,它已经完全纯净,只是一个非常普通的方法,一点ng1的影子都看不出来了。 + +``` +// index.controller.js + +var indexCtrl = function () { + this.info = 'hello world'; + + console.log(this.info); +}; +``` + +## 3、向es6及typescript进发 + +我们现在的js代码还停留在es3阶段,要靠近ng2,我们还需要使用typescript,而es6又是未来的趋势,同时也是typescript的子集,因此即使不使用ng2,将现有代码升级至es6也是有很大好处的。 + +> 升级至es6后,项目需要使用babel([https://babeljs.io](https://babeljs.io))编译为es3或es5版本。 + +> 升级至typescript后,需要使用typescript compiler([http://www.typescriptlang.org/](http://www.typescriptlang.org/))编译为es3或es5版本。 + +> 注意:虽然代码升级为typescript,但仍然可以在编译后兼容ng1。 + +这里,我们使用class来定义indexCtrl。 + +``` +// index.controller.js +/* + * 为了实现平滑升级,首先完成es6版本 + * 而es6是typescript的子集,因此该代码完全可以在typescript下顺利编译完成 + */ + +export default class IndexCtrl { + info = 'hello world'; + + constructor () { + console.log(this.info); + } + + // 这里我们为controller添加一个可以在html中调用的方法 + hasInfo () { + return typeof this.info === 'string' && + this.info.length > 0; + } +} +``` + +我们使用以下几种方式实现IndexCtrl + +1. 之前使用this定义的变量,我们在class的最顶端使用`foo = 'bar'`的方式声明为类属性; +2. 初始化工作在class中的constructor中完成; +3. 需要在html中调用的方法使用`foo () {}`的方式生命为类方法。 +4. 代码中export default使用了es6中的模块管理功能,将类导出,并可以在其他文件中调用。 + +类似的,我们将其他文件也做相应的优化。 + +``` +// app.js + +export default angular.module('app', []); +``` + +``` +// app-controller.js +// 这里使用import调用其他模块,从此就不用担心变量是否已定义的问题啦 + +import app from './app'; + +import IndexCtrl from './index.controller'; +import LoginCtrl from './login.controller'; +... + +app.controller('IndexCtrl', [indexCtrl]) + .controller('LoginCtrl', [loginCtrl]) + .controller(...); + +// 这个文件不需要其他文件调用,因此不需要export模块 +``` + +``` + + +... +
+
+ +
+
+... +``` + +虽然到此为止,代码可以在typescript下编译完成,但我们还是为typescript来做进一步完善吧。 + +``` +// index.controller.ts +// 为变量增加类型声明,同时也就不用再判断变量类型了 + +export default class IndexCtrl { + info : string = 'hello world'; + + constructor () { + console.log(this.info); + } + + hasInfo () : boolean { + // 使用了typescript,这里就可以省略类型判断了 + return this.info.length > 0; + } +} +``` + +其他js文件的typescript化就留给你做练习吧。 + +## 4、根据最佳实践进一步优化 + +这里有一些最佳实践,我们可以用来参考。 + +> 最佳实践:我们建议在constructor中,只对一些变量的值进行初始化,不执行具体的业务逻辑(例如本文中的console.log(this.info)),而将涉及到业务逻辑的初始化,则放到单独的初始化方法中完成。 + +这个最佳实践也正符合ng2的理念,在ng2中,每个component都有一系列生命周期方法,并通过ng2框架自动调用运行,我们涉及到业务逻辑的初始化工作在这里拆分到单独的初始化方法中,将更方便我们的代码升级至ng2。 + + +``` +// index.controller.js +// 我们首先来优化es6版本,es6和typescript都可以进行同样的优化 + +export default class IndexCtrl { + info = 'hello world'; + + constructor () { + this._onInit(); + } + + hasInfo () { + return typeof this.info === 'string' && + this.info.length > 0; + } + + // 这里的初始化方法我们统一命名为_onInit + _onInit () { + console.log(this.info); + } +} +``` + +> 最佳实践:初始化方法并不需要在网页中或其他模块中调用,因此我们将其设定为私有方法(以`_`开头),并写在所有公开方法后面。 + +这里有个问题,es6本身并不支持类的私有方法,因此我们没办法把方法声明为private类型,但使用`_`开头命名方法,可以人为的将该方法定义为私有方法,只要我们不在外部调用以`_`命名的方法,就可以很好的保护该私有方法。 + +接下来是typescript版本。 + +``` +// index.controller.ts +// 接下来优化typescript版本 + +export default class IndexCtrl { + info : string = 'hello world'; + + constructor () { + this._onInit(); + } + + // typescript中,类的方法默认为public类型,因此不需要显式声明 + hasInfo () : boolean { + return this.info.length > 0; + } + + // 这里用typescript中的private关键字将方法声明为私有方法 + private _onInit () : void { + console.log(this.info); + } +} +``` + +## 5、升级为ng2 + +到此为止,虽然我们对项目的修改已经如此巨大,但它依然可以兼容ng1(在babel或typescript compiler帮忙编译的情况下),而代码却已经变得整洁而先进,对你现有的项目的运行完全没有任何影响。 + +准备工作做的这么充分,升级至ng2就指日可待啦。 + +``` +// index.component.ts +// ng2中没有controller概念,我们将controller改造为component + +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'index-ctrl', + template: '{{ info }}' +}) +export class IndexComponent implements OnInit { + info : string = 'hello world'; + + constructor () { + // 初始化方法为生命周期方法,由ng2框架自动调用,这里不需要手动调用 + } + + hasInfo () : boolean { + return this.info.length > 0; + } + + // 这里用ng2中的生命周期方法 + ngOnInit () : void { + console.log(this.info); + } +} +``` + +改到这里,index.component.ts的ng2升级就完成了,我们可以看到,除了添加一些annotation以外,component的核心代码几乎没有变动。 + +这说明经过优化的、完全兼容ng1的typescript版本核心代码(也就是此步骤之前的所有重构工作),可以直接升级至ng2,之要添加一些必要的annotation就可以了。有木有很平滑! + +ngModule的ng2升级就留给你做练习吧。 + +(未完待续) \ No newline at end of file diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index cfa8267..1e1a5d9 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -255,6 +255,15 @@ const items: Article[] = [ tags: ['RxJS'], authors: ['Tim刘'], }, + { + id: '从ng1到ng2的平滑升级[1]', + title: '从ng1到ng2的平滑升级[1]', + summary: '系列文章:手把手教你将ng1项目平滑升级至ng2', + content: require('./260.从ng1到ng2的平滑升级[1]/_index.md'), + first: true, + tags: ['ng1', 'ng2', '平滑升级', 'es6', 'typescript'], + authors: ['王開寧'], + }, ]; @Injectable() diff --git "a/src/app/_shared/api/authors/260.\347\216\213\351\226\213\345\257\247.md" "b/src/app/_shared/api/authors/260.\347\216\213\351\226\213\345\257\247.md" new file mode 100644 index 0000000..f668d69 --- /dev/null +++ "b/src/app/_shared/api/authors/260.\347\216\213\351\226\213\345\257\247.md" @@ -0,0 +1,3 @@ +- 任性跳入前端坑,偶尔也涉足一些Java或Node的后端代码 + +- [基本不更新的个人主页](http://twincle.github.io/) \ No newline at end of file diff --git "a/src/app/_shared/api/authors/_images/260.\347\216\213\351\226\213\345\257\247.jpg" "b/src/app/_shared/api/authors/_images/260.\347\216\213\351\226\213\345\257\247.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..09ad2f906501d9a588a12e01407b855a3d5f58be GIT binary patch literal 50588 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�@< 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 Date: Fri, 4 Nov 2016 12:26:09 +0800 Subject: [PATCH 039/177] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E9=94=99=E5=88=AB?= =?UTF-8?q?=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/src/app/_shared/api/articles/220.Angular 2\345\256\230\346\226\271\346\226\207\346\241\243\345\257\274\350\257\273/_index.md" "b/src/app/_shared/api/articles/220.Angular 2\345\256\230\346\226\271\346\226\207\346\241\243\345\257\274\350\257\273/_index.md" index 456cdcc..fa1882a 100644 --- "a/src/app/_shared/api/articles/220.Angular 2\345\256\230\346\226\271\346\226\207\346\241\243\345\257\274\350\257\273/_index.md" +++ "b/src/app/_shared/api/articles/220.Angular 2\345\256\230\346\226\271\346\226\207\346\241\243\345\257\274\350\257\273/_index.md" @@ -12,7 +12,7 @@ 准备好环境之后,打开命令行窗口,运行`npm i -g angular-cli`命令,来安装一个供你快速入门的工具。安装好之后,你可以到你的联系目录下运行`ng new AppName`命令来创建你的练习项目,然后进入这个`AppName`目录,运行`npm i`(这个过程可能会比较长),然后运行`ng serve`命令,你的开发服务器就算启动完成了。 -长辈,你可以在浏览器中访问地址`http://localhost:4200`,就会看到一个非常简单的页面,但它实际上已经由Angular 2支撑了。 +这时,你可以在浏览器中访问地址`http://localhost:4200`,就会看到一个非常简单的页面,但它实际上已经由Angular 2支撑了。 接下来,你就可以用IDE打开这个项目了。强烈推荐你使用WebStorm作为IDE,它价钱很便宜,而且还有一个月的免费试用期,对Angular 2的支持非常全面,物超所值,你在它的帮助下学习会事半功倍的。 From 2db05b9405b5616ffb6ec4053a2877c954dd2963 Mon Sep 17 00:00:00 2001 From: Kaining Wang Date: Mon, 7 Nov 2016 13:31:27 +0800 Subject: [PATCH 040/177] =?UTF-8?q?=E7=AE=80=E5=8C=96=E6=96=87=E7=AB=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除es6代码部分 --- .../_index.md" | 254 +++++++----------- 1 file changed, 101 insertions(+), 153 deletions(-) diff --git "a/src/app/_shared/api/articles/260.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[1]/_index.md" "b/src/app/_shared/api/articles/260.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[1]/_index.md" index 063cb96..b8ad48a 100644 --- "a/src/app/_shared/api/articles/260.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[1]/_index.md" +++ "b/src/app/_shared/api/articles/260.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[1]/_index.md" @@ -9,8 +9,8 @@ 本文的目标是: -1. 将ng1升级至ng2,为了实现平滑升级,我们还将尽量使升级后的代码兼容ng1,从而在升级过程中不影响当前项目的正常开发和发布; -2. 将Javascript升级至Typescript,平滑升级过程中的ng1兼容代码将提供Javascript es6版本和typescript版本; +1. 将ng1升级至ng2,为了实现平滑升级,我们还将尽量在升级过程中把步子迈小,同时使升级后的代码兼容ng1,从而在升级过程中不影响当前项目的正常开发和发布; +2. 将Javascript升级至Typescript,平滑升级过程中还可以生成兼容ng1的typescript版本代码; 3. 尽量尝试使用最佳实践。 让我们开始吧! @@ -33,9 +33,9 @@ var app = angular.module('app', []); /* 一个简单的controller */ app.controller('IndexCtrl', ['$scope', function ($scope) { - $scope.info = 'hello world'; - - console.log($scope.info); + $scope.info = 'hello world'; + + console.log($scope.info); }]); ``` @@ -46,9 +46,9 @@ app.controller('IndexCtrl', ['$scope', function ($scope) { ...
-
- -
+
+ +
... ``` @@ -64,17 +64,17 @@ app.controller('IndexCtrl', ['$scope', function ($scope) { /* 一个简单的controller */ app.controller('IndexCtrl', ['$scope', function ($scope) { - $scope.info = 'hello world'; - - console.log($scope.info); + $scope.info = 'hello world'; + + console.log($scope.info); }]); ``` -仔细查看代码,我们可以发现,我们定义controller的方式使用的是angular.Module.controller方法,这样的定义方式与ng1完全耦合在一起,无法脱离ng1的依赖,因此,第一步我们现在将controller实体function从该方法中剥离出来。 +仔细查看代码,我们可以发现,我们定义controller的方式使用的是`angular.Module.controller`方法,这样的定义方式与ng1完全耦合在一起,无法脱离ng1的依赖,因此,第一步我们现在将controller实体function从该方法中剥离出来。 ## 1、分离controller的实体function -分离的方式很简单,我们定义一个function变量,再将该function变量写在angular.Module.controller方法中。 +分离的方式很简单,我们定义一个function变量,再将该function变量写在`angular.Module.controller`方法中。 ``` // index.controller.js @@ -83,13 +83,13 @@ app.controller('IndexCtrl', ['$scope', function ($scope) { app.controller('IndexCtrl', ['$scope', indexCtrl]); var indexCtrl = function ($scope) { - $scope.info = 'hello world'; - - console.log($scope.info); + $scope.info = 'hello world'; + + console.log($scope.info); }; ``` -但是这样做还是不够,因为Index.controller.js文件中还是调用了app.controller方法,这个方法是ng1专有的,因此这个文件还是在依赖ng1,因此我们可以将所有使用app.controller方法注册controller的代码集中到一个app-controller.js中。 +但是这样做还是不够,因为Index.controller.js文件中还是调用了app.controller方法,这个方法是ng1专有的,因此这个文件还是在依赖ng1,因此我们可以将所有使用`app.controller`方法注册controller的代码集中到一个`app-controller.js`中。 这样,我们将index.controller.js文件拆分成两个文件。 @@ -105,32 +105,32 @@ app.controller('IndexCtrl', ['$scope', indexCtrl]) // index.controller.js var indexCtrl = function ($scope) { - $scope.info = 'hello world'; - - console.log($scope.info); + $scope.info = 'hello world'; + + console.log($scope.info); }; ``` -修改之后的代码就清晰多了,app-controller.js专门负责注册项目中所有用到的controller,index.controller.js以及其他的类似login.controller.js等专门负责完成controller中的业务逻辑和交互逻辑。 +修改之后的代码就清晰多了,`app-controller.js`专门负责注册项目中所有用到的controller,`index.controller.js`以及其他的类似`login.controller.js`等专门负责完成controller中的业务逻辑和交互逻辑。 -> 这里有一个问题要注意,因为app-controller.js中要调用indexCtrl这个变量,因此一定要在调用之前定义这个变量,否则调用时indexCtrl为undefined。避免这个问题的方法,一种是在html中引用js文件时首先引用定义indexCtrl的js文件,最后引用app-controller.js文件;第二种是使用es6或typescript中的模块管理功能管理相互之间的依赖。本文最终会形成es6和typescript版本的代码,所以这个问题仅在改动过程中出现。 +> 这里有一个问题要注意,因为`app-controller.js`中要调用`indexCtrl`这个变量,因此一定要在调用之前定义这个变量,否则调用时`indexCtrl`为`undefined`。避免这个问题的方法,一种是在html中引用js文件时首先引用定义indexCtrl的js文件,最后引用`app-controller.js`文件;第二种是使用typescript中的模块管理功能管理相互之间的依赖。本文最终会形成typescript版本的代码,所以这个问题仅在改动过程中出现。 ## 2、不再使用丑陋的$scope -index.controller.js中的代码使用了$scope,而$scope是使用DI的方式注入到方法中,因此这里并没有对ng1产生直接的依赖,这也是依赖注入的一大好处。 +`index.controller.js`中的代码使用了`$scope`,而`$scope`是使用DI的方式注入到方法中,因此这里并没有对ng1产生直接的依赖,这也是依赖注入的一大好处。 -但是controller方法中到处充满了$scope,不得不说代码会显得很混乱和丑陋。如果你对ng2有一些了解,那么应该知道ng2中是没有$scope概念的。为了升级至ng2,我们从现在开始对$scope说NO! +但是controller方法中到处充满了`$scope`,不得不说代码会显得很混乱和丑陋。如果你对ng2有一些了解,那么应该知道ng2中是没有`$scope`概念的。为了升级至ng2,我们从现在开始对`$scope`说NO! -ng1中提供了一种可以避免使用$scope的方式,那就是as语法,我们先来看一下如何使用。 +ng1中提供了一种可以避免使用`$scope`的方式,那就是`as`语法,我们先来看一下如何使用。 ``` ...
-
- -
+
+ +
... ``` @@ -139,9 +139,9 @@ ng1中提供了一种可以避免使用$scope的方式,那就是as语法,我 // index.controller.js var indexCtrl = function () { - this.info = 'hello world'; - - console.log(this.info); + this.info = 'hello world'; + + console.log(this.info); }; ``` @@ -153,77 +153,72 @@ app.controller('IndexCtrl', [indexCtrl]) .controller(...); ``` -使用as语法,相当于在$scope中定义了一个属性$ctrl,并将这个属性指向indexCtrl方法作用域的this上,具体可以参见官方文档([https://docs.angularjs.org/api/ng/directive/ngController](https://docs.angularjs.org/api/ng/directive/ngController))。 +使用`as`语法,相当于在`$scope`中定义了一个属性`$ctrl`,并将这个属性指向`indexCtrl`方法作用域的`this`上,具体可以参见官方文档([https://docs.angularjs.org/api/ng/directive/ngController](https://docs.angularjs.org/api/ng/directive/ngController))。 -因此,使用as语法后,controller方法就可以使用this来操作其中的变量,这样几乎与ng2中Component类的操作方法一致,在注册controller时也不用注入$scope依赖了。 +因此,使用`as`语法后,controller方法就可以使用`this`来操作其中的变量,这样几乎与ng2中`Component`类的操作方法一致,在注册controller时也不用注入`$scope`依赖了。 -同时在html中,调用controller方法中的变量时,需要使用$ctrl.foobar来实现(因为$ctrl为$scope的一个属性)。 +同时在html中,调用controller方法中的变量时,需要使用`$ctrl.foobar`来实现(因为`$ctrl`为`$scope`的一个属性)。 -> 这里使用的$ctrl属性可以根据需要调整名称,如ctrl、indexCtrl等,但统一使用$ctrl是最佳实践,一方面可以在所有html的controller中统一使用相同的属性名调用controller中的变量,另一方面使用$前缀可以作为ng1的一个标记,避免出现变量名冲突的情况。 +> 这里使用的`$ctrl`属性可以根据需要调整名称,如`ctrl`、`indexCtrl`等,但统一使用`$ctrl`是最佳实践,一方面可以在所有html的controller中统一使用相同的属性名调用controller中的变量,另一方面使用$前缀可以作为ng1的一个标记,避免出现变量名冲突的情况。 -这时我们再重新观察一下index.controller.js文件,它已经完全纯净,只是一个非常普通的方法,一点ng1的影子都看不出来了。 +这时我们再重新观察一下`index.controller.js`文件,它已经完全纯净,只是一个非常普通的方法,一点ng1的影子都看不出来了。 ``` // index.controller.js var indexCtrl = function () { - this.info = 'hello world'; - - console.log(this.info); + this.info = 'hello world'; + + console.log(this.info); }; ``` ## 3、向es6及typescript进发 -我们现在的js代码还停留在es3阶段,要靠近ng2,我们还需要使用typescript,而es6又是未来的趋势,同时也是typescript的子集,因此即使不使用ng2,将现有代码升级至es6也是有很大好处的。 - -> 升级至es6后,项目需要使用babel([https://babeljs.io](https://babeljs.io))编译为es3或es5版本。 +我们现在的js代码还停留在es3阶段,要靠近ng2,我们还需要使用typescript。 > 升级至typescript后,需要使用typescript compiler([http://www.typescriptlang.org/](http://www.typescriptlang.org/))编译为es3或es5版本。 > 注意:虽然代码升级为typescript,但仍然可以在编译后兼容ng1。 -这里,我们使用class来定义indexCtrl。 +这里,我们使用typescript中的`class`来定义`indexCtrl`。 ``` -// index.controller.js -/* - * 为了实现平滑升级,首先完成es6版本 - * 而es6是typescript的子集,因此该代码完全可以在typescript下顺利编译完成 - */ +// index.controller.ts +// 为变量增加类型声明,同时也就不用再判断变量类型了 export default class IndexCtrl { - info = 'hello world'; - - constructor () { - console.log(this.info); - } - - // 这里我们为controller添加一个可以在html中调用的方法 - hasInfo () { - return typeof this.info === 'string' && - this.info.length > 0; - } + info : string = 'hello world'; + + constructor () { + console.log(this.info); + } + + // 这里我们为controller添加一个可以在html中调用的方法 + hasInfo () : boolean { + // 使用了typescript,这里就可以省略类型判断了 + return this.info.length > 0; + } } ``` -我们使用以下几种方式实现IndexCtrl +我们使用以下几种方式实现`IndexCtrl`: -1. 之前使用this定义的变量,我们在class的最顶端使用`foo = 'bar'`的方式声明为类属性; -2. 初始化工作在class中的constructor中完成; +1. 之前使用`this`定义的变量,我们在class的最顶端使用`foo = 'bar'`的方式声明为类属性; +2. 初始化工作在class中的`constructor`中完成; 3. 需要在html中调用的方法使用`foo () {}`的方式生命为类方法。 -4. 代码中export default使用了es6中的模块管理功能,将类导出,并可以在其他文件中调用。 +4. 代码中`export default`使用了typescript中的模块管理功能,将类导出,并可以在其他文件中调用。 类似的,我们将其他文件也做相应的优化。 ``` -// app.js +// app.ts export default angular.module('app', []); ``` ``` -// app-controller.js +// app-controller.ts // 这里使用import调用其他模块,从此就不用担心变量是否已定义的问题啦 import app from './app'; @@ -244,99 +239,52 @@ app.controller('IndexCtrl', [indexCtrl]) ...
-
- -
+
+ +
... ``` -虽然到此为止,代码可以在typescript下编译完成,但我们还是为typescript来做进一步完善吧。 - -``` -// index.controller.ts -// 为变量增加类型声明,同时也就不用再判断变量类型了 - -export default class IndexCtrl { - info : string = 'hello world'; - - constructor () { - console.log(this.info); - } - - hasInfo () : boolean { - // 使用了typescript,这里就可以省略类型判断了 - return this.info.length > 0; - } -} -``` - -其他js文件的typescript化就留给你做练习吧。 +虽然到此为止,代码在typescript下编译完成后,仍然可以生成兼容ng1的es3版本js代码。 ## 4、根据最佳实践进一步优化 这里有一些最佳实践,我们可以用来参考。 -> 最佳实践:我们建议在constructor中,只对一些变量的值进行初始化,不执行具体的业务逻辑(例如本文中的console.log(this.info)),而将涉及到业务逻辑的初始化,则放到单独的初始化方法中完成。 +> 最佳实践:我们建议在`constructor`中,只对一些变量的值进行初始化,不执行具体的业务逻辑(例如本文中的`console.log(this.info)`),而将涉及到业务逻辑的初始化,则放到单独的初始化方法中完成。 这个最佳实践也正符合ng2的理念,在ng2中,每个component都有一系列生命周期方法,并通过ng2框架自动调用运行,我们涉及到业务逻辑的初始化工作在这里拆分到单独的初始化方法中,将更方便我们的代码升级至ng2。 - -``` -// index.controller.js -// 我们首先来优化es6版本,es6和typescript都可以进行同样的优化 - -export default class IndexCtrl { - info = 'hello world'; - - constructor () { - this._onInit(); - } - - hasInfo () { - return typeof this.info === 'string' && - this.info.length > 0; - } - - // 这里的初始化方法我们统一命名为_onInit - _onInit () { - console.log(this.info); - } -} -``` - -> 最佳实践:初始化方法并不需要在网页中或其他模块中调用,因此我们将其设定为私有方法(以`_`开头),并写在所有公开方法后面。 - -这里有个问题,es6本身并不支持类的私有方法,因此我们没办法把方法声明为private类型,但使用`_`开头命名方法,可以人为的将该方法定义为私有方法,只要我们不在外部调用以`_`命名的方法,就可以很好的保护该私有方法。 - -接下来是typescript版本。 - ``` // index.controller.ts // 接下来优化typescript版本 export default class IndexCtrl { - info : string = 'hello world'; - - constructor () { - this._onInit(); - } - - // typescript中,类的方法默认为public类型,因此不需要显式声明 - hasInfo () : boolean { - return this.info.length > 0; - } - - // 这里用typescript中的private关键字将方法声明为私有方法 - private _onInit () : void { - console.log(this.info); - } + info : string = 'hello world'; + + constructor () { + this._onInit(); + } + + // typescript中,类的方法默认为public类型,因此不需要显式声明 + hasInfo () : boolean { + return this.info.length > 0; + } + + // 这里我们将初始化方法同意命名为_onInit + // 这里用typescript中的private关键字将方法声明为私有方法 + private _onInit () : void { + console.log(this.info); + } } ``` +> 最佳实践:初始化方法并不需要在网页中或其他模块中调用,因此我们将其设定为私有方法(以`_`开头),并写在所有公开方法后面。 + ## 5、升级为ng2 -到此为止,虽然我们对项目的修改已经如此巨大,但它依然可以兼容ng1(在babel或typescript compiler帮忙编译的情况下),而代码却已经变得整洁而先进,对你现有的项目的运行完全没有任何影响。 +到此为止,虽然我们对项目的修改已经如此巨大,但它依然可以兼容ng1(在typescript compiler帮忙编译的情况下),而代码却已经变得整洁而先进,对你现有的项目的运行完全没有任何影响。 准备工作做的这么充分,升级至ng2就指日可待啦。 @@ -351,27 +299,27 @@ import { Component, OnInit } from '@angular/core'; template: '{{ info }}' }) export class IndexComponent implements OnInit { - info : string = 'hello world'; - - constructor () { - // 初始化方法为生命周期方法,由ng2框架自动调用,这里不需要手动调用 - } - - hasInfo () : boolean { - return this.info.length > 0; - } - - // 这里用ng2中的生命周期方法 - ngOnInit () : void { - console.log(this.info); - } + info : string = 'hello world'; + + constructor () { + // 初始化方法为生命周期方法,由ng2框架自动调用,这里不需要手动调用 + } + + hasInfo () : boolean { + return this.info.length > 0; + } + + // 这里用ng2中的生命周期方法 + ngOnInit () : void { + console.log(this.info); + } } ``` -改到这里,index.component.ts的ng2升级就完成了,我们可以看到,除了添加一些annotation以外,component的核心代码几乎没有变动。 +改到这里,`index.component.ts`的ng2升级就完成了,我们可以看到,除了添加一些annotation以外,component的核心代码几乎没有变动。 这说明经过优化的、完全兼容ng1的typescript版本核心代码(也就是此步骤之前的所有重构工作),可以直接升级至ng2,之要添加一些必要的annotation就可以了。有木有很平滑! -ngModule的ng2升级就留给你做练习吧。 +`ngModule`的ng2升级就留给你做练习吧。 -(未完待续) \ No newline at end of file +(未完待续) From fad447625a4e7b15785286c10b95197a98fe645b Mon Sep 17 00:00:00 2001 From: Kaining Wang Date: Mon, 7 Nov 2016 13:34:29 +0800 Subject: [PATCH 041/177] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修正一些文字上的错误 --- .../_index.md" | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git "a/src/app/_shared/api/articles/260.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[1]/_index.md" "b/src/app/_shared/api/articles/260.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[1]/_index.md" index b8ad48a..1bb3c85 100644 --- "a/src/app/_shared/api/articles/260.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[1]/_index.md" +++ "b/src/app/_shared/api/articles/260.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[1]/_index.md" @@ -5,7 +5,7 @@ 1. 使用的ng1版本为1.2.X+; 2. 使用的Javascript版本为es3或少量es5特性; 3. 暂时不考虑其他外部依赖,例如第三方ng1插件等; -4. 如果你有一些es6的知识,阅读本文将会更加轻松。 +4. 如果你有一些typescript的知识,阅读本文将会更加轻松。 本文的目标是: @@ -115,7 +115,7 @@ var indexCtrl = function ($scope) { > 这里有一个问题要注意,因为`app-controller.js`中要调用`indexCtrl`这个变量,因此一定要在调用之前定义这个变量,否则调用时`indexCtrl`为`undefined`。避免这个问题的方法,一种是在html中引用js文件时首先引用定义indexCtrl的js文件,最后引用`app-controller.js`文件;第二种是使用typescript中的模块管理功能管理相互之间的依赖。本文最终会形成typescript版本的代码,所以这个问题仅在改动过程中出现。 -## 2、不再使用丑陋的$scope +## 2、不再使用丑陋的`$scope` `index.controller.js`中的代码使用了`$scope`,而`$scope`是使用DI的方式注入到方法中,因此这里并没有对ng1产生直接的依赖,这也是依赖注入的一大好处。 @@ -173,7 +173,7 @@ var indexCtrl = function () { }; ``` -## 3、向es6及typescript进发 +## 3、向typescript进发 我们现在的js代码还停留在es3阶段,要靠近ng2,我们还需要使用typescript。 From c9dd9bc172c59eb44fa60b71b1ddf7474f8c6877 Mon Sep 17 00:00:00 2001 From: lhtin Date: Mon, 7 Nov 2016 13:44:52 +0800 Subject: [PATCH 042/177] add: --- .../_index.md" | 18 ++++++++++++++++++ src/app/_shared/api/articles/index.ts | 11 ++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 "src/app/_shared/api/articles/250.\344\276\235\350\265\226\346\263\250\345\205\245\347\256\200\344\273\213/_index.md" diff --git "a/src/app/_shared/api/articles/250.\344\276\235\350\265\226\346\263\250\345\205\245\347\256\200\344\273\213/_index.md" "b/src/app/_shared/api/articles/250.\344\276\235\350\265\226\346\263\250\345\205\245\347\256\200\344\273\213/_index.md" new file mode 100644 index 0000000..18bfae0 --- /dev/null +++ "b/src/app/_shared/api/articles/250.\344\276\235\350\265\226\346\263\250\345\205\245\347\256\200\344\273\213/_index.md" @@ -0,0 +1,18 @@ +# 依赖注入简介 + +简单来说,依赖注入是一种降低代码之间的耦合度,提高代码的灵活性的编程方法。事情是这样子的: + +我们编程都是从`Hello World`开始,但它不会永远停留在`Hello World`,它会变得越来越复杂。为了能够掌控程序的复杂,我们引进了模块化。模块化的目的是切分复杂,带来的问题是需要考虑代码之间的合作问题(不只是多人之间的代码,还有自己写的代码之间的合作问题)。合作意味着依赖,比如模块A依赖模块B提供的功能。具体到面向对象编程就是对象A里面,需要使用到对象B的实例。 + +现在问题来了,对象B的实例化是在对象A里面实例化呢,还是先实例化,再将实例化后的实例当参数传给对象A呢?如果实例化的方式不变,当然在对象A里面实例化最好了,因为使用对象A的程序员不需要关注对象A还依赖了对象B。可是呢,需求总是在变化。如果哪天对象B改变了,它在实例化的时候要求添加一个参数,这下对象A就傻了。因为需要将对象B实例化的代码做更改,这相当于A限制了B的改变(不能只修改B,还要考虑到A)。 + +那就选择将对象B的实例当参数传给对象A吧(解决问题的一种方法),这样对象A就不需要知道对象B是如何实例化的了(**题外话,对象B依然需要保证提供的服务方式不变或者说暴露的接口不变**)。这种将依赖的引入从使用者的代码中分离出来,交由框架管理的技术叫做**控制反转**(Inversion of Control)。OK,这里有两种方式将对象B的实例传给对象A。一种是对象A先声明依赖了哪些对象,框架根据声明去实例化这些对象并传给A。另外一种是对象A在需要的时候自己去问框架,框架返回A所依赖的对象B的实例。 + +这两种方式都是**把对象的实例化的问题交由一个依赖管理框架**。第一种方式叫**依赖注入**(Dependency Injection),第二种方式叫**依赖查找**(Dependency Lookup)。这两者的区别在于框架把依赖注入给对象,还是对象主动查找需要的依赖。 + +不管用没用控制反转,代码需要做的事情是一样都不少,控制反转只是将这种实例化的工作交给了代码而不是开发者。因为交给了代码来做,与代码的交互只能变的固定了(比如声明依赖的方式)。**有了控制反转的好处是对象B的修改升级只需考虑对象B和依赖框架**。 + +## 参考文章 + +1. 依赖注入([https://github.com/android-cn/blog/tree/master/java/dependency-injection](https://github.com/android-cn/blog/tree/master/java/dependency-injection)) +2. 控制反转([https://zh.wikipedia.org/wiki/控制反转](https://zh.wikipedia.org/wiki/控制反转)) diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index cfa8267..b7d6ba4 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -235,7 +235,7 @@ const items: Article[] = [ content: require('./250.RxJS Overview阅读笔记/_index.md'), first: true, tags: ['RxJS'], - authors: ['lhtin'], + authors: ['钉子哥'], }, { id: 'Angular 2官方文档导读', @@ -255,6 +255,15 @@ const items: Article[] = [ tags: ['RxJS'], authors: ['Tim刘'], }, + { + id: '依赖注入简介', + title: '依赖注入简介', + summary: '什么是依赖注入?又为什么需要依赖注入?本文尝试给出一个简短的回答。', + content: require('./250.依赖注入简介/_index.md'), + first: true, + tags: ['DI'], + authors: ['钉子哥'], + } ]; @Injectable() From 5d6b6a9ab365802761e52972379409a585b2799f Mon Sep 17 00:00:00 2001 From: lhtin Date: Mon, 7 Nov 2016 17:08:03 +0800 Subject: [PATCH 043/177] update --- .../_index.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/src/app/_shared/api/articles/250.\344\276\235\350\265\226\346\263\250\345\205\245\347\256\200\344\273\213/_index.md" "b/src/app/_shared/api/articles/250.\344\276\235\350\265\226\346\263\250\345\205\245\347\256\200\344\273\213/_index.md" index 18bfae0..8311d53 100644 --- "a/src/app/_shared/api/articles/250.\344\276\235\350\265\226\346\263\250\345\205\245\347\256\200\344\273\213/_index.md" +++ "b/src/app/_shared/api/articles/250.\344\276\235\350\265\226\346\263\250\345\205\245\347\256\200\344\273\213/_index.md" @@ -10,7 +10,7 @@ 这两种方式都是**把对象的实例化的问题交由一个依赖管理框架**。第一种方式叫**依赖注入**(Dependency Injection),第二种方式叫**依赖查找**(Dependency Lookup)。这两者的区别在于框架把依赖注入给对象,还是对象主动查找需要的依赖。 -不管用没用控制反转,代码需要做的事情是一样都不少,控制反转只是将这种实例化的工作交给了代码而不是开发者。因为交给了代码来做,与代码的交互只能变的固定了(比如声明依赖的方式)。**有了控制反转的好处是对象B的修改升级只需考虑对象B和依赖框架**。 +不管用没用控制反转,代码需要做的事情是一样都不少,控制反转只是将这种实例化的工作交给了代码而不是开发者。因为交给了代码来做,与代码的交互只能变得固定了(比如声明依赖的方式)。**使用控制反转的好处是对象B的修改升级只需考虑对象B和依赖框架**。 ## 参考文章 From 1578163801ea2d3e3c6e9cb31b95cf245f91b471 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Tue, 8 Nov 2016 02:32:28 -0800 Subject: [PATCH 044/177] adds mock-redux-episode-2 --- src/app/_shared/api/articles/index.ts | 9 + .../_index.md | 231 ++++++++++++++++++ 2 files changed, 240 insertions(+) create mode 100644 src/app/_shared/api/articles/timliu/mock-redux-with-rxjs-episode-2-todo-app/_index.md diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index b7d6ba4..405c7b7 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -263,6 +263,15 @@ const items: Article[] = [ first: true, tags: ['DI'], authors: ['钉子哥'], + }, + { + id: '应用RxJS模拟redux-第二集-Todo-App', + title: '应用RxJS模拟redux 第二集 Todo-App', + summary: '以Redux的思维,借助RxJS,制作一个Todo App。', + content: require('./timliu/mock-redux-with-rxjs-episode-2-todo-app/_index.md'), + first: true, + tags: ['RxJS'], + authors: ['Tim刘'] } ]; diff --git a/src/app/_shared/api/articles/timliu/mock-redux-with-rxjs-episode-2-todo-app/_index.md b/src/app/_shared/api/articles/timliu/mock-redux-with-rxjs-episode-2-todo-app/_index.md new file mode 100644 index 0000000..a197abd --- /dev/null +++ b/src/app/_shared/api/articles/timliu/mock-redux-with-rxjs-episode-2-todo-app/_index.md @@ -0,0 +1,231 @@ +# Mock Redux with RxJS - Episode 2 - Todo App + +初稿日期:2016年11月08日 + + +## 写作原因/目的 +在上集[Mock Redux with RxJS][]里,我们用RxJS模拟了Redux的最基本的功能,即实现了一个`state`为数字的`state store`。 +现实生活中,`state`的内容要复杂的多,而且除了改变`state`,我们还要处理`side effects`,比如更新`dom`、发送`ajax`请求等等。 +- 本集想要说明的是: + **应用RxJS,在改变`state`的同时,我们可以很直接的处理`side effects`,不需要像Redux那样使用`Thunk Middleware`。** + 落实在代码上就是: + ```js + // 从上集的 + const handlerA = (action: Action): ChangeFn => {return changeFn} // changeFn会被用来更改state + // 变成本集的 + const handlerA = (action: Action): changeFn => {updateDom(); triggerAjax(); return changeFn} + + // handler所在位置(对应上集): + action$$.map(action => { + switch (action.type) { + case A: return handlerA(action); + ... + } + }) + ``` + 仅此而已。 +接下来的部分都是上面代码的具体应用,大家赶时间的话,可以全部跳过。 + +本集承接上集,以Redux的思维,借助RxJS,制作一个Todo App。 + +## 变量名Style约定 +(这是我个人的Style约定,并非任何Best Practice。) +* `Observable`变量以`$`结尾,如`state$`; +* `Subject`变量以`$$`结尾, 如`state$$`; +* `Subscription`变量以`_`结尾,如`ultimate_`。 + +## 相关概念 + +0. `Observer、Observable、Subject、BehaviorSubject、Observable.prototype.scan运算符`,这几个上集已提过,不重复。 +1. `Obserable`与`Subject`的资源消耗说明: + `Observable`像是一个`Function`,每次运行`sampleObservable$.subscribe(observer)`,都相当于一次`sampleFunction.call()`,是一次独立的运行,单独消耗资源。 + 而`Subject`维护一个[`observers`列表][],每次运行`sampleSubject$$.subscribe(observer)`,只是运行了`Array.prototype.push`,将`observer`添加到`observers`列表,消耗资源很少。 + 举例来说: + ```js + const click$ = Observable.fromEvent(document, 'click'); + + // 在文件A里: + click$.subscribe(event => { // do some thing + }); // 这相当于运行了一次addEventListener + + // 在文件B里: + click$.subscribe(event => { // do some other thing + }); // 又运行了一次addEventListener + + // 我们还可以这样: + const click$$ = new Subject(); + const click$.subscribe(click$$); // 这里相当于运行一次addEventListener + + // 在文件A里: + click$$.subscribe(event => { // do some thing + }); // 这相当于向click$$的observers列表里添加了一个observer + + // 在文件B里:... + + ``` + 所以,本集代码里的`dom`事件,90%以上都被打包成了`Subject`,用来节省资源。参见代码中的`todo/dom-triggers/_shared.ts`。 +2. [`Observable.ajax`运算符][]:将`XMLHttpRequest`打包成Observable,比如,POST一个新的Item到数据库: + + ```js + const post$ = Observable.ajax.post(urlAll, form); + // 或者 + const post$ = Observable.ajax({ + url: urlAll, + body: form, + // headers: {'Content-Type': 'application/x-www-form-urlencoded'}, // 不用手动设置这个header + method: 'POST' + }) + // 然后,用subscribe启动这个XMLHttpRequest + post$.subscribe(res => console.log(res), err => console.log(err)); + ``` + + +## 编写代码 + +源码:代码在这个[Repo][]里。 +运行:`npm install`,然后`npm run with-json-server`。 + += = = = = 分割线 = = = = = + +主演: + +0. `action$$`、`state$$`,这两位上集介绍过了,是两个`Subject`,分别负责转推`action`与`state`。 +1. `handlers`,这位上集有出场,但是没报姓名,就在`changeFn$`的`map`里: + ```js + const changeFn$: Observable = action$$ + .map((action: Action) => { + switch (action.type) { + case INCREASE: + return (state: State) => state + 1; + // ... + } + }) + ``` + 上面这个可以写成:`const changeFn$ = action$$.map(handlers)`。 + 上集中,`handlers`只根据`action`来返回一个`changeFn`。 + 本集中,`handlers`还要负责在更改`dom`(比如显示提示、使按钮失效等,不包括在dom上更新todo list)以及触发`ajax observable`。 + +2. `triggers$`,这位在上集叫做“外部”,就是触发`action$$.next(action)`的主体,可以是domEvent、ajax,但要打包成Observable,比如: + ```js + const clickTrigger$ = Observable.fromEvent(document, 'click') + .map(event => action$$.next({type: 'click', payload: event.XYZ})) + // 每次点按,发送action + // clickTrigger$不会自动运行,需要subscribe来启动 + ``` +3. `renderer`,还是老演员,上集没报姓名:在`const ultimate_ = state$$.subscribe(console.log)`中, + 这个`console.log`就是上集的`renderer`。本集的`renderer`负责在`state`更新时,更新`dom`里的列表部分。 +4. 后端:[JSON Server][]。 + += = = = = 分割线 = = = = = + +故事梗概: + +1. `triggers$`触发`action$$.next(action)`,这个`triggers$`可以是打包成`Observable`的定时器、DOM事件或ajax等等; +2. `handlers`把`action` `map`成`changeFn`,同时,更改`dom`,可能会触发`ajax observable`; +3. `changeFn`被`scan`成`state`; +4. `state`再被推给`state$$`; +5. `state$$`再将`state`转推给`renderer`; +6. `renderer`更新`dom`。 +7. 如果步骤2中触发了`ajax observable`,这个`ajax observable`就化身为`triggers$`,再从步骤1开始走一遍。 + + += = = = = 分割线 = = = = = +以`app启动`为例,走一遍流程。 + +页面载入后,app启动,运行`action$$.next({type: CONST.GET_ALL_START})`。 +找找这个action的handler, +```js +const changeFn$ = action$$.map(handlers); +export const handlers = (action: Action): ChangeFn => { + switch (action.type) { + case CONST.GET_ALL_START: return GET_ALL_START_handler(action); + // ... + } +} +``` +就是这个`GET_ALL_START_handler`: +就是这个`GET_ALL_START_handler`: +就是这个`GET_ALL_START_handler`: +(本文开篇说的就是它) +```js +export const GET_ALL_START_handler = (action: Action): ChangeFn => { + GET_ALL_START_handler_dom(); + GET_ALL_START_handler_ajax(); + return defaultChangeFnFac(action) +} +``` +`GET_ALL_START_handler_dom`就是在dom上显示消息,通知用户:稍等一下,我读个数据。 +`GET_ALL_START_handler_ajax`就是去读数据,要读所有数据,所以没参数。 +`defaultChangeFnFac(action)`返回一个changeFn(跟handler\_dom、handler_ajax没有任何关系),而后changeFn被scan成state,传给state$$,传给renderer。 + +回到`GET_ALL_START_handler_ajax`,具体是这样: +```js +const GET_ALL_START_handler_ajax = () => { + getAll$Fac().subscribe((response: any) => { + const list: Item[] = response.response + action$$.next({ + type: CONST.GET_ALL_COMPLETE, + payload: {list} + }) + }, (error) => { + action$$.next({ + type: CONST.GET_ALL_FAIL, + payload: {error} + }) + }) +} +``` +getAll$Fac()返回一个Observable.ajax,subscribe启动这个Observable。 +读取数据成功,触发action$$.next({type: complete}),失败就是action$$.next({type: fail}),再去找handler,转一圈。 + += = = = = 分割线 = = = = = +来看一下`index.ts`,和上集区别不大: + +```js +import { handlers, domTriggers$, renderer } from ... + +const stateInit: State = ... + +export const action$$: Subject = new Subject() +const state$$: BehaviorSubject = new BehaviorSubject(stateInit); + +const ultimate_: Subscription = state$$.subscribe(renderer); // will log stateInit immediately +// 对应步骤5 + +const changeFn$: Observable = action$$ + .map(handlers) // handlers将action map成changeFn,同时更改dom,触发ajax observable +// 对应步骤2 + +const state$: Observable = changeFn$ + .scan((state, changeFn) => changeFn(state), state$$.getValue()) // 初始值是state$$.getValue(),即stateInit +// 对应步骤3 + +const intermediate_: Subscription = state$.subscribe(state$$) // state$开始向state$$推送 +// 对应步骤4 + +const domTriggers_ = domTriggers$.subscribe(); // 启动domTriggers$ +// 对应步骤1 + +action$$.next({type: CONST.GET_ALL_START}) // 这个action会触发ajax.getAll,从数据库读取已有的todo list; +// 对应步骤1 + +inputElem.focus(); // 可以输入新的todo了 +``` + +## 总结 +这样,是不是真的可以不用装redux了? + +希望通过此文,能够帮助大家进一步了解RxJS。 + +## 参考: +[Mock Redux with RxJS][] +[Repo][] +[`Observable.ajax`运算符][] +[`observers`列表][] +[JSON Server][] + +[Mock Redux with RxJS]: https://wx.angular.cn/library/article/%E5%BA%94%E7%94%A8RxJS%E6%A8%A1%E6%8B%9Fredux +[Repo]: https://github.com/rxjs-space/rxjs-typescript-starter +[`Observable.ajax`运算符]: https://github.com/ReactiveX/rxjs/blob/master/src/observable/dom/AjaxObservable.ts +[`observers`列表]: http://reactivex.io/rxjs/file/es6/Subject.js.html#lineNumber25 +[JSON Server]: https://github.com/typicode/json-server From 2284b9b15f3a448245cecc47d87ae1805fcf89bf Mon Sep 17 00:00:00 2001 From: lhtin Date: Wed, 9 Nov 2016 13:48:53 +0800 Subject: [PATCH 045/177] add articles: DI Framework demo --- .../_index.md" | 158 ++++++++++++++++++ src/app/_shared/api/articles/index.ts | 9 + 2 files changed, 167 insertions(+) create mode 100644 "src/app/_shared/api/articles/250.\344\270\200\344\270\252\344\276\235\350\265\226\346\263\250\345\205\245\345\260\217\346\241\206\346\236\266\347\232\204\345\256\236\347\216\260/_index.md" diff --git "a/src/app/_shared/api/articles/250.\344\270\200\344\270\252\344\276\235\350\265\226\346\263\250\345\205\245\345\260\217\346\241\206\346\236\266\347\232\204\345\256\236\347\216\260/_index.md" "b/src/app/_shared/api/articles/250.\344\270\200\344\270\252\344\276\235\350\265\226\346\263\250\345\205\245\345\260\217\346\241\206\346\236\266\347\232\204\345\256\236\347\216\260/_index.md" new file mode 100644 index 0000000..2f285a3 --- /dev/null +++ "b/src/app/_shared/api/articles/250.\344\270\200\344\270\252\344\276\235\350\265\226\346\263\250\345\205\245\345\260\217\346\241\206\346\236\266\347\232\204\345\256\236\347\216\260/_index.md" @@ -0,0 +1,158 @@ +# 一个依赖注入小框架的实现 + +之前一篇文章从原理上介绍了依赖注入这个概念(依赖注入简介)。为了更好的理解,本文通过ES5的代码实现一个依赖注入小框架,它叫做`DI`,它提供了`register`方法来注册服务,`inject`方法来注入服务,`lookup`方法来查找服务。先从这个小框架的使用方式开始: + +```js + +// 定义了一个常值服务 +var con = 0; + +// 定义了一个函数服务 +var fun = function (n) { + // fun依赖服务con + var con = DI.lookup('con'); + + return con; +} + +// 定义了一个类(对象)服务 +function A () { + // 依赖了服务con和fun + DI.inject(this, [ + 'c: con', + 'f: fun' + ]); + + this.sum = this.f(this.c); +} +A.prototype = { + getSum: function () { + this.sum += 1; + return this.sum; + } +} + +// 注册到框架中 +DI.register('con', {type: DI.CONSTANT, value: con}); +DI.register('fun', {type: DI.FUNCTION, value: fun}); +DI.register('A', {type: DI.CLASS, value: A}); + +function B () { + // 注入A的一个实例给B + DI.inject(this, [ + 'a: A' + ]); + + console.log('B: ' + this.a.getSum()); +} +function C () { + // 注入A的一个实例给C + DI.inject(this, [ + 'a: A' + ]); + + console.log('C: ' + this.a.getSum()); +} +function D () { + // 注入A的一个实例给D,A类前面一个加号表示单独拥有一个A的实例 + DI.inject(this, [ + 'a: +A' + ]); + + console.log('D: ' + this.a.getSum()); +} + +var b = new B(), + c = new C(), + d = new D(); +``` + +输出: + +```js +B: 1 +C: 2 +D: 1 +``` + +先介绍下语法: + +- `c: con`表示依赖于`con`这个服务,并命名为`c` +- `a: +A`表示依赖并独享`A`这个服务的实例,并命名为`a` + +从上面的代码可以发现D是独享一个A的实例(输出1),而B和C共享了一个实例(先输出1,然后累加输出2)。上面的示例代码已经演示完了这个`DI`小框架的所有用法了,那么它是如何实现这个功能的呢,且看下面的代码。 + +小框架`DI`的源码: + +```js + +var DI = (function () { + + // 定义服务类型 + var CLASS = 1, // 类(对象) + CONSTANT = 2, // 常值 + FUNCTION = 3; // 函数 + + // 存放注册的服务们 + var services = {}; + + // 存放共享的实例 + var instances = {}; + + var getNew = function (name) { + var service = services[name]; + switch (service.type) { + case CLASS: + return new service.value(); + case CONSTANT: + return service.value; + case FUNCTION: + return service.value; + } + }; + + var getOne = function (name) { + if (name[0] === '+') { + + // 单独享用一个实例,直接方法 + return getNew(name.slice(1)); + } else if (typeof instances[name] === 'undefined') { + + // 把共享的实例存起来 + instances[name] = { + value: getNew(name) + }; + return instances[name].value; + } else { + return instances[name].value; + } + } + + return { + CLASS: CLASS, + CONSTANT: CONSTANT, + FUNCTION: FUNCTION, + + // 向依赖框架注册一个服务(可被依赖) + register: function (name, service) { + services[name] = service; + }, + + // 注入依赖 + inject: function (self, names) { + names.map(function (name) { + var temp = name.split(':'); + self[temp[0].trim()] = getOne(temp[1].trim()); + }) + }, + + // 查找依赖 + lookup: function (name) { + return getOne(name); + } + } + +})(); +``` + +是不是觉得很简单。其实就是用一个对象来管理这些依赖,如果没有实例,它就去生成一个,如果想独享一个实例,它就去实例化一个新的实例。 diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index b7d6ba4..3db4bbc 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -263,6 +263,15 @@ const items: Article[] = [ first: true, tags: ['DI'], authors: ['钉子哥'], + }, + { + id: '一个依赖注入小框架的实现', + title: '一个依赖注入小框架的实现', + summary: '《依赖注入简介》介绍了下依赖注入的原理,本文尝试使用ES5代码来做一个依赖注入框架的实现。', + content: require('./250.一个依赖注入小框架的实现/_index.md'), + first: true, + tags: ['DI'], + authors: ['钉子哥'], } ]; From c820f4bbc0d3280e2e9a3d69f22fb9fc24ff1530 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Wed, 9 Nov 2016 02:46:01 -0800 Subject: [PATCH 046/177] adds simple-javascript-event-and-async --- src/app/_shared/api/articles/index.ts | 11 ++- .../_index.md | 85 ++++++++++++++++++ .../after-enter.png | Bin 0 -> 76595 bytes .../after-line3.png | Bin 0 -> 24100 bytes .../async-checkbox.png | Bin 0 -> 30848 bytes src/app/_shared/api/authors/index.ts | 2 +- 6 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 src/app/_shared/api/articles/timliu/simple-javascript-event-loop-and-async/_index.md create mode 100644 src/app/_shared/api/articles/timliu/simple-javascript-event-loop-and-async/after-enter.png create mode 100644 src/app/_shared/api/articles/timliu/simple-javascript-event-loop-and-async/after-line3.png create mode 100644 src/app/_shared/api/articles/timliu/simple-javascript-event-loop-and-async/async-checkbox.png diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index b7d6ba4..bcc20bf 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -253,7 +253,7 @@ const items: Article[] = [ content: require('./mock-redux-with-rxjs/_index.md'), first: true, tags: ['RxJS'], - authors: ['Tim刘'], + authors: ['timliu'], }, { id: '依赖注入简介', @@ -263,6 +263,15 @@ const items: Article[] = [ first: true, tags: ['DI'], authors: ['钉子哥'], + }, + { + id: 'simple-javascript-event-loop-and-async', + title: '白话Javascript的Event Loop和Async', + summary: '以编程初学者的视角描述Javascript, Event Loop和Async的模样', + content: require('./timliu/simple-javascript-event-loop-and-async/_index.md'), + first: true, + tags: ['event loop', 'async'], + authors: ['timliu'], } ]; diff --git a/src/app/_shared/api/articles/timliu/simple-javascript-event-loop-and-async/_index.md b/src/app/_shared/api/articles/timliu/simple-javascript-event-loop-and-async/_index.md new file mode 100644 index 0000000..fa5a7e3 --- /dev/null +++ b/src/app/_shared/api/articles/timliu/simple-javascript-event-loop-and-async/_index.md @@ -0,0 +1,85 @@ +# 白话Javascript的Event Loop和Async + +## 写作原因/目的 +作为编程初学者,尤其是前端的编程初学者,免不了会问:什么是Javascript?Event Loop是什么?Async?Async?!Async!... +笔者就是这样一个编程初学者,他带着上面的问题,在网上寻找着答案。本篇记录了笔者经过一番浏览之后见闻。 + +## Javascript +就是`ECMAScript + environment api`(enviornment可以是浏览器或者叫web、Node.js、Photoshop、洗衣机等等)。 +`ES与api`的关系就像`自然语言和语音助手`,自然语言(ECMAScript)定义了语法、词汇,语音助手(api)定义了指令。 +比如,要开始拍照,一个语音助手要求你说“拍照”,另一个要求你说“相机”。放到Javascript里,如果要发起`http request`,在浏览器里用`new XMLHttpRequest()`,在Node.js里用`const http = require('http')`。 +DOM(如`document.addEventListener`)、BOM(如`window.setTimeout`)都是environment api。 + +## Event Loop +Event loop包括`call stack + task queue + looper`(task queue和looper不是任何官方文档的名字)。 + +- call stack: + 举例说明(例1): + ```js + var a = () => {console.log('a')}; + var b = () => {a()}; + b(); + ``` + 在Chrome里,F12打开developer tools,先按F8(暂停脚本),在console里贴入上面代码,再按回车,状态见下图, + ![after-enter](./after-enter.png) + 注意,右侧有个call stack区域。 + 然后按F11(逐步执行),头两行都是变量声明,不会进到call stack; + 再按几下F11,路过line 3之后,call stack里出现b(那个`anonymous function`指的是整段代码),见下图。 + ![after-line3](./after-line3.png) + 然后`b`调用`a`,call stack里出现`a`,`a`运行完,退出call stack,`b`也结束,退出call stack。 + +- task queue: + 这个在developer tools里看不到,全靠想象。举例说明(例2): + ```js + var a = () => {console.log('a')}; + var b = () => {setTimeout(a, 1000)}; + b(); + ``` + 上面的代码中的`setTimeout`(一个enviroment api),它会去到我们看不到的地方执行。 + `a`是`setTimeout`的`callback`,即`setTimeout`在1000ms后会call `a` back。 + 在`setTimeout`被`b()`触发之后,等待1000ms,`setTimeout`把`a`添加到了task queue里,`a`不会马上进到call stack运行。`a`要等到什么时候运行呢? + +- looper: + call stack里有代码在运行的时候,这个looper是休息着的。 + call stack空了,looper起来,看看task queue里又没有排队的: + - 有的话,就把排在最前面的调到call stack里,然后looper休息。上个例子中,`a`被添加到task queue里,如果它前面没有别的任务,它就被调到call stack里运行;如果`a`前面排了别的任务,`a`就只好等一等了。 + 插一句,`setTimeout(fn, minTimeToWait)`的第二个参数是fn要等待的最小时间,可能会更长,就是因为task queue。 + - 如果task queue也空了,looper就站着等,一直等,等task queue里有排队的了,就把排在最前面的调到... + + 周而复始,如同一个loop。 + +(有个名叫Philip的Roberts,做了一个可视化的event loop,叫[loupe][],大家可以参观一下。) + +## Async +如果在developer tools里面观察上面的例2(F8暂停、粘贴、回车、F11逐步),在`b`从call stack里消失1000ms后,`a`会突然出现在call stack里,很突兀的一个`a`,并不能看出这个`a`是谁调用的。如果要看到这个`a`的来头,可以选中Async框,如图: +![async-checkbox](./async-checkbox.png) +这样,运行到`a`的时候就能知道是`b->setTimeout`调用的`a`。`setTimeout`并非call stack的一环,所以是灰色的。 +嗯,选中了Async,Async,Async。那么,Async就是: +如果一个environment api的参数包含callback函数,那有很大可能,这个api执行的是个async操作。如果需要选中Async框才能看到这个api的存在,那么这一定是个async操作了。 +- async操作所做的就是:当一个async api在call stack里被触发后(比如`setTimeout`被`b()`触发),去到一个我们看不到的地方运行,然后在适当的时候(可能是async操作结束的时候、或是点击鼠标的时候、或是http返回的时候),把它的callback函数添加到task queue里。 +- 而sync操作就是在call stack里逐步的运行任务。 + +常见的async api包括:timer(setTimeout, setInterval等等), eventListener(onreadystatechange、onclick等等)。 +另外,Promise和Observable可以是sync也可以是async,主要看Promise.resolve和observer.next是谁触发的。 + +```js +var p1 = new Promise(function(resolve, reject){resolve(1)}); // 这个Promise是sync操作 +var o$ = Observable.create((observer) => {observer.next(1)}); +var o_ = o$.subscribe(console.log) // 这个Observable和Subscription都是sync操作 +``` + +## 总结 +Async什么样?call stack里面看不到。 +Async什么样?添个callback到task queue。 + +## 参考/推荐阅读 + +- [Concurrency model and Event Loop][] +- [loupe][] +- [The Node.js Event Loop, Timers, and process.nextTick()][] + +Happy coding! + +[Concurrency model and Event Loop]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop +[loupe]: http://latentflip.com/loupe +[The Node.js Event Loop, Timers, and process.nextTick()]: https://github.com/nodejs/node/blob/master/doc/topics/event-loop-timers-and-nexttick.md \ No newline at end of file diff --git a/src/app/_shared/api/articles/timliu/simple-javascript-event-loop-and-async/after-enter.png b/src/app/_shared/api/articles/timliu/simple-javascript-event-loop-and-async/after-enter.png new file mode 100644 index 0000000000000000000000000000000000000000..f80b5d5ee0b661019fc0433646b6bb0b51dc1ce7 GIT binary patch literal 76595 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
CJ` za`yd|yIVa2rLpdkF~bk2ao%hyEyPH#lu%(W`muy^QBF&?-(m|QDr!Lu=Wz(f>nzq( zKdF*$i-+pT-4rSEC3VmKYd<#-Ve8OrIE34*{u37hTALm)Oz@rKC-g|OgI{w#D52s1^i68)ISC~< zN#aVdyEVm7_vY|{5d{6%w=lS(-xUB>=5z^xvp5g2vzs)a|4^oqIoKU&1uB2d`CH=$ zmoXFT2FeJs2C?0rj+)`|40A7szuXMi`?Uu632mf!@3zC&vWb^BGt3vBETOcm0^C); zdiH&5d3!&xde|hwk6FRbbbB>%i%7uab*3&LaQ(;;7NwP-$bl6!ujD0RQItm@a}q{r zk&%G)ceZ~v76vOJ4=F1|c@G>$?(cX&SUwd8!0ikS0WmG4NAR<=>#Aj=(4R}KSu~*H<<`&I zUA(>0PzDf~NYL&!Zx$kI^C#iOZji*%>Yr5Fop5kEUt75|4r_(@pS$14p(-B>Xkf1oS{Ru49mqmr{kpO8+v~nB4NL_~qO$e3 z29)fS1NIiy%BBTvhue6_PT-D$pXdV(SoFe&QeK%q&uuE~+G9k(Wh!$0k6l>0)H*6gs}uDfqqe@u5lElM%_HQ(i&`d z@6ih=Gg*RaL`Hn)UXE4u-Je(vwx)Q!ZRb?;dsbjdl+glhapPOkR$p+?MUZ{|sMvXY zx;Z=`isuDHc3cW{fyaGS15wL*Y?w7)SsJOG02$AocaxN29Shva*F*J!Xr+1biTI+| zO!cm-`{#DCKFuk%OZO8a8-ss8L>UsbCC>$K>|n`(_ZNF{uwCVRyJoE|xXw|)wm_Wj z?PUH1lFcr!xbwmaa{V7Z#)&zxzGIc?jF+;?QYaC(@|}5FHtbRt4gl_%x<+)&aWU_o zmk0MADnFd=CYLe5SsAVQ{%n0HJfWgcQ|Rsi=z}h&jIS@%iK{dQ`A2jz*Oh+TH2;y{ zA>Ka!^MyWHcHpMB~tzI-JR4 z?3ywWL;}5x!Mpm6iZkPTt<%)EY(q9tEdABpw@YJ)_bB{T$MO*ZnW6>yCY1W=v++`KZWHnbp z?zE~c{Fmu7>wWjaVK-fLZ^kXRZ;N8POoOh`t2fn?U8q^>?t5>GFFU1A`I{fC1fREo~EP9uCKHvb?>n zMAxx{>w2pHrSrknOO|H~3-MB@wo~Y++AAB>^*cqLQsWez8pzF3wvN_pxpi-gOEhYI zVkW7I5|d8t)E%nr(G`C!Y!)H%SbPvM?{c z+kC!z3~AVH%zs$y7GgIPg0FpFDLANR>D7;xrjQda>Non&4^BO!Mz7HL-gxtIUcE)) z!N~sBzJwGSwq|szM@x@p1D&z_#|9&h(V(3>^SZa2n#R)`TO%%014jPq=AY5qe5_xr z{N1G&D=Bjxr6A7S<2U-Gr|wM*=-;rgs}(4Fg~BmX==+ppgA@F_hr#y!qm!* znVx#lS)8~FLU2(ZncNgG)vUNPo2t+fu}+KJn%7kNPHSA6_3-crHkto%DCnjSHU*ir z!f*lqGAIrwpt~YOHHXL9Py_xA~SkLCL> z=1yo1Hx-?uRo`1F}6hkWv+9XcjHIoG_I zGyezQst!DRsfD7@E+o9}Yq@Ns=g`9gh=OuGFXhmk>h|f9$*tHY$h&?SAnXAroj~mnjjch)(inFYy4398{e_8^ zlYMdJiXKiGArkTUu8AZ2=1&Wju-{v|6@eb|i4@p47empS++MqPZe>W+-i4^{=bGy+ z${=JN+}A*%Q7j&vbC{VllM3Hdc-sv(rm@oQlhw<|Sgs6wR58I#fgrp)4Vyy(Zy(A@ z)hT^=m=ggtrxz?CU?_j_5V6;8^GD%SkBF5$wk!3bo(#4O`d#~BIM>Q3SN56QxySVg&HjCPFT`f1eOFdb-pfBZ-Ogs>~oYa>EJ-ycLaX$MP}dQ$vM#_O!AHTW_Z- zxk4(nR!khEQa!(1C;32=qW(OY^!V*E%NyyjhpJ z;e@265j1_DPT-)iEB)j73#ewrTa&rY+x<)@qU3JdgXFCM*P03Z_EQv30ml0;Dms^t zn?cIu=lh=Ukl>d^L!hTKS2nGIO`#Py%0X^7pf-;uXwJ(3MKr}PL&$*%ry95@=Zv37 zFYmY_Ke3*1_J&>1J?kJ}Iae$@-}0v-lSnw&g-TH2bLY<#M`=;~^RsUIv_T+UWtwSA z)%C(J=ZZs#1{`>Wv-k*6QN(CxzS$3#fYp&faJa%xsS5J^MBHd4_G?0OinCbzp@NaS zS$peqeTmFGsSOxQivFyiKMNBjbxSc{J{g!(B(Wdi-8D|3Z#($(glflh8VF@B!!!FK z@s)r4r5H$^>26$k|43PMpUBASOx@3lSH#>z^(wuJJ3o2ft|$$Agc4ctMzRE9s7#kY zRfl0#OAjNHeWEL3%i!=xaG^#l?;C7DxnET-8?UKRQ1Ip2Brix%K9CY7)MRwOK!UwL zJVxO;r$~*%E>ok^1@AM%ezWZQW45X$^@jTx(rSUV$hyq_WcPi1vujUjE zxk*mIz=!F6o>!_OzgJrCKyGUS5v-ae<58|?QUP;cM!!5FtGU$kXlW^41d{qz9xL}h=z z`cVQ959$~VMfe)!Kwj=84{4UUz0s}Lh1b~GANKPophsal-@aWBE}a%&1uL8$$>CDg z>yRm84qRE@c)r-794JsYg>)J%^}Z=Db`GDnBNF!q2ga8(BG*l9zIP$!Ddfz!Ly1$s zuCj7}%b{KjMT+Ej(lLbZ?aqiRsksz^R_GDcIU3#*a|P&jC($T5^l>|-Ii4V*@=MzW zsb4v6&W)hY%5J<@9VX&VWl4&}^5&f=SUbd3gh6gUTOTEYc~&-Eo)aB)F{e+j%j|W4 zZw}x%D9-B8`8L6pjo$hKRCt$9z{u;CsOzfDs+EeDe_&Jm?ivx6~Hgw{%=_~J~ z1geLu!xyBd*Xzdis&aUUhf805ub(fsdwVFGS$b@M6l4pRk-iDsP13HE)r})TPmD!m zW>T{?ZKw9OtX*T3L%$j%D2oOD*?wO-mIaKuQuVM^w04Td9hSW()}{@9-rff>)Z(r1 z_ECS@M%q;52%$)F2FVW6ooF|Q%VgIKeuE8;NrS4?ScH$@+C!yakL_mi*DMD#1LRD8 z4%@#<6CvvO#;s;cBC?%UmL;02y#exdO1@YG0GPLh;*q^y_g_6c7nU_Suc=gO#7z|} z__VT?V$X|2(W8Mr8XKG-iX|AX0s}_{?{gAHOwgwgOQmfa<;<3WG>6#3=LtE+he*JJ zt;!1jXFErFNgSC==627ELbY9X=CXx}PT*&r23f{k zZt+)wZRm=}uya_;Qr*ELyVJfgamGUsS(X zK(>p#AOE@vHf-4`vQ-_!rY|>28zd1dK@`s5Rn?9qJ2ID}y>{zLbI$OaH}oCcO#YKMMqtz7%>Wa3B8Ta}>A=#i0|u zj+ca6KHaG_%Jbavw}+(eWIHWSTbeh`nV&Tzd{#P+Er?Ac$}1iLPK2$`0B{1PvVwsT z8dLu5IVC0jGorf-g}+VVkn26Ev@=K{s;I5W{s!3)OB(l+%lZ`k@4%VMhu{EeYE{U; zflThoSuy0;sx3ynrB0eU+?JwPb65+!IG-GYoY$4GpUsYk0A{2tBMz3C z^7Vn*D-sk#oqf>tTGGj5-00-IZ*C8d?bB4x#0BQDEh4d{4nICuxlOdVO~p%f1f(Qo zP4O%H7j*!XkcLR3gtA|YAGv5(psgB|8Tr;{GaB#g5d<^VUi;~2JHQh>=AkxMb#t)7 z4NA|><~yIIH7um}x2L9>%BmNU!*o*j!z&As=4&aHx9FoN@f>BX&Zx5Z_c?!NRGiGaVD$c3ofsJ&tl$A zccn~KWtJySX_){_x@~g+Cp~{w|FuVqpd%@Mk5X+9@@1 zwUjG_4Ao;n{#X%P6*;#2YZ%F-*{6kB&v>!mE998~;ajXdrr(3 z3J!I*x1ycl;FEUNUQKM??GbKdQYLk{i!6*kk!+9&?K&9_o} zl1i!#&A#6%O+or21Chsq=Ieu*GM*I!9w?r#dOL^{Ym+Sknm3=GtYEsa%WbK6Cu!QI zJVS}>w?5=*MsAJzm-08`?&bWvtnxZ-t&<9^gKXY#aJ?YnR@zTrXZa%$uwiB;%BI)> z7{D;;Bl-aG3*+}b-um%by`*+FV`YlvK>E35tyqC}m;?R-+zShIE9)GDp_3tTT8LH= z9mz)Zv!dtBM2tX5R2X*cclgC^pLZ2k1a{Aoq08% zQ{0VipjhVk#N^8sb(eN&2PqI6rNyH<^Rq%^oNkNpJmxZc>7XI_L_zub#kgL7UfHm4h2#+-AapzJa= z{{Fzz@bg8h?+eSp2mV!pzv{nq@wNh)ID{&?-9=tG#@W+_DROFb|u@WFtqjL z{k*SYo-iS&yVFf{dbxgG?`>FP<)>b-y=i7tNUOe%iX!H|bcl+be-W^Ve{G}<**?lTG!XVuWo<^fhaCb55*J3aRD7U z!4=wh!is|~?3x-LZs_DQ-aNPy){LySB(oH*5Nyw+WKW19ND>iXO=eW?cSgX`~Ib5B$A4+Xpl@4XTKY4Kz#Cz#)&*-WVlyH=Ep9I+}X zl;}6X5H2vWP?(*NT||M#Y#L|m4%pvU26zWqZSL#W&^XctxhtG%18&*ox=oyJc zIW)VY@mlEI#I=O+ONvuzzZh-W@XlGEzhA3Ya_`3(^WIk6zLWKWF{4sUX0>O^Md8tbfHA|`p*xPZ3?5ezIt3B=wPKX$h(IA zz*a)wpq(y{+kab%^mfmQ;k70@a-4dy?krr>ZgF2Jk!w%AQSUyI^|p=^3g7b}N!IbD zZV$aOvwMS2+$eSX?PgB70uM85CTl7xC6|tp+i~Vq+qU{Hq+N{iXK4;uQBiLzAs5H0 z`;y7NYWsLy(lKHPsX_BzWuGOujSr>*&V}*cDgI6h0at2AG>(R z024HQVbjt?Aew7v8OyRauj!nlEEG0BZJ>O4!pX4Yg^uq`NpWVdki)Ervt8A=LUNpa z)S@93y8AcEB%F_L=8u56p2%_6%7Zj7B7H&8g7X zoUkYz`5boft8b%>f)VJjFoxPBUx)pCjL*>ps6maE4F02AZJshlDC}CC2fM7>>xx2+{Q4L>g-q_zose%6!1qs$tvK~2Z8rvo z=zvyJ)-m!x-P|rYtbnR2rPctqKK<8hl_bvV)3}MwTr=OO zo2Ola$tPY2R|h<4jyh0&-)Hwoubzx9j&lAMw4+gBKP2!9051%?f+)c>r#adsBUN%_TBV)bDh^`cz>#9f+EkWv!TQ2 zwq*C-=Zs;*ATF&?P#^AE0l17PQz0YvmIXvw21D{e3RItBzShOu9LVCJumlmR^oDrxW( zK+QO~0k{G4kxQ|L4!hWbwiimhGAOblcb4je(OL2`9-T}+;mF7m|F}cD(tlmnd&1Bz z2(igfQ0#;O8p-c+-@t^O7AyZn>e=3h555TlvUCU^{`G8O$PKQo{mOXrrB&E`9M^eU zev>I~j{|YHd}S*(N^6eyNM{BB_voAd1>jDS@th5ZZbhNs0LC&@IGqCa!KDULHCh2< z8l;)K0z{DWj?6yjm2bx0sen2y+(=J`>usit_|4J!S|O&+OaMU;e3{t9(p~*4zrZFoI0D zVZ(6qs~90Yx#G4Bl^}4DdGpPNR8ptTrwbB6e2>@sSYt2}o3x?j3n9yga{C~VZMf91 z#qi$b*xUWRerSpD25fu1OH-M}0-%hK?2DmBl3{u|n4xy|eJUUBX83{QF1*51j5#!W`8yn|p znkaFV9l)Hkn4mlUR7H?VEp^g6p#gRg`>Y$EpGOZL9x*kShM?*WN4x@ut!u43-w%Y{ zK=giP*FQb0g08;-oJdDLm9lAg5&~+5bOddOAza}_rx*T!BONp-dG=eTVJEVGC^CuuwS z2)RLCGGwgmB$F=xCbn-^y^>A(=h{rqaPuv(Z-tn8_#}w@{r7GLXgDqs%Tzc)LNCUt zSJ;JjbCDR=#Nj0aPT47Pho;-d-Kif?MdrOlrV)XcF~+uKm9K<2l*o?c_|;gaLj7#! z6R(nKvw!zIlWvpbD*(5Y#L=b5i{%ss6b8}s>JCugCN@kbpKoc4rktW;u}NbJj}^7= zs3a0;6K5+S3b8ihu1UXy+_>y24DW55&`u(OrSU)&tIS|f=_EL4w-6h7A+NsM8@9+c z&m^+dX{4hqn$6n(*1oxc9PUPLAO;#c zBQ)TRAPslu)~1)CIB{(

X0odd2)$35K-L*Wi~C_jMFqeF|ZIT0ar(pPXaqzesSec{;WBEUexERX47)*bkh5eVhuA&-5q9=zYTf@EF{ znzNkmd*vJ$adg917Xi4Yt0us+sT-ahf&Y%K>&*!iSZR{>u#8 ze=Ssd65i31`tqx4$RM|883n2t@Qy~j=#>>fmfi=|sk^FVM8fqeD%)WBf6ett37IZf z={E$|Wn!?6fvAnT88ZX0-hTf#Is}>RAfI7qfy@6gaW2gIx@H_51w=?y^V$W#ueoPi9dsFat+=Y zb{o)@x&wRaO_`jAcUVylzcl%S-F1s9FBi}{6&V*310wCcJr}$`x1xWrp+5nWixQii zVn@$ti*1vUZyU_7pjHWnTvmexqzIB*)-ig^k{+}!nudyK*VZ8xOO_(4NkQPP^y($ zRC&9Ak`5?La+uZ^yY!2Yg+v1=I7;Mb^FG0VuZ(1YNkdECg479P`!-Ncd^tNJmlFJJr4m%mtK0`Zx<)^(( zDgz^RypswdfRLOGfdQCjv#A?jAV`Qb@K&weX#!J@RdcWVz|Ym@sWU)QUT)vnvAA&m z%{rw4*Ta)N3aSW_hc^m{l=I-)!*Zq%;ZuB_`ax?cD?r1w&)qxny?}i>B12=Xtqfs-sIkd1qvwd z7WFb|xUsy>{@&PuLJWnI_0o=IJmlGEq-M*>yLPV{bobp&2p{1(pWe2hm>P0G;m1px zbM$ck@Yl@55sx0B#UP=@H`t!OlR+*bhT2rk{EI)X9cw*@S9+I9tqNd^(cWV*Ap=Os zVvph!CFl-gL*BZKzU|j*4Kw~qz)!CLGN~DY!*+rVuleOoNOtJ=^>yJCP*RokE65WY zUyRTSjU<{m{`X$43M_v8TadgQZbwXd4txym=cB9*A>%DgjpBL#Yl%zTwCAeK$tm%< z+N}dv0G^h&oxhImP0AwoA?Xh*<9QW5{9)sPP6TT?WKDLYU5oil-5hRu zyf8b+k3{T2tgYcl7A2Z6{cB_Jfg7Bv9eqyYhGaVD8AG73I0v`kPt@vVjhlce6Xbkt z@(i782kZCLmWtUy*jM#!Z@~8Fx+8N`i1#vOELJD}P|>tNC~9 z^PU!$GR|5f8^NVP0i*_s&W95~Nyj+#kLS^;a)z8svK*q9UO6e$gO@_v_;Ic12S^#G z_OAdt@15z_Ivy&&-D8uxeO|buPO4~WcU|egGkivg{>jP>FL#l)@dC>dHJ5YwPUcf| zV+OB_+Hdz^oW~mscFB0y^0xQ%sP5dojz<|cM>HwaS0vsm&7oL?$x2l>sahADy02lL zfqY*?fTL$v3apnkChtLdNwJ3G^nqIw?cdb?(zemFqSLT0Jy4;ak&sLC&7fpf#vv<}Y4^%2U%SbDRmod4ygh-7u zj!J>x1w|+M0%cHvqn!ka2A8PA;7>pW{M8NIxe?R?#+A+-q(&wPTT=$rP9$`?5>PbC zFIiMxGoXX)%C8{vV@J>Vf+B7>;ak10Ck85a)r0-LsUW+2MhL7#Wckicj|3GVD}o;( zBPO5-B7>eYdTy$|K3fR{TN8-A*Y_79-vSe_yPvM8()Sy0v7)vIds~SMh*sn0?I0 zC_xlEw&eseah6ImdA!9J#7?h7Tt;eEARbq}q-HXv40e5_XsVRc7=x(o6)G+>^~?1gVN6Lh#AcxX&Tck3H6Ee`t=pVql4qbQ$^j z_#V-TKi3uL;lSHS-u@E2_hmlKfJ*(C!Ev_yd6`fiycSIv8-Dfp8kK&(V0n@;FT!cCdvm%-R)y0s83%F7+2I3}E&Ll^c1pIyg{PW$)drQ|A6^{D!; zIjns`bPp}Zd(K2sEfvUC96>3_Lrm}2D)MBTWJ)`XQH$GSeV zNM^MlHWL=Lfh8Yv=cdFWxAT-KZ$WG86?hm4R(vz^YI(~?-sNjxz(PrNgCvc*wlYnt zMZ>o#yIur4no>0re!PuHEhZ;YCn+_HjtA*5;w(JizjSQfC}=}Xt!<$zMv8>Mz@>47b{7wbxE+u|{<>`)NQG^c3K6ouBtpuE2k#H`jR@kW6 zm=)l%Ww0KjR;OH3E931n3DHjBZm+mdAQ1?E^MDmk+f6TDIa`6$IhUhk|PbN6%-6doj$^=zivv%tsSIRBt6ZgRD$POPQl>=#Q)llo@Q zaOXB*ZD#5y+UFvz9-VFKw!i4?@=&H{d9W)=IVZ}|(r2Q%wMAq=0z0XQ(^A1tE-?EO z80_*hMpjJ4$tkgY{g;|?4WeK9E!EDoK=;YAOe8=w!PP4Bgi`)81g0<49XXExXAS|@ z`=teYH4VI9adM&Ol*=woCQuC+pF*!Zx1qPk4MF&957;Byn+m&z!y4Ppu)P-$RgmU6 zkHet|cd_4{P?$0D8bqVi8yN;=l2crPyk_T4EW?~djsNEl<;R8441@waKYMgvHiF*7DdV%{5r`e4p#UNG`2WXGDzjd~ z@y3BPF19ct926er_DA3jsD*xzB0Fje;st~J@G6I%&#=GOAP%V&IO|;o`){3}6A<&5 zep3cVp%9;6FQVRE0%&ae+dPp!l4o>y+<{I<$U>r6_Mh^n23sWA9ln8m4WxCq0v}d= zb1xDJ`J8}0j}*i*+X!ZoS<3qwnidd4)B@7j0zd#w^{?=~Mc3ey$gpzu-7(5dK*__w zA9o9cE;lE3>fi+tvZypZ6mtC)yA>81{dr&$P_sy60y+p)xsgtH0^;I^E9O`_yr>I` z;WTvYNiVUGwKfZ2TYjt>83FNAJ^)upy(Y)p8+Yg@(RgU!^YQU#zkjX{zo8Z0S_ngH z{Wq$el&z0%iz_|e&l3Rx+OsRwW$$gP9- zZjB`F?JWl<&eTG~HZ+;X`sT0{ilKv{e-R82FR^ zkLI8{7I)_D28%S$`*Ey5~W39e1Nx#D%Vs%`z0q3 z)Wk~D*bRr`ot%^;NxJQf#0!JD^s*oWEBl4l6RnYvpg-^Q?8{bCBBs&~XCn>8aRTg@ ze&E<}%ohWa?Tm!SXJR112okE62$3Pf!(EOr#=ZO|0_%fP#j9OR$g)PHKv@Dfar2e0 z+M5u1smXQ~8N^Oj+fhC0CqT^8&UXPRB7aji1V}68ochx2-WEC$@Qd(m(b=s3yuu2) zmUG$43MagtGp?MC=Enqbk`oF>pPc@ZRNnYgD1>em7CDHQ9ww0;k6?YOu4;4cxpJj; zgxk6Mt8~pCPW`va$OZ5NxR`c$58!~O+p-U^MqOOF0<=|YdhuA0(Rm}^H4xPLwtazd{y09%5H`gY16%^vNe<=L(?Ne}apg69I+dPE~ zsW7<6OAz4TmSB1zt13)15bwkBRZho+fOcs{!edb!7#&VFw*2!BS{>g-F#hkeMEfT$ zx1>_pC@~8YGVv%6jhV%?hT0@`U(^d@!>|T$ zQbhR8zT%bYc*zlZfu;QidQK>Y*TMGWd7~%NuPwccm;VX&{?HbPCG0|}eodIukQo>x##wk{8Nm#zu%z^@@ArH%U?sTvA{bZYSz7z~7rWg&Y_C@Vf z)&lKUpDPT6^Z1r?89x#k-Hti9N6NKc@_* zoxFc7@XL`Bh?v`4-<-?+cppK%@Ja@&qJ}%a*5D0xvr`J)c3K~#SqAjGag=?Di5EO_ z&}WSB+#&vqPukP}Jd05cXwwSecKB9sx8?o%IOqtV&)p7Wt6Oc7}>zR$Z0q9LB~^ z555T`GIxj*3XqHn(9iV{;kM~Qf@UKfyRP1oCXN&CIX`_vDXvkgmMKf0d!!XXOK4;g zWs+R*no6Arr`1DOy_{!`B9x*heAj45hnf3%j%t>+R+n!IYXPelRaj*Kd^7XSwJx)6 zrB9DPZ=wG_-0!NzXO5Q_=haiAE3een&~>5CqVTbQ3^R#CS(7JSP(_@@9<4SF@-GW- z!tNc8I+uQ2vE?noy*R4jw1tj*WbReJZHn`%!h2lJ3Y336d?H;p)~6A%`PGKUlsi~f10wiQ+uF%QFmyBtr(TW zbt4yKyH0SK$-1spHKWiq+zDL4}KnMc>5_3E#sk zv)&wcHp;r1vaSZjw|)+5Yq{WMv{jT8dR5zDD#**5ymD6Z@5c`(SHal`wkxdZRE3+@ z{=rAU0X=ZK73*;^K{&^$!RhZti~w-&AAv#(+{y4;;8IG{JMSGrez41F5@u#T~rSDj@ zK>nSPpekqJuove+8VDjiIRpY4X0pEeuT;sKK0m>|bP8ad&kN<>l)(c$k{fb@AOd0Q z5mhos+WlDmUPA~*On54a{&4tF=^fDN%0X5G#RMn~62sOjAJz*4O61nB&2tAiL!H4! zgpd*5FizkNB5k`vzP3Dn8ZvfG?n}hl=*U%`Ru^GY z$YMi|Xeu747_qu0LI@jAbrx)Mqg9I_3?{Bytg@&>KFXsLA(j0ykU2fyHrcgB_+qJm zxHd&(v9j`2a`U9kS1g=5#9}3YTm7$WRm8vq>TCmPn9ZOq>3o*c7H2yc@*0uZO`-=m zU$hnQC>2>C=9GFpR3}v1ac2Gu(t4aa`Y))^r;rLNvm&{m?_)QDhAh=BGb6ezq=bc> z0D=fO_KPlO_z`ipsj{8vZYE%1EX2)UbO3LfeP;qGJi(h(-u;pVyLY{zmOvn->ps1J zDRnxXvt)6;`xhSVnhe=z$UF9 z37F8!WorZyoe#;QL!{@&3E;`g0L||7Oh%~pldh1RS?4uvRh zKNziqB03TgbY$I=_~;+AlYGdwAoP3576Mpw8gzh-%ByxUDk`+A+T`xC^r7vwqx`l5O80pz!eQ#Q+h*v==$hcA*pW~c{6VFhSPfP7U)>gSXr2xuSBz32 zP&xnGbWIa;4$Di-*S04OyKHV#lPDpB_7$yA!ns!QqOZ1W-9z1}8UhP8+Rup~754@~HGiEgCCt--@ zqr+>0(URc{wx6woH31n2M6q9J^`zA+yT2SEGc7W_^eCPlp}JMY36EsTnM^_t4=O75 zbAt>x7@jl!LaALu+%pmwaaI)7dM^S1l^^^mJviMUwsM-U05ZcMNU|05*F(;lm8_#g z${quf1@sitG_DCcA@;Oz?jV*@?-ukaG)fLd_oT3bmTc!~*yQhH1~^F({+)A{wZ|Tx z{D9lctsB`*#GQFU|IswpiMBg@o!;6Gdf6ebS{U-_)M(i9vG<}r9wFl&o8hKF?Hmqe zZS}h0JPH0>7(OX6=;2JiLjThOx4-7n>CxyOfl(^kr{kG608H^}-aePAyfJ_CcGeLX z%fi?DLILa_XY^9Ehu<6ky!)1zBhT^Hqv`k-vG(csnx>1?ZKSxT`}6I;M!r9s6Jk$` zAX%kYZXd;ZDeNiLAf~jFfM5-l+?&C-{guZnjEjakd=U=z6t|6bN6bUqwtw#QnW&~4{eV@QL>s)T)Q3hX9QlnKEB>^%R6&Ry=b z_`W=drLMhQ8&F`y7d(_MKt2-$eXAWKmTD)DQA%Cy`VmpX`!`@bbweqv=*++M%q7V> zjk$^HJfTmy#(Io@lS-MI~88Ag$SUWkH|2b`BMI9NUP*g=_kAYy(<7=8;yrpVJ0E>sd5Ajh0$m_0! zK_S}g?ysmt9n zxo2)rpu2JO%tVFIMNLW&i{Q3`{_8Q&(N^P?05s&l3G3R#m@BacIO!nyR4e?tmlq)Ic@@w}#B^PwC zYEhY>wMA}gN@x|8e>4&~9*&PoP_Ns)!%D>6UIS~Mn8;l-#tA}%%fJFu^PQwKnLyc* z$n6167CTvfeuNJIW?1r~#XKwrUp9bN3HGNcJGnlD@1cj4AF<*S&#A_pOXc(Tb~_+U zjeVpnyH*PgyuEMiLY2CRa@55BsiN?i1PXKk`hLH$WC`uWbpX{C*G?r39fiwcY}n(^ zn_Yy+?|(pL?8rb#Bys7#%vV(CJaIU$%qjmq#Gw%M0 zO5)7l*Bkko7b{ZZc()O>oiEFg6B7K~ydc1lt_LB-;FQhpwV4UvQ%C_83YK?)9hMNu z3P$8wzzUI9=_Ecn_e!9oh8>7Er=mTg&7_FR`bZ>1VMZ7T5dt88IgpY zM6h^BxzhG-jPg=C@;!hWfkdBABA~KBlAM0-n`^-_1XkRXVWhsxK~)Us$=v}ZM8vxX zQq^)x2tcZY}g6NB7IQGJD97wM$kY^a3rN$60px(1f$aPKS!F8kZUdru0vwb!ak z33rg0YcFk7h7jk!7&=p0G)59|IP1u{d9n-x5o81+#OoAo#83=s9NDbnA+~~fIT7re zyfHi=5qVos1c6MJ@Qp1NRqq}i<=4Q-yHT}BNI`gtq!P-~u_ZdJxT7AGC{l&$T~ogB z6=XlTHXcCjSIHF+?jT}FYzc(heZY6USGkCU?Aqz;Co1`!7a63*0xagO+W?l6UGA_+_bkAb@l=Jy8qRY^$Re%HmjWo7hVX551I?Srni-UA=Mpx z+CxOaIlmY3DCztIQ_vQ{0e_-pdv$8Kip%|kD|H*HV1+92csNa4s>Dp806avPR)Uls zbzYV{Mi-*`R7Np#W#q#2B?QZ~1;?2XHWJp(V!b^L=+AqV4tC3W&eXL@-D`Uf2x4>fmIG$=IO}&rd2z77L8qQ=BLeESUtu_4lrA&1M$b=_ zoc!PfYhd*iuXv~DO<4k`Ct*}OcrmwBWYxsFI~BjjIoT{^{!_usagsY4K|g`y%)LH= zB>DJENMN(TR&-cuQ;Q)}BN5LK5>ip^eEx*Lyb6mJxjdLK=%wjXW;6ef~>-#L>WOOq~u!X?@$4yA}nK!)3vf#9)okx%!O zY7KXC!4j@q*$N7j21`0%cePmK^Y*Ne{dry3%*G2PKT zS#%0KC=}|HtoaPSA+Tnr`>WQPnB6&qMB}7Rgau4`mX*>p=V5tR!^bZhP%(P6oO`ud z5vh~IyTsapsz#DIRx^0lfpPwPM!&awF3Vq|Jit&qlAuX7JCNPVQp z?zz?ET`-on2X~3mwCbiARaw-7mO!@jn3iZQhoc)CP@$v*$8nT%rAc$eyHETQgQyW= z&ZuLUkd5WB#&w`huhS0=--{-JPGx3G^Uh#|{^P|Y=0;Q4zK_+^Jmc)>#fcqvXrfB76EVcV$cIS@ zI-KfRyMS?_mVFPB__ZcQ=hiSJsQd0w zo2*szPc1kuIetB}M~?bS;G%8A=~$amQ!1y0vN)eVGE^iJCV*t@k7lCWOp(?21JWh0 zzCWw6bX~>5BS$f>s6n#+OG54$I_}gx|FIn_3~)HZ`QQ<1$1wdr+`R=CZGS^)zjHwXwycc&W!C8V~b(jg!n64DJycZVP#jYxghjm|vG^Ss~sW4-VC zgEec`4D7h$y3gy3BZ96*y&mDlQXjZwu5tU}!>syTe{-22Tr6=QKi!LkA9NG&t>VHl zeh{uki!2=fRUlRX1ozm+O?tWX2X;YW8v3r8xqjGErj@=}jxFS7O_nQeTTN0;tV_)FXBQtj7QdH#+*H_t^nKMAwz8`#PjmqJ zXeIvt*6;oj)BGQUKmEVGQMVup!B}m8Q!oMmPE8J+(ORXg4Dukn5u|4e2c((N6X0fk z5uN~?;UNItIkyIYZb%?LdK;)*$f3*(0)oWkj{=@{Waw@s)Z07P0)r6MkT8tM#Zr{z zoFYVldHB0C7Y%a1Kp>oO&O(AvDDb%^AXK=}PE^JasuC}d$64doZZPLbA@E$wDLJTw z`kx7=g5+NYEn8218?>Bzk3+END>nh~Q%XQJqLvBi@WM?$Fo^FT+37#KX=Z@R#YgEl zpgs#4Vn8vtk`IJbsC_1W@eBWIpGg-3EY2EFG!n>-ohM5Wzvajtm{(?CLRt?HVTfnH z9g<7~Nm=zKpg=r#eutbULm3-ysbfj7LgFE@C&!nZKjGFF7FPj#BamVpD^t;Ckpi3X^7CQjg zPlyHpd<~cPGf~_C>wBF$7*npp2z|xQymJn7iV;HAQErmlc)`l4!b~@G#~Ftyhz26h zU8M}d_A6IR*Wy^Q&k0OSLL$uld%_RZ1kuK?P;bTDZ=nGe+*mb))2&w>w~@ z#Fh}`Kyu+K$%D2TqA`lFnk-oJj)*_&jUYm(8}H-|+>rH&U6dEZm@W}Sf+{qh^BsFD zz^8FBfX;|S$Q>MN3Kt7qhp%$$+fBw9%)k!WM3&_}2UJhKLVdGuOQl%ibDw}UU-9kL zWk%=ce$a7w!pb@pV~qwt9>b`hEOx!xlx@=NT&L)7&gp9wBw@)lsdq6Ctb$=*m}&e% z-dMXr2a~MbjZyy|B#uo9jNvvM{hGn-HJ4BiL0u^rOuUjHr|vs{2TVz7*nvz7D~@Cn zUcF2zOV+)zqD>j`ndmneQ}_LhLxvwtB&}Zi8uadCb5*B07$>yq&c+eGvs=CvVR;dH z{S?#|mo@L$70OunzDseDPg}I#+E&<74x*7>3kTK#pe-c~m?QHRJk7>LG*DfHM0mPL zLeMR!WANJF<2K9fCd20ueK1EX?w5c_j3o^KEkVQ4hO5L$+@MSTR|D&+lFu2d{ntjc z_rYS?JqMt)51YHkV}&L4oRvnOCv7n)-8kDn!A3p*QAgvRzI`|U)&y`Jz`P)q`0JoKWpmSn0E2(*tL8F=DO0eXs_saPm8H_?vzx z^gq!U1NjU~Cn!{iS!AqzR45;XSB9@@NgJ2dSWmiAkVLsOi;FzZdmgOLp~w^Bv%0f{v9r$AygjTm|dG zCi(vaJ^0^`;ftnUdtbV;oNU_53+=q!D8o1IG}nkCS}p*h|Ko5K2fnF+y;C-h;9tGG z{{t7m3uhlrBDDG%$nz-dTowuxiN4@NYHt1+-8%2&LcWabb1XU4{hTBWllG zUfS15R-XOaA6HhKmq6b00_vYVhs0jKa`;a|4Yj{O*PpzBLNpviVtlA6=HzYQSH&{b z2#NkfyZ7vC!Kt>4A8Nprd=%QdL4T@xiT~Nqll~wF%nKn1vO)v~d0s%$B^B#m4KUQM z_DJS(fBS{d6>Oj|yAD}3AP#qy%??O`-+aIk?D@#YwOV;Z6*LEhkjK@5P%!|t=%65^ z_0dpjAGwhN=pU?_83DQZRcv0|c1Ln-|8}i1;+&UA4Lo?Dz8?@|mQfcQt*|u~(Bo&U zPy1S}SdkAIo&x7PZs1eWcg@ZCqXB`P;}*1!0y3BV+tF}@5mZMSy;LF#O@1t^e1*!Rak9R6>`P00KaxRtz&x2j@Qs|N~r zj{8U@2PPz#Ju;u01A@t@MY$)iE!#@SOt4cL9|#1~#6XZW-O6D0YJrGD5L&!HW4@2} z7ZB-usVR5v#&8OHSFie6HC%&jh2Evsdx2P*(g`8(r&s#RcysOIQIa|mXDy)DmD#aO#{SNg}d1Md^8?BqPi zZO}GLycR0)>zjZtclvv3q`ZvRL?qN!tp*((%ht=9UqCX||L`Dfo;qf}INU&eS7B}( z46^4O*FkEumGs3)*jh=3D%_fWP_b&tI8>O4`VM)eS*h1>+C}m*^jtvq8VtlLz__## z;QVr^yMUiKOu@v)1+;m}ZmiXTOL5*(n?p$^QiU+{LNF7Xb{`=;wGdSE9(zDRXb}VX z26<)()a0_=?6k#IBiFLWMRh&p{rTe?>Dgm+k`6U;vgafW=u)$Q4G@-cX;@hzR?kU0 z;0ypkh|r1hlZ)Pv(qj*|?frmu3vk=aMGefLp=B1KHDfetkI?)p7FioL08YtY2f;ct zMNu8uuAYz6M7n{q%snO9M<+(Bl4dW(e-PpB>v9WVE?q2dODqbp4#-$MVx3OWdea91 z$+xPA7Dw((Tr=uP011TUfjCvK)4n}H_IRY42OZg~?|b^N%GLDg0yGyTYHH zZuHo=^Q~b7n3OiRp%&@5Ev^;04U;vN#1AlEUBBGSI|2!B0MoR~1H4G_&CjUwK78pi z6Ywuxv|^UZ`Y6Y$<810c>(Z>l=Rift|6b${v0}3CuCDRdal|~?6B;n$QvU|m;U89* zq~(qB2MFv|jb#rtKWy_5zdJXxLbg3+*Vx?h(j35weD+Di$Kr=E`51;}8Vgps$igo| zGD78G$2Wa8)*UDaqML-~PrrNgMB`*Vl8rPv2{!}YQtLZM! z#}Gjp)ptvxjr1={$wF}pcmY8Sbs%?GJz2034TfM=(Ue}z%y|BmUhnVvyI^GCHedp) zIn38KU{-C4Ie;s0-hJc7z$iAcjxMPYYg^|65=+SQif(^xRJ#DL1GU)_YU(k+Vr(l1 zZXQb%tTKgaBr9Hw@S9*D?GXKrD>!$7mhYnl?wpKz7p>mmV~fhLXT$lglc;q`G#|9l z*diQO$oA<21_m}v@*Sybqv0&U zZQrD0XC zY~4zSd$p#05Bg*5*6AN{M;!qvuV8weU{8(Ec=`+Dr++>D4SbZ<*gvDi1z~xzX8vE% z=CB$r^RNYtt0$y{ivfR#K;9_UmqgJRZG-rB_EDH!CU&UvXqqBHs`c+`DFf4V)tXT9 za6xv^rmZ9xb;}e z-rS`0yN9c>``T9VY4z@D)#8H${iYg~cKV|C_K#VIZY8sqrt5xc8&vk=rH`6f(Fh&> zk282!A5hQkUv1#n@?}b4Sx;=1oE9nB|EV96AOo+j(!0gJSFhESZ}bG!+y%s&S+um0_6k) zF=vsov1e&wL0H4O_NrZh$0PE`Zy2?Jur+HdjE;8op!T4q;)5-Zp7ySf#RkJ1I{WFD zQ!RdkJ<*qF+9J@5JTt#j8SOU`_R~k9{)ARi%uCDl8^{YRNu)$T>%Dwi?GZYOQS&|d z)4o%pJJ77drjxV0>CE>mm#8PL^xv{G&2G_Ks9Kk`u6v{ZV8dl2*IhDt7zM%wA^EFJ z!-8fHp9)&s9&#JIW2lwXe;w82I_6io4u9S4JD;K1nsGt|1USkyCdTdSG{MAZ#0~C5 zHEyDgDZFXWN92x5^o|9ehxU#vy(xMUKS<0SB|!F6Mw@vo4yg3wc_kX1{PbvruVBk4 zF&6S83iMh)4c>?pdhjh7k=8Iqw*+!8Mw&@kjskXhinrT0HJ$UOA}+!{vy-v zxIr%Ni`+jb&~zX7aA>fbsLQ2kU#OS=q_26vv}5<$g>pdHH+6~yslW~<I3SA3I-QQ9se!)GN?!-{^Jk;os{O^GTQ$#t*^fI3Xw`hE-P z0xQt-M+%P)`9Z%%pRyBJ=0=7`l)JczQ zfkO!2^12gCu*ESKoeRnT0!|5Q6t3aUI~V9v)!EwpaSg5Siv{# zO`^)g0UxO|dZKs?5i*L8KHbP*hD24MuJ!22pr6)@z+R9TQilSDl~!-vufc-3Wu;;L zm$kIWFHF_|m>XB12ky&XYo0QgFd9akgkZD#Nh%YCp^5<0J7`6GphJsh`A6<=YBIs$c>bx5{780)Y>^0x}He-`L>$NB(+%`>2S{Q{Cl z38n!G;ATGo%&^!zWTrjBuL)|40Xa0``1~m#t?g&l4wc9=zFOxb&3TY&yykggcl1db zd`plWL|)s4X#=KKH3kH|B3k+D&et#@2^oM~^;D4NBdryTS${He2*5MgiFO7lvMify z0~zjz{E22d;Dp*=qAGr#Av5x!-3>plv_Yku>eR{&W>9XUusjTKqpw3I5L~Ke4i8}O zH;}GFO8090*%;UA#fr3<)`ftk*?C~^qe)G5pI`LCWE)0qEMNwnoiK`*p; z%8{KoVMGeU9?P*mg%EbD+!qvfjC}W#W`KyE=$Nm$dM1ki8ukjvrSSnZ zbav!%jM|ciFi*;@3a0!#iuyDSR}{FP2VwKiYLG6wswM~(a;l0@7Xm*$6U%YPUFq8j zFA(`Evm6}ogK*?R{DC;P;MddQ{2b`=sgG@>@K*h}GO#@WnBnuS0)!cO z75Wwnp`=zzDTS@i$TdY6JUm&sp9-4JaJJROK!I_$$ohx!e8fWKQv9=5rQwS+{Xl^mB7wpnB5PuZVBZ^^E z^Hb#95-+=kF|R^nwAuTnOfKj-Ra9DB-hzO{<`*6mf;18>RG4vz$#^kllnz=DB_f z5Mld$MG=H5$fB06XjnAt-wNu!`Xt)}Q$ zAxoG)3CGyNy5hnT)vxHjIrEt$t$2hH+VVBL|GIJVu-RBIF;ol!YRVe?O@v{vk}y?6 zhqc#EJWJLqN?~4Tn(T4B)e82v{h3J~D0E4H$zlkki)G% zAqncogP%!YLHawbI^Sj$1XKUY0MGy22k0n&(rIW9|DSrhwjMOIIRA;L4FEusKRlc8>dNfyfuJT{+lI_G{dTg0-z9zuC^MJ(K!^l4;9i+exV#(l> zKj%!}2PItmZ+}bl1BubgfRU*BfA+0>C5GFvb;mcwKw}nIi*e(EqyYzzl6x}%jSn~H>Rj)aWmG;<;5Bp0K2(hewv1he#FS5~Bh(S1nfiFAJ&=wJcUivS=| zB7A%{F1kZ29(=U1oP0lBcQL0rTS>z-|MdAWRbeI4k1O`08O zuX{;8m>!#aoAfqmBWd)|GxHO~f%fu>2BVV>)ntj9H$^+rlkKnwM#VS3|Ecm1@}vQ# z2N`sN0%FXR2> z*FzVuWW88=0Ov(ZTZ3vz7XJdc{QGK@u(O;}gpxBgtv9u1TS_}xGzQE}NMHwG;88@W z3_o5Zhqf4}R!VyntGIBWGg~!%c6zXpl^VJ&PhfSe1)YgN9&;(kSG(_%v$b&1z_g!#way+CHM&b)eBJqLygbm2e6f>UXZFdnO zP~j|B`BlKqwbo6%q>DW(wBWrtQ?FWc2d0vhW|I}R_mo`1qvGs_J!+)?4~4)H2^O4C z(tRP6AxIf>1K4YAG2!2Heh+^$7DLSncz)rcK%eq>f=9dU!rBojE~-V4;P=wWmlZ6h z?fZ(9!uzIjV&Q(Hz-O0G@^}fPbvYc9*w-9EUG_@}6*m&h#j@LvVOmp}cWI_SHMt@0 zz17TAvy6!GG<|zxm#d!eeJl3)*OqcFQ&`1HU$`{`+Sdpg=`zX+W(i3$Ym*wc2Wp=n zpWLQ1wtJH3jJ1RzkBPW*WuJ)RdYW=N9v%tsv4||tLaf4Cv9Gm@u@YwD%~r$QVV<;( z9!s2xtP@->F0RR2Z2Y*))NY!LuN4uB7`xvL$?zhJ9`}ZGC@6j@y$j5ZL3q!W=SwTGxZ^RTKT`8fE`HWQ>Zd zui^kQzh5lN)u8cZU6MVJVLC*Lstsr3k*N8#D`0Q%a7%zJ@=4VYTQAHPBm+m-I@Xno zF;DJ>5^leIAHg5k4mf-LyNhx32yF9t?xA}_Wv3um?UB@)cEjz!*i~>({{4n@V}Ru$ zo7(YS68%4JRO+`&HlSa6^p#!!mpK}rh~}0UX7Q7ekMQ!(2ZKkpc7RYvoJ|jOH zx_}8;webtkqZGE*2a*z#nVm;U_{+D;X;OpW(u>dD%FDdE>B zHxz6`_pRa7((5Wy?#%)ua{^8NV`^TNzaOo%9=5qDfRui4av7gK)C=TK#{$`ViDR&O zmv4ZT8VUD13MFJqxb(8Jd2i8V|h6 zqe5mObC+m|8*Z>>59)ibL@5GdreX-s>_O4TyY+m+J^*@(XbX_s3tzY0K>fI=_Vdcc z1KM~8Lf04NIlz)V5U2a5cP?}PHouh30vVKe@$yyqgKN~lnB9fV>vilht%^vZ$act! z#*G|{xcD?;f^d;mbF(qc=?PNd?>j#!#j7H#`p=Jhf((lL$AgU74kP0K$9lnk1E;t6 z$NHyYY?K`cxVUOX6%a48u*sSJ{w@vYa9k2~l7F70mF0z_dBd1~pR_SRAM@|`fd9~w zbL3G8Ae6?UJO5V|G4F-{qkn?@^Ly||*)|x_UoQ&?0;llzyNJNi|NT08aNvJ`oGduz z-yaNK9E3&A^!Eo468+S~Kfe}A>C zS(+v}(|DPsJurU>{R9{?y1hx_w_dnz1E-&g#m?AAWzQu+8|k}hoZBkUnaW+$!zyIo z0SF&~x3oaoG(*rWcLj(h9gK?s7VBve^Y0V?mf%3q2uWx$7y zJiv15(F6I&21G#M_i29$q5-h7`8VJNBqNWC3+Lk(rl!jV>M0M`*Oc(1_$ zY)<>;W2m=OU{8UVwXXB&;c~gsb9X@eKJ)}DEall}&n>{yu>*p;If}p`b$h%PjM1aT z9{^z-PAkwUQ$3Jy0HLW8j9ojyCTSLZf0Fdi4NIBgn}EG{hU&n_yBw9EPZi(w26(8s zMFR)fMOAY!Azg6KD#5H4&v5Pp%-`9a_AMQTDVAiQ&L>d^1X=ReYSsbEs{J(?PeXTt zaB-1r&;|;|Dq!B=yqx7-uLsHE5*~?L@BmxcVv@$yTPnb6PyQfN@}wO{lRR<;coA)i zKdQR*XUWLcm{-6X&n~}`zbTYEvG2Wo&L`=Fc6Qp z!KC8%lnI;Q1j#7ifbKsFweQx%w}FQe_xXfccaEfP77V+|1zF`Jr=3)LOAO-WWyJrOAs2^;qtDx-`8P{Bfl#pxZRryvg zFWl7m>Bc{R%4q| z6NfqidFI19a*Rmks`1DeOESBr!$FeEjQdn8g&5 zwLp;WB-s0!c~{QtMUpAm3zgFZUM0c_#0gaajH(%@=1OsODPtQ~x>zctl{hF$x zp-Rv&0L*5TO1=Pj3ktqjKJz=0L z%S^R=29R}!?nb&x=K&|h{fkXw6Lm+#TY9lJVilx$1FEZq3%>Ub%*y=ds;s*d;TEW$ ze(KXNgwP2%WSdd@MQPpXCGJZC{${5?U^7{m36e4h7MU*k%NXpb&<>61eVGBltzPEQ zvkOo$P7qMIxQLOAmI`EixZ;i+oQukv^s;6FQ)VE;RgSy)6l7plAW}sS>}B2}V?xH& z9Zmj-Lo6U|eNgK6DC2OE706DNqVCNGpqh7N$s@LQx(k}oM~5*moC;FpmeB#qr*d2> zk%4J%!ow=SCz}Ly*har05*D=u+Mx#rG~1s~d9=UbHJ%L2OgR8Jj9Vl|g`jQN9Az7~ z>t~=nJael@JMH`$Z5tbyGtf{*8sEabC6I6)%w!MV&myof&=8meTXbmB`%Y1NWCUnr zvzrNdI_1CS$A1CxU{+Cv=gj+GAUD{u&#)1ru4oOV8gJl$lYdw6w*u)(Rs2l^I`(Wh z<#zjx2UD*QEm(wnP1dg17+Ug#q|)5veo<~cmGrVTa0x<{#u4y76npnRg+??IzeDA3 z>7;7EEDq2%P~P*@*IXho0Xp5?G4^*q1HIvd6XSb<@;G&=AKXK_Q;llA!Bi?Tn|5+O zCOLSpw$13vdRdZtN78h(%~b3HKdttv*cOB$=RrNt7#pFvm899yqx^eEl08TRCmH!J zZkEWKqIhf*;2LmobpqADP7#(6+8D+eF2NR<1XQ$4Gp<VdOOF#{qc7w1 z0=GHE#lQJbGm(uTsb=p{wN;gCO|8{76ndR}Hz*gno}o}7o`E5*R*@OU+PIlAa1wMx z*jP}6z-~FneZ1lSyuaMq;7pR4Q6T%zO-cdBPmsMo(`zPe47-8F(Zz=yxV#AiHXGh` z3EWE#_YHex`1MAFxvW`@8v}0pIzoEo{W{b8^d`uW@kyJv5mzq#6u(9YcJfbG&|1l& zO=E1Oueh=6`KR)< zvO7*RbX2Z0W>`lpl<=qch_)h=P7eb79`qs=I+CM>V~wWsqd#7-jtNZLi2eNl9)Sli zpm1d$rZQ}Y7;Soj*9$+c@qCQLoDZcG;RV6`yr!#p0dM%}GQ{)N$UX8(s7r`4;Tzs} zYuy$?9xn}j%ByT=qRVOML`X{XmL?3z@a@eu(eoHfK~wguuo&)+=-hizuNmvRBJtqBUtm~U zx%$WRJ0%zX+LtHA!uYmI?X`IMTSrfpo#xtLNy;8pJZ;YD2-rhR!i=unO zywvd-<_abt?Cv>gI(Q`UltWC9x-a+BqZw1AqVF_raC!_f^@ewV?ffQ;83?KV=wELPf+EX`Zj3A{1TRgk#hls`s)OF7z8zF zQPF0$ZNAF%Ihri$Cbi40HD$iJ%$yWBJqjpD}1tfYIP?Ustqp*oq!3m)ma z;e`9Gc5Y=_)?^!I3p@p+@aM?eUyo?dbdXu`iyxLJc+`cgRgC}SB9oC|fBlSlOPsRn z5*&$#f=*B_)@GEmSr#rB35wt?l0)ssh?S8iFQ^pFcvO5Y;WnZ&yrffW0TADlg_kvM zd)tTb3dk$OQyW2u3v=a?A~09zJay^6QD=EwdM%(J*QOipHNb`-Y!;{4&I$yz$x9-` zVc~jHj&)DA9MaSK^wA}JSr}o6)sywXM5x~k|LQA zvzttOr?^krco6G;py9tHMl6U%&VjHPrt*jQ)IZC;RaSk5>S zGB~ckG8FPW-|lA_i?Y(l8IusYpd%Jc|C0)-<4&0!F3`e|KpV-wc?fQD3Zj_IOlGyDt`CtGqd3@FJ_kzl&u? zMUB{q3#Fdon>2+BRULR8{lz98qhc^94ljHn>zn^eZyta(J{jL$v|4W>ov6+&u;~x| zRT#hh!@WY1$~HXSebL0KJHTuL$b-Hazi?WNrR5YxNRQK@c&n+Kq*cO_KYevdmI)?0 zsEOP;IlJk^P{HN2^+{vZI&dBfM zGM45)M2GSn2_`(tKUI2rAAs?em-d|jxm4Lijq(9oiyGGG(5jQeUhk>2p8FCdf@6t` zuYaXd&pVV5ja{*1(q}GB9<#g4nu9N>BA{{>dGrmLT-oftKK>-C$>{J+-!JVur%ie8 zsU(y4a>$w9YfY2mkyxpvhfJy>!}X_=EJ{Wh8f7~)7z%K}P1OT;)k)k@HvBX&klOC# z*S_No*CC}3f+p$nKgKZ$oO&e>pA;{?cj9k+GT2IUWSOawFjDeisLCb(s`unWw%BTW zE)A#kJj-W86|?0NbIm`p`LZ5Y^;oe)6!bhrei^C|m~x+gz3?mlL&`x?S(Xf5%Z9Grp2)42{X7whK9<&F zf#mBe0S~U@Lq~`4k}|DzYLmkvN6?1tSuc&XKbZPHu{tPv@Q6=Oz4-_ynk|*oz+oeP z+F?Uy+Ky{4Jkn8eiHx$dZ`9VhuI6z6eQ*rb5!Ud@qJfBW6H(9B?ZZ(s&I5Ku4Z3#N z=-$AT)VE)9Art9!hp!2AHNLC5t^}9l>UG0hw^lMIUF%Lu2}~`u^BmO|5=0yM+jUN- z%#udCD3!7wi;y$rX^MAR_7|C0b+tuo3}~utiCehsudQHAx}@p|n5h*z=qUHbmTVQf z9qh042%R__v;w!#RaKM6x4dfw+W?y32{1%Gn6eGjDYt=xS3mq<6DG0g^Bs&m4jq=0 z>_g-EysF2OcDf$!PW3-@%z_tr^>tcpgms83z~pMl9CF8nwo%GgePlXK+fM_lUOP`O z3rz6$ovBsb^>Xpi5ruo$c~{P%hrBbcp4n1jtBofv(BwX+k~9+mV!{U}5`SJpnhG`1JEUoKvAoAU4= zF3FVB&QLs^Fm89@qTV2k&hVzqO&`@f!3WCBjcJZKk1D_RVCZ_+e9AYdV@eH6K0X;& z=C;fc9NR@kFq|BE9Z$JW4Ipn>#tEv*hmy^9U+wcOGxRO^A&S6vGypkP`O&UF!Gs*C z?hHn3l4iH=EVH-4;iu`!YdcGaC$@D$KqPGPXDf}h6W$9pw;$%YA_FjOp{MV3CXDMc zk{E9wrWc)_Pka-Qyj7nkvCC4vvL#tX6)*5fmEg7Is!35vlo$N$wEbi;Ckw8TBi4Ef zE<&d@9l4eL;Dg1*m=@|U>#8>icEv^lk6y~Xi-^UK-B>H`v=%>`<4zFWR#=|$`eY)) z)n;&#lMrfrb}}71O+8F8Vp229|KccBeeM{@I2>v%gx&r&=^X!~_~8Sb1{V8{BoW%X zXFtPw@MtzBg0FS=t2@Q&J@iUVj17GkG4pya?I^d7E!OxME=g{$Vr0iriQBuWxp<~U zSyy!{${z!ooiY*)eBVlkJH{jN6YZ2b9pqN&*|A=u%0FvOkZhGW-rSZDjuqW_N`Bi8 z_nAB80cqXSw~`$RMdiGw8_tRDGrqewj>9C_k}(^{a`a+d=c;mTjgz7q_qU zKgUx`rieNyDvRpyX>4W=n^rH!Dr30NQifw`Ib%09Wzx3RiZyk^EXn}5&I>R-H z`RNmb)Q#%?6ELrI=sle!*qCgOoLtFFT;c+D2By}M!hvv5_Y0;1>}kTMUmffxGF5p6 z59~AV9vm4O1YsV19QH9+Tsfm$yiE}*4&-7Ur!f%D9J4+ery2j4mtMGYQ)_9Y?ni%X zERVImur-dn%HV33A8V*++3tjzNT@Pl z<&%_Q^L^BFf*bFVcV|obZnai_8?98((~7(AN-J9axFd9WG}Ke)M!L8yUgp$HWT<`f zW_#|V`@5Xp5e~NE%_&s2)-%-g!Wv#sBH3hKnemMre&BmLtlK~5R`RUXO|$7BNlOlw zWDLKxh&M^dN;kwuvii{ozw)Qh{s*59zJxZ4ghjKpR#%m7FDFrPE&tf8&ddCAV;6?s zS95y219n+83yTBFWL~TvcfPIk)g%=0+PCM&j(Y#n)THR}qh_|{=G6S^eph_pJ)-@C z27~TPZKJU>LhG2dk?r*HGKaV0g|5Zp+aSIT`Udi+)15rO+}?C*Cr5jK-Is!B;x)CN z*O3AP0L$2IKC-B27Ys*37yGhfNK=3l9UJNmCY|3WZpKFWySd*0B%p3p5-&5*C1}KZ zEqwj-S3w9mFY7hz0G7x}C;N@;%#PMHo@8hJN?nZ%HT6ZR_;=sG$Rx7sd7L_nJ_;qT z!=vWQn#fCvCtpz_O(Z}x(uTNkPttmRe2&7q2$H{6<3uyWI04`Et{I(i>R7mdUHj3-Y0^0Htrq%Q*SaJ zXpmqR&vvq7H5Rk8s49kWeHdd!-{rmQY1__XZ0tcZ-oWasod%AN4ov$mv8ARmRi9PX zW(jd`BZOt%+D29{C&et^E8)5q@%^$kxg9kC`HA4=#Pke3`gA9KTW+fEKzv#0Z0*=} z@J)VJa13UH3m9p5B#xd$CTEvuTMj;H?S32<9HTdJs!HSaZNj;BUUvm0ZPZTjjfYK_ z|LzxG)DwRWf)61|!(B3|^8Dz@*Ka4ewvc;Sy}(QV9v(P49eqj@K#&iws!czeN5euh zMSH38#jKu5>gso4rn*SPCFJK9v@s`deLw3c`n}Dh_8d6tY2+oC6T3(9v#4$`*<%jx zsvo?{CAC%gY`N{uGZm6DxDNFu4>2LZfrB_fzo*78NwSQ2OE$nAH+ssb-hze_MZVZ6 zJPmBoHs*j})|7(rva(M@C82^k7aBvg?a8-9=eYHP$BEj6vQ?NrKJ{W!;3zG&OlQvw zu7>)A_=xD!1b@zM3kVtP8|7)FmAqb0S5ImpU1LvetW5C9)#pKBJ!Q-S;f)W0iZ-?-KILFFTUPM4+z@a62{~ z_Hc+BHw|-o8)JBsT14NK2}8$?`B3zvZlU*;|GnppWhHkyqE2j2!o$7@G0-6Gy6!gC zG;FBrj>Gk?)*QU6whM`VRIY5+yDyJ*_})XidP4^F2~yDNXf5sPSs*D@tp zt-=A+Lfff$LH^+G*?@=W*k#L>-C?(>}mSy)saIxeRwa)crv=Z-1jcO?2ox(QiKRK zHZo?_uhdLY&Joz8x#{f0yPB;f*j=nT@-_D);qSBtV1@h5ynbSS(r#=Y^DL7Gr?Amh zCO_ZRF{RIXa>MV3iyla6?=}W}=3f*3EHNtBS~fExE0KL>A+GWP4`FJqB-g))eu~y& z%Z;X^rl&QdBK~y9`akjf=JRRx3tT=YFC8bok3r}T-ncCya-r>4+Jno%O zu{OPCk|huJLx`TVSm#g~5gXG-l5SgIsAPdc!VM}UM$Hn3s{`A^@L35ON2^EUZ;A?7 zZi}lur1}DWn{Z3XSI5Y^lAeX>^XupXTB{DXFY;)FVqci8!n>oQLzNb#B(IeOG7(7e zWT<9u@hKal$d%q^QXVX8MR}s2GSJ+CDPNsfa6N5-_4~*KnUY|@!WR^3>Kyb;7J)Wc zjn{th?w6c0GA7rq_O)AK{DPS%_3I~K)xW_rv~ z>JiVhPw(L&EpBfocV*fOVX}B)ryp3aLmo#xVp<3}j_7sK z%Xu|lRY*;l?L-paBewwz&+T#_Ag>pwAZJu{^KrbkouB4tlfz+s>=+Ou*w~h&$#00y5M%-sl0lK5wl;4 z)5OHgLdJ!D!OJb`{5`8o+-bhW;MVe2*6D7|=q~soF$^pWRd-C08U$lmPhrUDp38_$ zt@j+g+P*K)ujb*c?dmC75iy|{WflbJe+(Vt0sPdv`6}m>Y6BacFgsuvS z%pD!h;!#%u=6SP9xi~!aPlhz*zSDP+TGPYskyAJ=C*~&E?EIrfP#q@I&xzU;;M+Uf6#_HD31>~b|azPp!}{=DbghMoC5{(97U5N-(>sLnAGv>j_1CM;cSBWAzdJt21tBGYyDE^ki{&|UX&QSD{bGG-$H&Z( zSG?&jx6l67=4tcP?DrqW8%#lF`spe5!0Ij(TlbpjhExEmAnle(tZe& z6Mi5nAM+ebs+8`!T)#pM)?L|cIm;#q;jiSPzJ=8 zR%(Kli|gM;;iaLvA47ACu@p4Js5-zBh+DqgJZvDg#;rU+L=vTe0WXNI<~2+HvwKhu zzur>`W>%I1ck7<^0kx)nEFGudrm`=1K!KtK1LPz59U_OykPT6~{5NR)@8VQw+H6g$1*G zFOzOY(+RWh3%7BuILo+(MuOtvK@*IQY^GjfO-&8I|4SY><7#ugs=udq#$?V$*6pb?$bxS9MmqYlq|Yh{x-!CF2#a@NC*7f zfGgvLiv?qjzB-+-klF`JxpZ|%ZMjckb3wz;@FRczD&aMx@*aLnI+%|`vKS#K_%i!( zRf=OomFd&gU25!cxvvg#(aw2sA3PtwjbEdVjcaAf&(w07_^_AtbToYo+trxf7&o#^ z#gJ1`@7{HmZCVP6k1ZWndgcu4`?hE)GeYDDqpw_YF)Uw<5gaFNEec%U6cQWRq1Crk z3oB#8kK^zjTvGX1-GV`+H`;iqcR%*8r4oIOY^)m9)gDRsocQO18%FAUddH?B>G!=f zm*uN$ywJzcBhg91wX19lIC2MJ?>&jh5C$DQG8_dG7I`>sIk0SV3zx8Lh0*3==8jvu zZDysyU|wLb5ScI6|Ng_a)EXuUzd)){WUzfT&~Wyg%07ZwvUCJ|4}CWg^L2k^B|Ha5 zwzlD!04FzTvyg`SQmJ#T{^SW7ajN> zZ$GN?IU!ZdLFaWflJszFt9?#fu-qc;(`>sk`+1z81AQK0Nj&-a3OhFzgW*Z<*~F-Q zz`UKuwz}KTtwVaMaSZ?fi0ZeIis7QLHVxS8)_EdvP45@xLS0J3@clMP`P=T~OhJ3N zcV?dPBCluj1rZPgrvzGL8n?nqB<18QCGrCx7s=D$x$$t zi7{AXxY(cKJV@(dVGbq2l+u=}ie`1~h-2`v`X$Gt%Mlmq5k@ZDcTh{`v-m?um8~w@ zKD8Dri_8jcPfysil`-D;;;6_lJo%U^rY0KQb^gcwqmp^v<;%WLDP<8L^KmIwJLx;3 z?R>?q;iP+O;q`a_y`j)UjVq0e8Y`@k9|{&mj%5ZfAE&ISXfOJ=-D))ZNy#nGwp@Q` zBmN@t8~tVXj@L;&}LZ|K4VI$c))fXfbq%{Y$xTF%oDxQm;8x)I!dEN0wCSANezMlPF&xHsNGrCya z%ibUV!P{9nIcj-(TF^3c6} zMPj@|#IL85%bv?tCXcNn{CLb(`i04>3Pr8AhQY_1fs5q}(IGt{Agg!Zm!c-`k-kR} z%fp1~*jbBY4>;-P8taGA73hvohPf)P>6(+m4coh;s41t9O49i^>b3wcj8twc2Qtm~@hysB(>x=%oIzl2K#MAIgT zypzS!7ZxiYxYmT;H~cDeSE?pB-SS$0W};ad1EOlF5>>ahX#j~a8Qx1K}xzox~<1QmK z`#7vb88_x#jA@O~w==vnT!|NOp3$&r2%K$z=sXb;BUjnfm&a-H6(a4}`)n^9d=#x}K$B4`SbCmZ!#PQpdq|)AhwZ?`G+sIx9fl(jLah(^a zo{k)A&0v@tP_=zCeZGgAj8woX3v znZ7|I$<%i(0Lp<0r0maqm)G0q9@FT!DST?!RM3ebU=XL z+w_$SjUT_}xrD+6t|zHLzFf0Qkeb?}kY|#S8p?Eg()35m%-VEibUkFlUZOf#>2zj- z&)T+V*L1L?gf0PgQmKGAO8($&3DTt)KVte~GHYZIBoq z*?$pIv$`G&|E*#Ef33Uz7tvO!i8$Q4E4sRrT+enpzphbUaJdcES-&xT;@B(>TaS#c z?PDd(D6J!cR_cRtxR{J^+{Jm_~^UAf-Ed$2r z59Mj=inPBYrJhbF`9H6(^O$^;PEcbO{iTJ!bNR&0uEyQ3Tm`+yU%4EX&6^Mjc^ob_U-dJRxe{PXk#}(s;~;~H59Hw zEjPavdG7?;JaB2bn#YBmC(t6I>{=3XA3dM1H4N97Ids6IzCiV8+aMw#HO)~jE+G3B zg%d5tS4w9b8GpOweJ=HrcJ-QY)&8x1XstYq;Ju^9_vL)8%>rs)YfqNak zG~aFae~Xe;1A)WG%j$EEG>03fbw_&@BcJZAkQCfS)AKRKeK|+UMjvoQMo@bQ+x8gA zwh*T@embsWBJFY4;FDcK$%(IbThZ&| zqDKw2g76~2!3g9d#070Y4t(%`Yk z7{zrVeX*?`OxVCFf2TJ$ja$1sU+LrW+MUzT?TqKvUf_@t)!G}aA7gl0r$DdQTKfd! z(CcQob6N!ylaOA!wx|S@Oq<;Xr2zMMVEnOi@6d2#43~B;sTA$~zK0+gpt(e_m9@?G zit%L(esTKK-G%nbur|yW_u{+q$a~yW1}Q$=n1}>DW`zmzg+pKszwi7cHW@8LQHGJ3 zX*-;;dp;pKHg9l0vC%xuGzi{b>=0V@kvnTk%o$c10akw6!!q6{Zr`q_%WDa!l+@nZ zlaA4c%?^vQOiXhgND;=^X1B&Jc*Dqh>r8b0j zpMiuy@e{m~%f-zlrwmhUrh{pM=E-Dlq+zR#FFpy2OU{DCEuE#a+YPpqMv5D0{#WVQv|q|q z(%U~?0qYD~=bTGDYpkFU>b;8oG@s88^izSmW#+jF`bWfvG+gQE^e3k^v1N1aaPna9mQwL53SF}V(JlA= zxj7FzGQQ$xhH*?7f1 z_03Kz-W^_7%yJLKYTLZmR zx9@d_?jH(2sKAcm`GgQ(5jXDX(q}LJl_tFzyzl&$CcQO;9B*A+)uQr45H9rXfniT; zW^*pTeyZnWFcJMzqZIoO8f6F%)Ep#dZ`*PxIp?OVKIo0*sGUWTr<1^AT4hU~R3)!X zHhY>g4aw*hkTrX136AH)r|2vc(y_MK4^fYvH<7hUW>~+2F0Qy&sT+`bOLX&qO_M6o zt(X7g`CY^O#2@e3l_*LE!xaQNMui#it!qwsMk}J9^cg#!cCpx$8S527l`JRKltbMV zYBx5L-cGqKCxHZu35{#>)8f>du2K3?pUUP~(aTMq6E}OhC4(NXbEr#^ghxPR32<0W zE8f4s@%f#I-5Q9z9!NUTcs#gBShvPdH}qO3%R3^!XkM7fg3w4QyG$5<(+0^sE#DY5 zxLb#amF5DHe*V_!o=tBHDHj_PPR@g489PO=v>K0#UO6#88WiRE5>zG@YnBI<_%2)d zjIS(iit$>6@o)^D83438P#vaV#J@e7OigxbD73sUr*SPRV6LyM?Z$qGLZ|SDMu)%_ zNqh&jW}D@^d)`z zt!nwRqUuS5Soqy0yR5@pDF0s>9+aq|>N~b5r#NoQY?0Q>*U$ z1s@mQtOai`Y$Q9Gh#$0*-Et3U=JcUH+o%G0`aT)xrW-fO?}2)sU9*L#%T98!H^xeh zhlq9!*E$AT79u(2ay<&)eV{iCET6WrM46UiV$x34Ywj;(uyaADKFV7p1Zk}#Cm;xG z6BgHuyT+IfF9v$wTob;sASswN($qX*VV0d9q3Rr^{*LS<9bIX|7B7rCmFI`r>m!SV zG3TQk)^vo{lcsTSSSe&4imP~b+&MWQz(9@F*lAbZvZ%Hq({PWVlUK5cEW^?G>;=y8 z#U7oP?iX5Hc;q?7W?)r;FJC185xzxMYUYLIJRKjyDSPL8u~U%2p?p?m5`Y>^Mwi3$HolVcXX&Y*gZTBSJO)MCrVbQR=M8NLNdof6{L z_Ga*v0Vt~>FX$q-F@}FM%{+hRX`DiYDo{oVjm5baI=__ZfB-bF_{C}ZNYtA*U}5wB z$^^84+d67gh$nM=PB5u~SLPazY&#V|UN*0*lj6~3;VVielnYd`&go!OJf^*RS8xQ_ zqD^nTIF*`kvs5YJ6H^)%wS@fUGKEAlO6t(8@L7Vf($n1%Ii?2f{ zzQJ|nET#AJJ&-iI62*Rf2x~kZ@pPetWM>Q6$i@-#U~U4RRD_cik^Y!h z1jrX2bSQrd4<%6_*moF9ABN&N6b{AXP&`rPtAUtd?fpsLh4&Shg- z=mC9~3p1)N>d>vi15~8dVk^=ReCZVmq@wBQuGDsQP$_wh);{9U-QYyjCzarJw(zsQ z_p0ly^t}$=MRX-(XU_gEfH6)>X*(xO|LrBanwq{McSwg)=~|5Mw~dqhIU3xx@g~1m zZkwh&ZLf-Z>(E9~$}MT#Mr!%zU$PDsT%uH24wlzt-eaispzSa1QtgO6D zqvT%E#1nMT+R=>to0iSD-QkkY5}e{oGL%M5pPw%sk6(NZnB2kLceUPB*21+(tx zC|(7UhAKk1#U!EwL4oM}Z$-kZI3FGmw7Y&LF}6VvJ}1y`bjn+UHfqn*7?w%lnsnci z;NNr}p6_|=RISi4Wwad?t^aQGh^_oE?-igmS5&(VHY`Tk>+SOE>|Sd?%N)(3bLE!IB?`{F20Zh8Zi&P_k{4M1fKAG>%&1@&_uf~| z5_DGdv;Ae|PGugMwx}W3p^@J+e6oz)RUs<_lnadO3N*}>6T5U_*fDg_$3Y$>88SO; zS;QThg?-{MnR@C@hq&8&(K!Hg(11g_2X(Rc=~udAbl%6R>6|d>9?*3(m&Ux7(x=y&t7-4cU_$#2C`w9j_T+Y-20`EioJfvYvn@!CA9skx?jO;eomP#({v z8+!R36TwX+sXT6H+Rpd>+&Y;yXWZVXAO^;rC*~YY&C9E+EDl~qcVS#oAo2Rdt>x24 zZX^Wx3@TW5q*{H?){@Gkzr53(XO@C1r!zK>aa#XBNP_+C{BoDpkW;sy)y%)-neb8t zR)_G(8Kv#9=G`k@|1A0pHfj2u)Qr|KpR~fNKCC81;`iIq1!-jA;IxQ~EsOKr@yQ%I zC#aKW4e!Ud@CmB+C&>}WugiOT?sC_cwX{#4=F=W`Y+c8{B)5FMcg5gP@(8wM0P-DM zGM?6_jGb&w?`{GyaOg5x4J!uHo}m%GWK}dAp|md_PrU@`Wusm5>9`Hgfh{$96y~Zm z`R&PkqV%lw6}a=dD<>Fap6N*8_1=jN6;lYR~0>0?4HqMVf0rj+{*tF5(n5|k7` zO3jDY>qn@zIa$3P+bE|<|`eiFVf15z_R z?>^SS1G+PkD?e3uZ}VK;3MTukiy$-*ZX)~fo;Y2Kh2+}`pCkY5^L*J+FP37x*4biV5HWlWfjA&^# zR!N`XGS53qbt3!17n=h{@UoqCkh#SC!H+!dw3Vfy^YX69tE<3Av)_1~$Q{I1wLv8e zN1B`Lm3FUm2BGMHv+t+lc;`SeOUxCSu=mXr*9p)Y^(*)2g)W&5=m0VBY^4g$%WpSs z?0$&7Y{MechEfeO*Hipzc@ejAHYp0<;_x!A*8*OQR7-}D9-sp-o zQVFIAa;@OZf~05l8O3iiLk%Q*(|9E9pM?sf#65UKGpqP0%TOaGEF+iy>5|+AHRJjDf6)LJ;bLw#zuwX}O_rCXSPw7;T?$*EW^~WI&G@WRx9^L_foG*7 zc#LOuE%kT_M`J*#%P28?=0Lx;)UXcL^e`(b-^`7#P_Oge3M)TvuvF<3j#OuFU8h7J z?%{jlwuP#h_sJO)U77UD*ChkC=H2fr#iZQk9(bG1r8#L=H>6&1u>~V$wC3*wt+D{S z)>jQ0uDZ6u+Pq>9#D#K_=uxHeY2h2g_Y{AfqcRtz}_7AkoZAVeGtB}{;gHSaZwzb{)@U=KE_ts*~D(8X^ zwFOl3r4b<9MBV?^SjO3KWq+Eq%cdiXNmg=dwMY2yMli7{19M;(Ww>{hv0nGp#uIaj zHFIQ$`a8U!wwl|{`6U66kFzFENP}!Vi)*GjADr~Q07DaPC30orzVX9xkjEK+_6RG> z!9NN+eG2y(O%dj86bYXuyqd*wQ;2=~3X3VfD_91xM_t$9}|rNy%G^ZEApAg{uPmuGk&5Qh}KtvnggFx_SPD4XU7mGa#Ld42R5Ju~p3zDkzH$lZo*t z!6L_@#|@Hxr%SpMZ_Kroxa`WZkrc^DRk6v4k=w{q#P$&UedKPThEIX;T0yW5X-VoodsUHRVYBXrX`v6+I zsz70tQ_ecw%ry+v*K0dfpV;e?>$TydX64h7e4v4E_*DE4nP$i?nF2>#4&5W7*6*kz zjyqVho6lR5ruYPJo0g$7Ma$-8udeg1n%gLz$-{)CBGw#5Oa$VO-ljCOE4S0CjLoV$ zOQoH(m8$+rcVboM_2H(67Fn(%c#A3qJn=Aigu_1eHO+E^xrgqpX)GQYAF*ojpa8I8_w_laT_ z_9r(yM|ECIzk&hka3qh;xnBS63E)6mvj+h8e85k-b7Ife(3VXQmeR?aLrWby-|ei7 zIU?mdj4MX($y2k+YWHpVw^oeSZ}Od(z6E%biaL+OgG4wnCFIi@Ffd&Q5D6E6hRJ8U z`U|~N!bid*2Y9n{bRIj37+}L!y@o1Rk9ymSo8AtXXsf=ZfW4nvRMHK|bxQz!Hj4!b zXN&8Zny!rGtyit&J76J`+I8-5WAjlg*qGJ?>38XfuMyH=+4e}9nvv2GkXb|fDE7My zfluL79M7 zt#jRWui7AUy$tP*Wn>`>LBe|)d`9gd*_e7PZ-w^7SMQUIU$>EbY;HzMKJ`%qFn!j6 zlZykeP_YeXQiw7ic!T7zj6#9u%zjS*Y*xQ70f3;o=0M%&r<7WX3cjs~K>gc}_*LOh zr4m{jo#KgFw;xGPpi}<|X!;bZ1J-{EeAW{sonhRQd4U&xbxfOG7xC`^kibd65vVbj zP#`CcVAn2F85!vf%0o?7tJf^+9&AXXqf~o*i{xeNZ2LBZTRmQEqayF5-7s%bhwWJp zq8)@ERZG{43<>XgZ8#U7m*4FQWY6KNq#%7U=CSojuKe5FE7-T-wu6#B53dsKy+)q_ zaaKa2Mrs>5ghQY3XkT<8=)gbB-vf+4-He#N7DVRG`Xq{48?G^-TkEPSuT9F#@hdC!G@$c06U# zo%S8^E*0jdwe@@wQwJC?y8syVa&$S~J5hv>4ty?>eVHfqF||&GZ4yUxlB9p9`?X&P zia;%kbkImUx^|V*%PGg}brtJfS+mp(t8+7Hc*6hy93)hbA z^0kkKgvxgV3TieB_a-A@N0@aNu6%e?EQda#!|(LPr&{OLa99)53OFDNqT^5*ZYjo1 zKD#11ib&s=+i{{^b);haqu%H6d1nK?t`T3=e|^EB`^q%H6>W+i02d`z*$E29_1nmk zB?T|7Xc^NSyp$5fWh<-&@G_xPt)j>@zaa~a?WZ#$Bu=s+Pi-jQ`NOy8Rh1$G&jq;v zi1>lC*oSuw-sVMER3gg)o!60_%V%-?eJCX*9`5Mo{qeo*ocyixm**s^us9Ub-3q|; z44;3P0Bx+i|In|}yq##lJ5*AnT>%t0$vt4|TnE%7GnOxkDUbH2D4?|(!SBE{7+DD1 znt6Vo_M5JBY1xdBn&@_kwyNMDm8 z4rfYq=QO7w{DtAN$WW$a{OEb?%4gDzOiy40e!IL zh)P5X;iT`^ukCk3v^#*k&9-oEh=}ot+1_`-HiB~o1K>NsV}zw}irxj zNr#&>?RuGs+->bEId1RD*rM3A=P!yLeMfW0iJHIde)D^aYR?$lfxrP-{D|7w=gHK- z0^VyWq|2yV4`R+rtE!>);}=QT^w@GO8KtYQxR2sl6J(9c+{($u-luoLt~G=O_>_FO zy13?2ALv#S3kdi#XX)H(|X*M{sp4g z%a}%V08qqSeUxP1<+JsG;F>P)fTSd@hPwv4#kzX2xp{iK*`4~=+FdT%9PFDET&SI0 zxChm}tn7B35qHtCL3AEzcqBvuwRziXfHcDE(Y%C1PT*1kmC&35!1O#`xd#fJ#{k7< z&1=Mn*v=jqyw&$i-whF{@j-hCGVKl=QjJAb{M`qLra{|?byP4Ld86C|kz*QVkoJou z9@a(3ETc)5U(<2yG@hjnldSZUw13c7p)QrT_8^!&;96B>wC?J{J@_%T*I=qEC8L`9 zaQLa-ygfqFcbg-yPXti}mpA#ZSGf zp~wEc_xeeH6dmLFLw%8puF!sGWc$#>#YbnhqX9aO;>0GUR9LQ&j&_%^3sT5np2eVG z=V_%&!4+!dgBq&APGPn>HtRkne^G%$xzlRJ0y;*ie6LR8;#uI{E0>V-dw;Cs?uLw) zS;x{NBnvLjvrW6W#txA)!j12dyT(G8I+ppO)kY$cFod--k4GQgouAL)Uo%D`3oqeU z$c@P0ASobDw`qm_W%Bgto*{PQb|PQKZ$I^Jc&Qlrp0xQR;iDPL#(4-~^r!{WuNk!! zdDk@of_eP9$NDmdKNxRLs~idBcK}Ga7I=--+9_I2ksK)*_dCNb3p)QOm>+6_+~xFt6Y~UaTw~C3L9~Q;v-
~fd*6WVNJt&(k` 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 literal 0 HcmV?d00001 diff --git a/src/app/_shared/api/articles/timliu/simple-javascript-event-loop-and-async/after-line3.png b/src/app/_shared/api/articles/timliu/simple-javascript-event-loop-and-async/after-line3.png new file mode 100644 index 0000000000000000000000000000000000000000..2ca7b70bd01c51690d12df23987230cec002ebc2 GIT binary patch literal 24100 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 literal 0 HcmV?d00001 diff --git a/src/app/_shared/api/articles/timliu/simple-javascript-event-loop-and-async/async-checkbox.png b/src/app/_shared/api/articles/timliu/simple-javascript-event-loop-and-async/async-checkbox.png new file mode 100644 index 0000000000000000000000000000000000000000..77da5ed262e91babf6e403a8e688b9e20a133696 GIT binary patch literal 30848 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

5w{dy5YonBCOjK%z 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 NF&ESna?w}3{}+~Y{$KzA literal 0 HcmV?d00001 diff --git a/src/app/_shared/api/authors/index.ts b/src/app/_shared/api/authors/index.ts index 7151ee6..336e3aa 100644 --- a/src/app/_shared/api/authors/index.ts +++ b/src/app/_shared/api/authors/index.ts @@ -52,7 +52,7 @@ const items: Author[] = [ homepage: 'https://github.com/lhtin' }, { - id: 'Tim刘', + id: 'timliu', name: 'Tim刘', bio: '小白小白小白', description: require('./Tim刘.md'), From 0a06de705846ce773cb6ce4a1a46a8bdb97e0ce5 Mon Sep 17 00:00:00 2001 From: lhtin Date: Thu, 10 Nov 2016 09:35:42 +0800 Subject: [PATCH 047/177] merge --- src/app/_shared/api/articles/index.ts | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 80157d1..1ead567 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -201,7 +201,7 @@ const items: Article[] = [ tags: [], authors: ['trotyl'], }, - { + { id: 'TypeScript的新特性', title: 'TypeScript的新特性', summary: 'Angular 2把TypeScript作为首选语言,很多新人可能还不太熟悉,就我来把一些个人的理解分享给大家。小鲜肉的处女作,多谢捧场', @@ -210,7 +210,7 @@ const items: Article[] = [ tags: ['ts'], authors: ['wike'], }, - { + { id: '杂谈:何不食肉糜?', title: '杂谈:何不食肉糜?', summary: '今天,我们不谈技术。来聊点八卦吧,雪狼的第一重身份其实是儒生,他为什么选择翻译官方文档?因为这源于儒者的信仰。请听我细说从头。', @@ -219,7 +219,7 @@ const items: Article[] = [ tags: ['过去'], authors: ['雪狼'], }, - { + { id: '如何选择合适的框架', title: '如何选择合适的框架', summary: '无论是在社区还是在公司,我都不愿意公开比较两个框架,因为我无法容忍自己公开发表不够专业的意见。那么我在公开发表意见方面恪守着哪些原则呢?请看本文。', @@ -256,7 +256,6 @@ const items: Article[] = [ authors: ['Tim刘'], }, { -<<<<<<< HEAD id: '依赖注入简介', title: '依赖注入简介', summary: '什么是依赖注入?又为什么需要依赖注入?本文尝试给出一个简短的回答。', @@ -266,15 +265,6 @@ const items: Article[] = [ authors: ['钉子哥'], }, { - id: '一个依赖注入小框架的实现', - title: '一个依赖注入小框架的实现', - summary: '《依赖注入简介》介绍了下依赖注入的原理,本文尝试使用ES5代码来做一个依赖注入框架的实现。', - content: require('./250.一个依赖注入小框架的实现/_index.md'), - first: true, - tags: ['DI'], - authors: ['钉子哥'], - } -======= id: '从ng1到ng2的平滑升级[1]', title: '从ng1到ng2的平滑升级[1]', summary: '系列文章:手把手教你将ng1项目平滑升级至ng2', @@ -283,7 +273,15 @@ const items: Article[] = [ tags: ['ng1', 'ng2', '平滑升级', 'es6', 'typescript'], authors: ['王開寧'], }, ->>>>>>> fad447625a4e7b15785286c10b95197a98fe645b + { + id: '一个依赖注入小框架的实现', + title: '一个依赖注入小框架的实现', + summary: '《依赖注入简介》介绍了下依赖注入的原理,本文尝试使用ES5代码来做一个依赖注入框架的实现。', + content: require('./250.一个依赖注入小框架的实现/_index.md'), + first: true, + tags: ['DI'], + authors: ['钉子哥'], + } ]; @Injectable() From 5f6534efcaa6225a88df193f92630614ee52d980 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Wed, 9 Nov 2016 19:16:03 -0800 Subject: [PATCH 048/177] lists articles from latest to earliest --- src/app/_shared/api/articles/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 1ead567..37683f8 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -286,7 +286,8 @@ const items: Article[] = [ @Injectable() export class ArticleApi { + private itemsLastestComesFirst: Article[] = items.concat().reverse(); query(params = {}): Observable

{ - return Observable.from(items).filter((item)=>!item.hidden); + return Observable.from(this.itemsLastestComesFirst).filter((item)=>!item.hidden); } } From a32405b3bd1995e53fa4cbf975126259755e3d28 Mon Sep 17 00:00:00 2001 From: JoeyG Date: Thu, 10 Nov 2016 13:36:35 +0800 Subject: [PATCH 049/177] =?UTF-8?q?add=20article=20"=E6=9E=84=E5=BB=BA?= =?UTF-8?q?=E6=B5=81=E5=BC=8F=E5=BA=94=E7=94=A8=E2=80=94RxJS=E8=AF=A6?= =?UTF-8?q?=E8=A7=A3"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 472 ++++++++++++++++++ src/app/_shared/api/articles/index.ts | 8 + 2 files changed, 480 insertions(+) create mode 100644 "src/app/_shared/api/articles/270.\346\236\204\345\273\272\346\265\201\345\274\217\345\272\224\347\224\250\342\200\224RxJS\350\257\246\350\247\243/_index.md" diff --git "a/src/app/_shared/api/articles/270.\346\236\204\345\273\272\346\265\201\345\274\217\345\272\224\347\224\250\342\200\224RxJS\350\257\246\350\247\243/_index.md" "b/src/app/_shared/api/articles/270.\346\236\204\345\273\272\346\265\201\345\274\217\345\272\224\347\224\250\342\200\224RxJS\350\257\246\350\247\243/_index.md" new file mode 100644 index 0000000..8005438 --- /dev/null +++ "b/src/app/_shared/api/articles/270.\346\236\204\345\273\272\346\265\201\345\274\217\345\272\224\347\224\250\342\200\224RxJS\350\257\246\350\247\243/_index.md" @@ -0,0 +1,472 @@ +最近在 Alloyteam Conf 2016 分享了《使用RxJS构建流式前端应用》,会后在线上线下跟大家交流时发现对于 RxJS 的态度呈现出两大类:有用过的都表达了 RxJS 带来的优雅编码体验,未用过的则反馈太难入门。所以,这里将结合自己对 RxJS 理解,通过 RxJS 的实现原理、基础实现及实例来一步步分析,提供 RxJS 较为全面的指引,感受下使用 RxJS 编码是怎样的体验。 + +# 目录 +- 常规方式实现搜索功能 +- RxJS · 流 Stream +- RxJS 实现原理简析 + - 观察者模式 + - 迭代器模式 + - RxJS 的观察者 + 迭代器模式 +- RxJS 基础实现 + - Observable + - Observer +- RxJS · Operators + - Operators ·入门 + - 一系列的 Operators 操作 +- 使用 RxJS 一步步实现搜索功能 +- 总结 + +------------------------------------------- + +# 常规方式实现搜索 +做一个搜索功能在前端开发中其实并不陌生,一般的实现方式是:监听文本框的输入事件,将输入内容发送到后台,最终将后台返回的数据进行处理并展示成搜索结果。 +``` html + + +``` + +上面代码实现我们要的功能,但存在两个较大的问题: + +1. 多余的请求 +当想搜索“爱迪生”时,输入框可能会存在三种情况,“爱”、“爱迪”、“爱迪生”。而这三种情况将会发起 3 次请求,存在 2 次多余的请求。 + +2. 已无用的请求仍然执行 +一开始搜了“爱迪生”,然后马上改搜索“达尔文”。结果后台返回了“爱迪生”的搜索结果,执行渲染逻辑后结果框展示了“爱迪生”的结果,而不是当前正在搜索的“达尔文”,这是不正确的。 + +**减少多余请求数**,可以用 setTimeout 函数节流的方式来处理,核心代码如下 +``` html + + +``` +**已无用的请求仍然执行**的解决方式,可以在发起请求前声明一个当前搜索的状态变量,后台将搜索的内容及结果一起返回,前端判断返回数据与当前搜索是否一致,一致才走到渲染逻辑。最终代码为 +``` html + + +``` +上面代码基本满足需求,但代码开始显得乱糟糟。我们来使用 RxJS 实现上面代码功能,如下 +``` javascript +var text = document.querySelector('#text'); +var inputStream = Rx.Observable.fromEvent(text, 'keyup') + .debounceTime(250) + .pluck('target', 'value') + .switchMap(url => Http.get(url)) + .subscribe(data => render(data)); +``` +可以明显看出,**基于 RxJS 的实现,代码十分简洁!** + +# RxJS · 流 Stream +RxJS 是 Reactive Extensions for JavaScript 的缩写,起源于 Reactive Extensions,是一个基于可观测数据流在异步编程应用中的库。RxJS 是 Reactive Extensions 在 JavaScript 上的实现,而其他语言也有相应的实现,如 RxJava、RxAndroid、RxSwift 等。学习 RxJS,我们需要从可观测数据流(Streams)说起,它是 Rx 中一个重要的数据类型。 + +**流**是在时间流逝的过程中产生的一系列事件。它具有时间与事件响应的概念。 + +![rxjs_stream](https://cloud.githubusercontent.com/assets/10385585/19881194/bd78ec98-a03e-11e6-9a3d-155fcbd3ba35.gif) + +下雨天时,雨滴随时间推移逐渐产生,下落时对水面产生了水波纹的影响,这跟 Rx 中的流是很类似的。而在 Web 中,雨滴可能就是一系列的鼠标点击、键盘点击产生的事件或数据集合等等。 + +# RxJS 基础实现原理简析 + +对流的概念有一定理解后,我们来讲讲 RxJS 是怎么围绕着流的概念来实现的,讲讲 RxJS 的基础实现原理。RxJS 是基于观察者模式和迭代器模式以函数式编程思维来实现的。 + +## 观察者模式 +观察者模式在 Web 中最常见的应该是 DOM 事件的监听和触发。 + +- **订阅**:通过 addEventListener 订阅 document.body 的 click 事件。 +- **发布**:当 body 节点被点击时,body 节点便会向订阅者发布这个消息。 + +``` javascript +document.body.addEventListener('click', function listener(e) { + console.log(e); +},false); + +document.body.click(); // 模拟用户点击 +``` +将上述例子抽象模型,并对应通用的观察者模型 + +![2016-11-01 9 53 52](https://cloud.githubusercontent.com/assets/10385585/19889545/58dababe-a070-11e6-8e54-be78121f9ba1.png) + + +## 迭代器模式 +迭代器模式可以用 JavaScript 提供了 Iterable Protocol 可迭代协议来表示。Iterable Protocol 不是具体的变量类型,而是一种可实现协议。JavaScript 中像 Array、Set 等都属于内置的可迭代类型,可以通过 iterator 方法来获取一个迭代对象,调用迭代对象的 next 方法将获取一个元素对象,如下示例。 + +``` javascript +var iterable = [1, 2]; + +var iterator = iterable[Symbol.iterator](); + +iterator.next(); // => { value: "1", done: false} +iterator.next(); // => { value: "2", done: false} + +iterator.next(); // => { value: undefined, done: true} +``` +元素对象中:value 表示返回值,done 表示是否已经到达最后。 + +遍历迭代器可以使用下面做法。 + +``` javascript +var iterable = [1, 2]; +var iterator = iterable[Symbol.iterator](); + +var iterator = iterable(); + +while(true) { + try { + let result = iterator.next(); // <= 获取下一个值 + } catch (err) { + handleError(err); // <= 错误处理 + } + if (result.done) { + handleCompleted(); // <= 无更多值(已完成) + break; + } + doSomething(result.value); +} +``` + +主要对应三种情况: + +- 获取下一个值 +调用 next 可以将元素一个个地返回,这样就支持了返回多次值。 + +- 无更多值(已完成) +当无更多值时,next 返回元素中 done 为 true。 + +- 错误处理 +当 next 方法执行时报错,则会抛出 error 事件,所以可以用 try catch 包裹 next 方法处理可能出现的错误。 + +## RxJS 的观察者 + 迭代器模式 +RxJS 中含有两个基本概念:Observables 与 Observer。Observables 作为被观察者,是一个值或事件的流集合;而 Observer 则作为观察者,根据 Observables 进行处理。 +Observables 与 Observer 之间的订阅发布关系(观察者模式) 如下: + +- **订阅**:Observer 通过 Observable 提供的 subscribe() 方法订阅 Observable。 +- **发布**:Observable 通过回调 next 方法向 Observer 发布事件。 + +下面为 Observable 与 Observer 的伪代码 +```javascript +// Observer +var Observer = { + next(value) { + alert(`收到${value}`); + } +}; + +// Observable +function Observable (Observer) { + setTimeout(()=>{ + Observer.next('A'); + },1000) +} + +// subscribe +Observable(Observer); +``` + +上面实际也是观察者模式的表现,那么迭代器模式在 RxJS 中如何体现呢? + +在 RxJS 中,Observer 除了有 next 方法来接收 Observable 的事件外,还可以提供了另外的两个方法:error() 和 complete(),与迭代器模式一一对应。 + +``` javascript +var Observer = { + next(value) { /* 处理值*/ }, + error(error) { /* 处理异常 */ }, + complete() { /* 处理已完成态 */ } +}; +``` + +结合迭代器 Iterator 进行理解: + +- **next()** +Observer 提供一个 next 方法来接收 Observable 流,是一种 push 形式;而 Iterator 是通过调用 iterator.next() 来拿到值,是一种 pull 的形式。 + +- **complete()** +当不再有新的值发出时,将触发 Observer 的 complete 方法;而在 Iterator 中,则需要在 next 的返回结果中,当返回元素 done 为 true 时,则表示 complete。 + +- **error()** +当在处理事件中出现异常报错时,Observer 提供 error 方法来接收错误进行统一处理;Iterator 则需要进行 try catch 包裹来处理可能出现的错误。 + +下面是 Observable 与 Observer 实现观察者 + 迭代器模式的伪代码,数据的逐渐传递传递与影响其实就是流的表现。 +``` javascript +// Observer +var Observer = { + next(value) { + alert(`收到${value}`); + }, + error(error) { + alert(`收到${value}`); + }, + complete() { + alert("complete"); + }, +}; + +// Observable +function Observable (Observer) { + [1,2,3].map(item=>{ + Observer.next(item); + }); + + Observer.complete(); + // Observer.error("error message"); +} + +// subscribe +Observable(Observer); +``` + +# RxJS 基础实现 + +有了上面的概念及伪代码,那么在 RxJS 中是怎么创建 Observable 与 Observer 的呢? + +### 创建 Observable + +RxJS 提供 create 的方法来自定义创建一个 Observable,可以使用 next 来发出流。 + +``` javascript +var Observable = Rx.Observable.create(observer => { + observer.next(2); + observer.complete(); + return () => console.log('disposed'); +}); +``` + +### 创建 Observer + +Observer 可以声明 next、err、complete 方法来处理流的不同状态。 + +``` javascript +var Observer = Rx.Observer.create( + x => console.log('Next:', x), + err => console.log('Error:', err), + () => console.log('Completed') +); +``` +最后将 Observable 与 Observer 通过 subscribe 订阅结合起来。 + +``` javascript +var subscription = Observable.subscribe(Observer); +``` + +RxJS 中流是可以被取消的,调用 subscribe 将返回一个 subscription,可以通过调用 subscription.unsubscribe() 将流进行取消,让流不再产生。 + +看了起来挺复杂的?换一个实现形式: + +``` javascript +// @Observables 创建一个 Observables +var streamA = Rx.Observable.of(2); + +// @Observer streamA$.subscribe(Observer) +streamA.subscribe(v => console.log(v)); +``` + +将上面代码改用链式写法,代码变得十分简洁: + +``` javascript +Rx.Observable.of(2).subscribe(v => console.log(v)); +``` + +# RxJS · Operators 操作 + +## Operators 操作·入门 + +``` javascript +Rx.Observable.of(2).subscribe(v => console.log(v)); +``` + +上面代码相当于创建了一个流(2),最终打印出2。那么如果想将打印结果翻倍,变成4,应该怎么处理呢? + +**方案一?**: 改变事件源,让 Observable 值 X 2 + +``` javascript +Rx.Observable.of(2 * 2 /* <= */).subscribe(v => console.log(v)); +``` + +**方案二?**: 改变响应方式,让 Observer 处理 X 2 + +``` javascript +Rx.Observable.of(2).subscribe(v => console.log(v * 2 /* <= */)); +``` + +**优雅方案**: RxJS 提供了优雅的处理方式,可以在事件源(Observable)与响应者(Observer)之间增加操作流的方法。 + +``` javascript +Rx.Observable.of(2) + .map(v => v * 2) /* <= */ + .subscribe(v => console.log(v)); +``` + +map 操作跟数组操作的作用是一致的,不同的这里是将流进行改变,然后将新的流传出去。在 RxJS 中,把这类操作流的方式称之为 Operators(操作)。RxJS提供了一系列 Operators,像map、reduce、filter 等等。操作流将产生新流,从而保持流的不可变性,这也是 RxJS 中函数式编程的一点体现。关于函数式编程,这里暂不多讲,可以看看另外一篇文章 [《谈谈函数式编程》](https://github.com/joeyguo/blog/issues/10) + +到这里,我们知道了,流从产生到最终处理,可能经过的一些操作。即 RxJS 中 Observable 将经过一系列 Operators 操作后,到达 Observer。 + +``` javascript + Operator1 Operator2 +Observable ----|-----------|-------> Observer +``` + + +## 一系列的 Operators 操作 + +RxJS 提供了非常多的操作,像下面这些。 + +``` javascript +Aggregate,All,Amb,ambArray,ambWith,AssertEqual,averageFloat,averageInteger,averageLong,blocking,blockingFirst,blockingForEach,blockingSubscribe,Buffer,bufferWithCount,bufferWithTime,bufferWithTimeOrCount,byLine,cache,cacheWithInitialCapacity,case,Cast,Catch,catchError,catchException,collect,concatWith,Connect,connect_forever,cons,Contains,doAction,doAfterTerminate,doOnComplete,doOnCompleted,doOnDispose,doOnEach,doOnError,doOnLifecycle,doOnNext,doOnRequest,dropUntil,dropWhile,ElementAt,ElementAtOrDefault,emptyObservable,fromNodeCallback,fromPromise,fromPublisher,fromRunnable,Generate,generateWithAbsoluteTime,generateWithRelativeTime,Interval,intervalRange,into,latest (Rx.rb version of Switch),length,mapTo,mapWithIndex,Materialize,Max,MaxBy,mergeArray,mergeArrayDelayError,mergeWith,Min,MinBy,multicastWithSelector,nest,Never,Next,Next (BlockingObservable version),partition,product,retryWhen,Return,returnElement,returnValue,runAsync,safeSubscribe,take_with_time,takeFirst,TakeLast,takeLastBuffer,takeLastBufferWithTime,windowed,withFilter,withLatestFrom,zipIterable,zipWith,zipWithIndex +``` + +关于每一个操作的含义,可以查看[官网](http://reactivex.io/documentation/operators.html)进行了解。下面将举几个例子。 + +**of** +of 可以将普通数据转换成流式数据 Observable。如上面的 Rx.Observable.of(2)。 + +**fromEvent** +除了数值外,RxJS 还提供了关于事件的操作,fromEvent 可以用来监听事件。当事件触发时,将事件 event 转成可流动的 Observable 进行传输。下面示例表示:监听文本框的 keyup 事件,触发 keyup 可以产生一系列的 event Observable。 +``` javascript +var text = document.querySelector('#text'); +Rx.Observable.fromEvent(text, 'keyup') + .subscribe(e => console.log(e)); +``` + +**map** +map 方法跟我们平常使用的方式是一样的,不同的只是这里是将流进行改变,然后将新的流传出去。上面示例已有涉及,这里不再多讲。 + +``` javascript +Rx.Observable.of(2) + .map(v => 10 * v) + .subscribe(v => console.log(v)); +``` + +Rx 提供了许多的操作,为了更好的理解各个操作的作用,我们可以通过一个可视化的工具 [marbles 图](http://rxmarbles.com/) 来辅助理解。如 map 方法对应的 marbles 图如下 + +![map](https://cloud.githubusercontent.com/assets/10385585/19889586/9af9d4ca-a070-11e6-8582-8dbdcfcef520.png) + +箭头可以理解为时间轴,上面的数据经过中间的操作,转变成下面的模样。 + +**FlatMap** +FlatMap 也是 RxJS 中常用的接口,我们来结合 marbles 图来理解它 + +![rxjs_flatmap](https://cloud.githubusercontent.com/assets/10385585/19889614/cb4bed20-a070-11e6-9de0-7f04d8de53cc.png) + +上面的数据流中,产生了新的分支流(流中流),FlatMap 的作用则是将分支流调整回主干上,最终分支上的数据流都经过主干的其他操作,其实也是将流中流进行扁平化。 + +**switchMap** +switchMap 与 FlatMap 都是将分支流疏通到主干上,而不同的地方在于 switchMap 只会保留最后的流,而取消抛弃之前的流。 + +除了上面提到的 marbles,也可以 ASCII 字符的方式来绘制可视化图表,下面将结合 Map、FlatMap 和 switchMap 进行对比来理解。 + +``` +@Map @FlatMap @switchMap + ↗ ↗ ↗ ↗ +-A------B--> a2 b2 a2 b2 +-2A-----2B-> / / / / + / / / / + a1 b1 a1 b1 + / / / / + -A-B-----------> -A-B----------> + --a1-b1-a2-b2--> --a1-b1---b2--> +``` + +FlatMap 和 switchMap 中,A 和 B 是主干上产生的流,a1、a2 为 A 在分支上产生,b1、b2 为 B 在分支上产生,可看到,最终将归并到主干上。switchMap 只保留最后的流,所以将 A 的 a2 抛弃掉。 + +**debounceTime** +debounceTime 操作可以操作一个时间戳 TIMES,表示经过 TIMES 毫秒后,没有流入新值,那么才将值转入下一个操作。 + +![rxjs_debounce](https://cloud.githubusercontent.com/assets/10385585/19889647/f6ce3aac-a070-11e6-8a35-b04f05afbe36.png) + +RxJS 中的操作符是满足我们以前的开发思维的,像 map、reduce 这些。另外,无论是 marbles 图还是用 ASCII 字符图这些可视化的方式,都对 RxJS 的学习和理解有非常大的帮助。 + +# 使用 RxJS 一步步实现搜索示例 + +RxJS 提供许多创建流或操作流的接口,应用这些接口,我们来一步步将搜索的示例进行 Rx 化。 + +使用 RxJS 提供的 fromEvent 接口来监听我们输入框的 keyup 事件,触发 keyup 将产生 Observable。 +``` javascript +var text = document.querySelector('#text'); +Rx.Observable.fromEvent(text, 'keyup') + .subscribe(e => console.log(e)); +``` +这里我们并不想输出事件,而想拿到文本输入值,请求搜索,最终渲染出结果。涉及到两个新的 Operators 操作,简单理解一下: + +- **pluck('target', 'value')** +将输入的 event,输出成 event.target.value。 + +- **flatMap()** +将请求搜索结果输出回给 Observer 上进行渲染。 + +``` javascript +var text = document.querySelector('#text'); +Rx.Observable.fromEvent(text, 'keyup') + .pluck('target', 'value') // <-- + .flatMap(url => Http.get(url)) // <-- + .subscribe(data => render(data)) +``` +上面代码实现了简单搜索呈现,但同样存在一开始提及的两个问题。那么如何减少请求数,以及取消已无用的请求呢?我们来了解 RxJS 提供的其他 Operators 操作,来解决上述问题。 + +- **debounceTime(TIMES)** +表示经过 TIMES 毫秒后,没有流入新值,那么才将值转入下一个环节。这个与前面使用 setTimeout 来实现函数节流的方式有一致效果。 + +- **switchMap()** +使用 switchMap 替换 flatMap,将能取消上一个已无用的请求,只保留最后的请求结果流,这样就确保处理展示的是最后的搜索的结果。 + +最终实现如下,与一开始的实现进行对比,可以明显看出 RxJS 让代码变得十分简洁。 +``` javascript +var text = document.querySelector('#text'); +Rx.Observable.fromEvent(text, 'keyup') + .debounceTime(250) // <- throttling behaviour + .pluck('target', 'value') + .switchMap(url => Http.get(url)) // <- Kill the previous requests + .subscribe(data => render(data)) +``` + +# 总结 +本篇作为 RxJS 入门篇到这里就结束,关于 RxJS 中的其他方面内容,后续再拎出来进一步分析学习。 +RxJS 作为一个库,可以与众多框架结合使用,但并不是每一种场合都需要使用到 RxJS。复杂的数据来源,异步多的情况下才能更好凸显 RxJS 作用。 + +查看更多文章>> https://github.com/joeyguo/blog/issues \ No newline at end of file diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 1ead567..a164d4f 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -281,6 +281,14 @@ const items: Article[] = [ first: true, tags: ['DI'], authors: ['钉子哥'], + }, + { + id: '构建流式应用—RxJS详解', + title: '构建流式应用—RxJS详解', + summary: '通过 RxJS 的实现原理、基础实现及实例来一步步分析,提供 RxJS 较为全面的指引,感受使用 RxJS 优雅编码体验。', + content: require('./270.构建流式应用—RxJS详解/_index.md'), + tags: ['RxJS'], + authors: ['joeyguo'], } ]; From 38f225e1416b503caa09601f049f536a58b9a598 Mon Sep 17 00:00:00 2001 From: twincle Date: Sat, 12 Nov 2016 13:17:53 +0800 Subject: [PATCH 050/177] =?UTF-8?q?+=20=E6=96=B0=E5=A2=9E=E6=96=87?= =?UTF-8?q?=E7=AB=A0=E4=BB=8Eng1=E5=88=B0ng2=E7=9A=84=E5=B9=B3=E6=BB=91?= =?UTF-8?q?=E5=8D=87=E7=BA=A7[2]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 233 ++++++++++++++++++ src/app/_shared/api/articles/index.ts | 9 + 2 files changed, 242 insertions(+) create mode 100644 "src/app/_shared/api/articles/270.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[2]/_index.md" diff --git "a/src/app/_shared/api/articles/270.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[2]/_index.md" "b/src/app/_shared/api/articles/270.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[2]/_index.md" new file mode 100644 index 0000000..6e13db5 --- /dev/null +++ "b/src/app/_shared/api/articles/270.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[2]/_index.md" @@ -0,0 +1,233 @@ +如果你已经看过了前一篇文章,相信你对升级的套路已经有了一定的认识,我们来一起简单总结一下吧: + +1. 拆分ng1框架代码和业务代码,并将框架代码集中至一个或几个文件中; +2. 解除对ng1中`$scope`的依赖,将业务代码剥离为一个普通的方法; +3. 使用typescript语法(包括`class`、`constructor`、`import`、`export`等),将es3代码升级至typescript版本; +4. 根据最佳实践优化typescript代码; +5. 添加必要的ng2元素,将代码升级至ng2版本。 + +> 即使暂时没有升级至ng2的计划,利用上述方法中的前4个步骤,依然可以很好地帮助你重构现有代码,解耦对ng1的依赖,也为未来可能出现的代码重用、迁移、测试等带来很大的方便。 + +下面我们一起来接受新的挑战吧。 + +# 二、升级service/factory/provider + +> 关于service、factory、provider:相信你在使用ng1的时候一定对这三个概念产生过困惑,网上也有很多相关文章讨论三者之间的差别和联系。但稍微深入研究一下就会知道,这三者本质相同,只是做了不同的语法糖包装。本文以service为例完成升级过程。 + +首先来定义一个项目中用到的service: + +``` +// user.service.js +// 一个简单的service,用来获取用户列表 + +app.service('UserService', ['$http', function ($http) { + var service = {}; + + // 这里假定了一个api地址:/user + service.listUser = function () { + return $http.get('/user').then(function (res) { + return res.data; + }); + }; + + return service; +}]); +``` + +## 1、分离框架代码和业务代码 + +与controller的升级类似,我们先将业务代码剥离成一个单独的文件,并将所有注册service代码集中到一个文件中。 + +``` +// app-service.js +// 这个文件专门用来注册所有的service + +app.service('UserService', ['$http', userService]) + .service('ArticleService', ['$http', articleService]) + .service(...); +``` + +``` +// user.service.js + +var userService = function ($http) { + var service = {}; + + service.listUser = function () { + return $http.get('/user').then(function (res) { + return res.data; + }); + }; + + return service; +}; +``` + +经过了前一篇文章的洗礼,这一步对你来说应该是易如反掌。 + +## 2、根据最佳实践处理依赖 + +但是和controller不同的是,这个service中所依赖的`$http`并不像`$scope`一样可以通过某种语法,从方法中完全解耦,有时候我们也必须面对这个事实,一些框架相关的API确实必须一定程度的参与到业务代码中。 + +不过好在这个依赖是通过DI的方式注入到方法中,方法也并没有直接对ng1产生依赖,因此到这里为止,关于`$http`这个依赖就这样处理也无伤大雅。 + +不过编写代码我们总希望能够尽可能优化代码。 + +这里我们会发现一个问题,如果今后`userService`的依赖,除了`$http`外又增加了`$log`依赖,这时你就必须同时修改`app-service.js`文件和`user.service.js`文件两个文件。一处调整涉及到两处修改并不符合最佳实践。设想在多人团队合作的项目中,不同人负责的多个service代码都调整了依赖内容,则会导致`app-service.js`文件被多个人同时修改,在通过版本控制软件提交时也会增加代码review的难度。 + +> 最佳实践:我们希望将service的依赖内容与service代码放在同一处,减少依赖调整所带来的文件修改数量,这也一定程度上符合高内聚和单一职责原则。 + +ng1为我们提供了一种实现方式:`$inject`。(官方文档:[https://docs.angularjs.org/api/auto/service/$injector](https://docs.angularjs.org/api/auto/service/$injector)) + +简单来说,我们将一个__字符串数组__作为`$inject`属性赋值给一个方法,ng1就会按照数组中的字符串对方法注入依赖,我们来看一下代码: + +``` +// user.service.js + +// 这里我们假设service增加了一个$log依赖 +var userService = function ($http, $log) { + + var service = {}; + + service.listUser = function () { + return $http.get('/user').then(function (res) { + return res.data; + }); + }; + + return service; +}; + +// 这里使用$inject属性对service注入依赖 +userService.$inject = ['$http', '$log']; +``` + +通过这种方式,需要注入的依赖就在service文件中声明完成。 + +同时注册service的代码也可以做相应的简化: + +``` +// app-service.js + +// 由于在service文件中已经声明了service所需要的依赖,因此这里直接将service方法作为参数即可 +// 注意:这里不再需要将第二个参数写成数组形式 +app.service('UserService', userService) + .service('ArticleService', articleService) + .service(...); +``` + +> 结合上一篇中定义的controller,我们也可以使用相同的方式,在controller方法上定义一个`$inject`属性来声明依赖,这种声明方式可以用在包括ng1自有依赖和项目自定义service的各种依赖上。因此,理论上来说,在注册controller、service等各类组件时,均可以达到“仅注册,不声明依赖”的目的。 + +## 3、向typescript进发 + +和之前一样,我们也需要将es3代码升级为typescript代码。 + +``` +// user.service.ts + +// 原来的service方法以class的方式定义 +export default class UserService { + + // 这里我们使用static关键字,直接对service类添加静态属性$inject + static $inject : string[] = ['$http', '$log']; + + // service的依赖通常都不需要在外部调用,因此这里我们声明为私有属性 + // 这里我们将属性名中的$符号去除,减少ng1的痕迹 + constructor (private _http : any, private _log : any) { + // 在constructor的参数里使用public、private、protected等关键字声明的参数, + // 将被typescript自动定义为同名类属性 + // 相当于执行了代码:this._http = _http;,因此不需要手动赋值 + } + + listUser () : Promise { + // 使用this._http来调用依赖 + return this._http + .get('/user') + .then((res : any) : any[] => res.data); + } + +} +``` + +``` +// app-service.ts + +import app from './app'; + +import UserService from './user.service'; +import ArticleService from './article.service'; +... + +app.service('UserService', userService) + .service('ArticleService', articleService) + .service(...); +``` + +## 4、升级为ng2 + +升级前的重构准备工作都做完了,升级至ng2就指日可待啦。 + +``` +// user.service.ts + +import { Http, Response } from '@angular/http'; +import { Injectable } from '@angular/core'; + +import { Observable } from 'rxjs'; + +// 这里假设已经在项目中定义了User类型 +// 如果没有定义,后面的User类型使用any来暂时代替也尚无不可 +import User from './user.model'; + +@Injectable +export default class UserService { + + // 这里不再使用ng1的注入方式,而通过在AppModule注解的imports属性引入HttpModule + // 不过即使保留这个静态属性,也不会对ng2的运行产生影响 + // 虽然保留下来并不是较好的习惯,但也在一定程度上减少升级工作量 + // static $inject : string[] = ['$http', '$log']; + + // ng2中通过参数类型来判断依赖的服务 + // 这里省略$log依赖 + constructor (private _http : Http) { + + } + + // ng2中默认使用rxjs的方式调用http方法, + // 如果不习惯,可以通过toPromise()方法将Observable转换为Promise + // 虽然推荐使用rxjs,但是转换为Promise类型可以降低依赖该服务的其他组件的升级成本 + listUser () : Observable { + return this._http + .get('/user') + .map((res : Response) : User[] => res.json() as User[]); + } + +} +``` + +## 5、关于value和constant + +如果说service、factory、provider比较类似——至少都可以注入依赖并通过function(es3)或class(typescript)来完成定义,那么value和constant就有点不太一样,因为它们就只是一个值而已啊。 + +这时你可以通过这样来实现: + +``` +let someValue : any = { foo : 'bar' }; + +export default someValue; +``` + +或者这样: + +``` +const PI = 3.1415926; + +export default PI; +``` + +但是这样把每个不同的value或constant分散管理在不同的文件中,显然也是比较麻烦的。因此,这里我们建议您将各种值均设置在一个service中统一管理,例如`ValueService`和`ConstantService`,这样在ng2中也比较方便升级和维护。 + +依旧留一道练习题:把上次使用的controller/component和今天的service组合在一起试试吧。 + +(未完待续) + diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 1e1a5d9..592d9f3 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -264,6 +264,15 @@ const items: Article[] = [ tags: ['ng1', 'ng2', '平滑升级', 'es6', 'typescript'], authors: ['王開寧'], }, + { + id: '从ng1到ng2的平滑升级[2]', + title: '从ng1到ng2的平滑升级[2]', + summary: '系列文章:手把手教你将ng1项目平滑升级至ng2', + content: require('./270.从ng1到ng2的平滑升级[2]/_index.md'), + first: true, + tags: ['ng1', 'ng2', '平滑升级', 'es6', 'typescript'], + authors: ['王開寧'], + }, ]; @Injectable() From 5bdbe870256732b34f9a7c05c54a9f5b0c6f9fbc Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Sat, 12 Nov 2016 03:46:22 -0800 Subject: [PATCH 051/177] modifies the pseudo-code for subject --- src/app/_shared/api/articles/simple-rxjs/_index.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/app/_shared/api/articles/simple-rxjs/_index.md b/src/app/_shared/api/articles/simple-rxjs/_index.md index c3f52e0..8a787f1 100644 --- a/src/app/_shared/api/articles/simple-rxjs/_index.md +++ b/src/app/_shared/api/articles/simple-rxjs/_index.md @@ -156,12 +156,13 @@ const FakeSubjectClass = function() { FakeSubjectClass.prototype.subscribe = function(observer) { let that = this; - // 添加新observer,获取其所在的index;添加之前会检查是否observers已经有了这个observer,这里偷懒了没写 - let indexA = (that.observers.push(observer) - 1); + // 添加新observer,添加之前会检查是否observers已经有了这个observer,如果有,就什么也不做 + if (that.observers.indexOf(observer) >= 0) return; + that.observers.push(observer); return { unsubscribe: () => { - // 从observers列表里将这个位置在indexA的observer删除 - that.observers = that.observers.filter((observer, index) => index !== indexA) + // 从observers列表里将这个observer删除 + that.observers = that.observers.filter((observerX) => observerX !== observer) } } } From c596716f985fd766968e97471bba1d578dd9fbc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=9E=97=E7=83=81?= Date: Sun, 13 Nov 2016 10:53:51 +0800 Subject: [PATCH 052/177] flatMap -> mergeMap --- .../_index.md" | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git "a/src/app/_shared/api/articles/270.\346\236\204\345\273\272\346\265\201\345\274\217\345\272\224\347\224\250\342\200\224RxJS\350\257\246\350\247\243/_index.md" "b/src/app/_shared/api/articles/270.\346\236\204\345\273\272\346\265\201\345\274\217\345\272\224\347\224\250\342\200\224RxJS\350\257\246\350\247\243/_index.md" index 8005438..3f1cb63 100644 --- "a/src/app/_shared/api/articles/270.\346\236\204\345\273\272\346\265\201\345\274\217\345\272\224\347\224\250\342\200\224RxJS\350\257\246\350\247\243/_index.md" +++ "b/src/app/_shared/api/articles/270.\346\236\204\345\273\272\346\265\201\345\274\217\345\272\224\347\224\250\342\200\224RxJS\350\257\246\350\247\243/_index.md" @@ -389,20 +389,20 @@ Rx 提供了许多的操作,为了更好的理解各个操作的作用,我 箭头可以理解为时间轴,上面的数据经过中间的操作,转变成下面的模样。 -**FlatMap** -FlatMap 也是 RxJS 中常用的接口,我们来结合 marbles 图来理解它 +**mergeMap** +mergeMap 也是 RxJS 中常用的接口,我们来结合 marbles 图(flatMap(alias))来理解它 ![rxjs_flatmap](https://cloud.githubusercontent.com/assets/10385585/19889614/cb4bed20-a070-11e6-9de0-7f04d8de53cc.png) -上面的数据流中,产生了新的分支流(流中流),FlatMap 的作用则是将分支流调整回主干上,最终分支上的数据流都经过主干的其他操作,其实也是将流中流进行扁平化。 +上面的数据流中,产生了新的分支流(流中流),mergeMap 的作用则是将分支流调整回主干上,最终分支上的数据流都经过主干的其他操作,其实也是将流中流进行扁平化。 **switchMap** -switchMap 与 FlatMap 都是将分支流疏通到主干上,而不同的地方在于 switchMap 只会保留最后的流,而取消抛弃之前的流。 +switchMap 与 mergeMap 都是将分支流疏通到主干上,而不同的地方在于 switchMap 只会保留最后的流,而取消抛弃之前的流。 -除了上面提到的 marbles,也可以 ASCII 字符的方式来绘制可视化图表,下面将结合 Map、FlatMap 和 switchMap 进行对比来理解。 +除了上面提到的 marbles,也可以 ASCII 字符的方式来绘制可视化图表,下面将结合 Map、mergeMap 和 switchMap 进行对比来理解。 ``` -@Map @FlatMap @switchMap +@Map @mergeMap @switchMap ↗ ↗ ↗ ↗ -A------B--> a2 b2 a2 b2 -2A-----2B-> / / / / @@ -413,7 +413,7 @@ switchMap 与 FlatMap 都是将分支流疏通到主干上,而不同的地方 --a1-b1-a2-b2--> --a1-b1---b2--> ``` -FlatMap 和 switchMap 中,A 和 B 是主干上产生的流,a1、a2 为 A 在分支上产生,b1、b2 为 B 在分支上产生,可看到,最终将归并到主干上。switchMap 只保留最后的流,所以将 A 的 a2 抛弃掉。 +mergeMap 和 switchMap 中,A 和 B 是主干上产生的流,a1、a2 为 A 在分支上产生,b1、b2 为 B 在分支上产生,可看到,最终将归并到主干上。switchMap 只保留最后的流,所以将 A 的 a2 抛弃掉。 **debounceTime** debounceTime 操作可以操作一个时间戳 TIMES,表示经过 TIMES 毫秒后,没有流入新值,那么才将值转入下一个操作。 @@ -437,14 +437,14 @@ Rx.Observable.fromEvent(text, 'keyup') - **pluck('target', 'value')** 将输入的 event,输出成 event.target.value。 -- **flatMap()** +- **mergeMap()** 将请求搜索结果输出回给 Observer 上进行渲染。 ``` javascript var text = document.querySelector('#text'); Rx.Observable.fromEvent(text, 'keyup') .pluck('target', 'value') // <-- - .flatMap(url => Http.get(url)) // <-- + .mergeMap(url => Http.get(url)) // <-- .subscribe(data => render(data)) ``` 上面代码实现了简单搜索呈现,但同样存在一开始提及的两个问题。那么如何减少请求数,以及取消已无用的请求呢?我们来了解 RxJS 提供的其他 Operators 操作,来解决上述问题。 @@ -453,7 +453,7 @@ Rx.Observable.fromEvent(text, 'keyup') 表示经过 TIMES 毫秒后,没有流入新值,那么才将值转入下一个环节。这个与前面使用 setTimeout 来实现函数节流的方式有一致效果。 - **switchMap()** -使用 switchMap 替换 flatMap,将能取消上一个已无用的请求,只保留最后的请求结果流,这样就确保处理展示的是最后的搜索的结果。 +使用 switchMap 替换 mergeMap,将能取消上一个已无用的请求,只保留最后的请求结果流,这样就确保处理展示的是最后的搜索的结果。 最终实现如下,与一开始的实现进行对比,可以明显看出 RxJS 让代码变得十分简洁。 ``` javascript @@ -469,4 +469,4 @@ Rx.Observable.fromEvent(text, 'keyup') 本篇作为 RxJS 入门篇到这里就结束,关于 RxJS 中的其他方面内容,后续再拎出来进一步分析学习。 RxJS 作为一个库,可以与众多框架结合使用,但并不是每一种场合都需要使用到 RxJS。复杂的数据来源,异步多的情况下才能更好凸显 RxJS 作用。 -查看更多文章>> https://github.com/joeyguo/blog/issues \ No newline at end of file +查看更多文章>> https://github.com/joeyguo/blog/issues From 6a99d2eb77fdd22a619e9fdf03a0d7faa2bc9a4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=9E=97=E7=83=81?= Date: Sun, 13 Nov 2016 11:32:46 +0800 Subject: [PATCH 053/177] operators static and instance --- .../_index.md" | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git "a/src/app/_shared/api/articles/270.\346\236\204\345\273\272\346\265\201\345\274\217\345\272\224\347\224\250\342\200\224RxJS\350\257\246\350\247\243/_index.md" "b/src/app/_shared/api/articles/270.\346\236\204\345\273\272\346\265\201\345\274\217\345\272\224\347\224\250\342\200\224RxJS\350\257\246\350\247\243/_index.md" index 3f1cb63..1b59e63 100644 --- "a/src/app/_shared/api/articles/270.\346\236\204\345\273\272\346\265\201\345\274\217\345\272\224\347\224\250\342\200\224RxJS\350\257\246\350\247\243/_index.md" +++ "b/src/app/_shared/api/articles/270.\346\236\204\345\273\272\346\265\201\345\274\217\345\272\224\347\224\250\342\200\224RxJS\350\257\246\350\247\243/_index.md" @@ -361,12 +361,12 @@ RxJS 提供了非常多的操作,像下面这些。 Aggregate,All,Amb,ambArray,ambWith,AssertEqual,averageFloat,averageInteger,averageLong,blocking,blockingFirst,blockingForEach,blockingSubscribe,Buffer,bufferWithCount,bufferWithTime,bufferWithTimeOrCount,byLine,cache,cacheWithInitialCapacity,case,Cast,Catch,catchError,catchException,collect,concatWith,Connect,connect_forever,cons,Contains,doAction,doAfterTerminate,doOnComplete,doOnCompleted,doOnDispose,doOnEach,doOnError,doOnLifecycle,doOnNext,doOnRequest,dropUntil,dropWhile,ElementAt,ElementAtOrDefault,emptyObservable,fromNodeCallback,fromPromise,fromPublisher,fromRunnable,Generate,generateWithAbsoluteTime,generateWithRelativeTime,Interval,intervalRange,into,latest (Rx.rb version of Switch),length,mapTo,mapWithIndex,Materialize,Max,MaxBy,mergeArray,mergeArrayDelayError,mergeWith,Min,MinBy,multicastWithSelector,nest,Never,Next,Next (BlockingObservable version),partition,product,retryWhen,Return,returnElement,returnValue,runAsync,safeSubscribe,take_with_time,takeFirst,TakeLast,takeLastBuffer,takeLastBufferWithTime,windowed,withFilter,withLatestFrom,zipIterable,zipWith,zipWithIndex ``` -关于每一个操作的含义,可以查看[官网](http://reactivex.io/documentation/operators.html)进行了解。下面将举几个例子。 +关于每一个操作的含义,可以查看[官网](http://reactivex.io/documentation/operators.html)进行了解。operators 具有静态(static)方法和实例( instance)方法,下面使用 Rx.Observable.xx 和 Rx.Observable.prototype.xx 来简单区分,举几个例子。 -**of** +**Rx.Observable.of** of 可以将普通数据转换成流式数据 Observable。如上面的 Rx.Observable.of(2)。 -**fromEvent** +**Rx.Observable.fromEvent** 除了数值外,RxJS 还提供了关于事件的操作,fromEvent 可以用来监听事件。当事件触发时,将事件 event 转成可流动的 Observable 进行传输。下面示例表示:监听文本框的 keyup 事件,触发 keyup 可以产生一系列的 event Observable。 ``` javascript var text = document.querySelector('#text'); @@ -374,7 +374,7 @@ Rx.Observable.fromEvent(text, 'keyup') .subscribe(e => console.log(e)); ``` -**map** +**Rx.Observable.prototype.map** map 方法跟我们平常使用的方式是一样的,不同的只是这里是将流进行改变,然后将新的流传出去。上面示例已有涉及,这里不再多讲。 ``` javascript @@ -389,14 +389,14 @@ Rx 提供了许多的操作,为了更好的理解各个操作的作用,我 箭头可以理解为时间轴,上面的数据经过中间的操作,转变成下面的模样。 -**mergeMap** +**Rx.Observable.prototype.mergeMap** mergeMap 也是 RxJS 中常用的接口,我们来结合 marbles 图(flatMap(alias))来理解它 ![rxjs_flatmap](https://cloud.githubusercontent.com/assets/10385585/19889614/cb4bed20-a070-11e6-9de0-7f04d8de53cc.png) 上面的数据流中,产生了新的分支流(流中流),mergeMap 的作用则是将分支流调整回主干上,最终分支上的数据流都经过主干的其他操作,其实也是将流中流进行扁平化。 -**switchMap** +**Rx.Observable.prototype.switchMap** switchMap 与 mergeMap 都是将分支流疏通到主干上,而不同的地方在于 switchMap 只会保留最后的流,而取消抛弃之前的流。 除了上面提到的 marbles,也可以 ASCII 字符的方式来绘制可视化图表,下面将结合 Map、mergeMap 和 switchMap 进行对比来理解。 @@ -415,7 +415,7 @@ switchMap 与 mergeMap 都是将分支流疏通到主干上,而不同的地方 mergeMap 和 switchMap 中,A 和 B 是主干上产生的流,a1、a2 为 A 在分支上产生,b1、b2 为 B 在分支上产生,可看到,最终将归并到主干上。switchMap 只保留最后的流,所以将 A 的 a2 抛弃掉。 -**debounceTime** +**Rx.Observable.prototype.debounceTime** debounceTime 操作可以操作一个时间戳 TIMES,表示经过 TIMES 毫秒后,没有流入新值,那么才将值转入下一个操作。 ![rxjs_debounce](https://cloud.githubusercontent.com/assets/10385585/19889647/f6ce3aac-a070-11e6-8a35-b04f05afbe36.png) @@ -434,10 +434,10 @@ Rx.Observable.fromEvent(text, 'keyup') ``` 这里我们并不想输出事件,而想拿到文本输入值,请求搜索,最终渲染出结果。涉及到两个新的 Operators 操作,简单理解一下: -- **pluck('target', 'value')** +- **Rx.Observable.prototype.pluck('target', 'value')** 将输入的 event,输出成 event.target.value。 -- **mergeMap()** +- **Rx.Observable.prototype.mergeMap()** 将请求搜索结果输出回给 Observer 上进行渲染。 ``` javascript @@ -449,10 +449,10 @@ Rx.Observable.fromEvent(text, 'keyup') ``` 上面代码实现了简单搜索呈现,但同样存在一开始提及的两个问题。那么如何减少请求数,以及取消已无用的请求呢?我们来了解 RxJS 提供的其他 Operators 操作,来解决上述问题。 -- **debounceTime(TIMES)** +- **Rx.Observable.prototype.debounceTime(TIMES)** 表示经过 TIMES 毫秒后,没有流入新值,那么才将值转入下一个环节。这个与前面使用 setTimeout 来实现函数节流的方式有一致效果。 -- **switchMap()** +- **Rx.Observable.prototype.switchMap()** 使用 switchMap 替换 mergeMap,将能取消上一个已无用的请求,只保留最后的请求结果流,这样就确保处理展示的是最后的搜索的结果。 最终实现如下,与一开始的实现进行对比,可以明显看出 RxJS 让代码变得十分简洁。 From 3746c89a21f6fba7f116b1dbae49c15c19a0a478 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Sun, 13 Nov 2016 23:50:42 -0800 Subject: [PATCH 054/177] style fix: fixes style in 'mock redux episode 1' --- .../_shared/api/articles/mock-redux-with-rxjs/_index.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/app/_shared/api/articles/mock-redux-with-rxjs/_index.md b/src/app/_shared/api/articles/mock-redux-with-rxjs/_index.md index d84358c..d9a67ae 100644 --- a/src/app/_shared/api/articles/mock-redux-with-rxjs/_index.md +++ b/src/app/_shared/api/articles/mock-redux-with-rxjs/_index.md @@ -49,13 +49,15 @@ RxJS的文档里就有答案,就在这里:[RxJS官方教程 - State Stores][ 水平所限,难免有错漏,请大家多指教。另外,我写的比较啰嗦,请大家多包涵。 ## 相关概念 -以下为粗略理解,具体参见[官方文档][]。 +以下为粗略理解,具体参见[官方文档][]。 + 1. `Observer`:是一个Object,里面有3个Callback,形如`{next: nextFn, error: errorFn, complete: completeFn}`。 3个Callback都不是必须的。 示例: ```js const observer = {next: (v) => console.log(v)}; // 这个Observer只有next callback ``` + 2. `Observable`:定义在某个时点通过调用`observer.callback(v)`(比如`observer.next(v)`)将数据`v`推送给`observer`; `Observable`不会自动运行,而是要通过`subscribe`方法来启动, 比如,`observable.subscribe(observer)`就是启动`observable`,同时指定`observer`为数据推送对象; @@ -72,6 +74,7 @@ RxJS的文档里就有答案,就在这里:[RxJS官方教程 - State Stores][ observable$.subscribe(observer); // 启动observable,并指定数据传给observer。 // observable$.subscribe({next: nextFn}) 可以简写成 observable$.subscribe(nextFn) ``` + 3. `Subject`:既是一个`Observer`(有`next` Callback,即`subject.next(v)`),又是一个`Observable`(有`subscribe`方法,即`subject.subcribe(observer)`)。 示例: ```js @@ -79,6 +82,7 @@ RxJS的文档里就有答案,就在这里:[RxJS官方教程 - State Stores][ observable$.subscribe(subject$$); // 因为subject$$是一个observer,我们可以用subject$$来订阅observable$ subject$$.subscribe(observer); // 因为subject$$也是一个observable,它可以被别的observer订阅 ``` + 4. `BehaviorSubject`:是一个`Subject`,能留存最后一个数据;创建时需指定初始数据; 可以通过`getValue()`获取留存的最后一个数据。(RxJS version 5文档中没提`getValue`方法) 示例: @@ -87,6 +91,7 @@ RxJS的文档里就有答案,就在这里:[RxJS官方教程 - State Stores][ subjectB$$.subscribe(observable); // 订阅一个BehaviorSubject,会把当前数据立即推送给observer console.log(subjectB$$.getValue()); // getValue()获取留存的最后一个数据 ``` + 5. [scan运算符][]:如果把Observable推送的数据流类比成Array的话,那么Observable.prototype.scan运算符就类似Array.prototype.reduce, 不同在于Array.prototype.reduce是把Array中所有的数值累积后形成一个值,而Observable.prototype.scan是把当前值和之前的累积值再次累积形成一个值,参见示例: ```js @@ -221,7 +226,6 @@ const clicks_ = Observable.merge(incButtonClick$, decButtonClick$) ## 参考 [redux][] [RxJS官方教程 - State Stores][] -[RxJS Doc在github上的源码][] [官方文档][] [scan运算符][] From d223e61c7bcb81d632654a91f88bf467595ed64e Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Sun, 13 Nov 2016 23:59:01 -0800 Subject: [PATCH 055/177] style fix: fixes style in 'mock redux episode 2' --- .../mock-redux-with-rxjs-episode-2-todo-app/_index.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/mock-redux-with-rxjs-episode-2-todo-app/_index.md b/src/app/_shared/api/articles/timliu/mock-redux-with-rxjs-episode-2-todo-app/_index.md index a197abd..9ddfc75 100644 --- a/src/app/_shared/api/articles/timliu/mock-redux-with-rxjs-episode-2-todo-app/_index.md +++ b/src/app/_shared/api/articles/timliu/mock-redux-with-rxjs-episode-2-todo-app/_index.md @@ -218,11 +218,11 @@ inputElem.focus(); // 可以输入新的todo了 希望通过此文,能够帮助大家进一步了解RxJS。 ## 参考: -[Mock Redux with RxJS][] -[Repo][] -[`Observable.ajax`运算符][] -[`observers`列表][] -[JSON Server][] +[Mock Redux with RxJS][] +[Repo][] +[`Observable.ajax`运算符][] +[`observers`列表][] +[JSON Server][] [Mock Redux with RxJS]: https://wx.angular.cn/library/article/%E5%BA%94%E7%94%A8RxJS%E6%A8%A1%E6%8B%9Fredux [Repo]: https://github.com/rxjs-space/rxjs-typescript-starter From 61dbbbfa7bbbda66d00961180c2eb8a13da9928d Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Tue, 15 Nov 2016 01:02:36 -0800 Subject: [PATCH 056/177] article: fixes simple-rxjs basing on comments --- .../api/articles/simple-rxjs/_index.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/app/_shared/api/articles/simple-rxjs/_index.md b/src/app/_shared/api/articles/simple-rxjs/_index.md index 8a787f1..81a4a1d 100644 --- a/src/app/_shared/api/articles/simple-rxjs/_index.md +++ b/src/app/_shared/api/articles/simple-rxjs/_index.md @@ -58,7 +58,7 @@ const x$ = () => { // 然后就没有然后了 } ``` -`Observable`可以`return`很多次,任意多次,每次`return`可能需要满足一定条件,比如“鼠标点击的时候”。 +`Observable`可以`return`任意多次,每次`return`可能需要满足一定条件,比如“鼠标点击的时候”。 可是,怎么可能`return`多于1次呢? 这是伪代码,其实`Observable`应该是这样: @@ -156,14 +156,17 @@ const FakeSubjectClass = function() { FakeSubjectClass.prototype.subscribe = function(observer) { let that = this; - // 添加新observer,添加之前会检查是否observers已经有了这个observer,如果有,就什么也不做 - if (that.observers.indexOf(observer) >= 0) return; - that.observers.push(observer); - return { - unsubscribe: () => { - // 从observers列表里将这个observer删除 + let subscription = { + unsubscribe: () => { // unsubsribe要做的就是从observers列表里将这个observer删除 that.observers = that.observers.filter((observerX) => observerX !== observer) } + }; + // 添加新observer,添加之前会检查是否observers已经有了这个observer,如果有,就直接返回subscription + if (that.observers.indexOf(observer) >= 0) { + return subscription; + } else { + that.observers.push(observer); + return subscription; } } @@ -180,7 +183,7 @@ x$$.subscribe(observerB); // 这个observerB被加到了x$$的observers列表里 x$.subscribe(x$$); // 当x$向外推送时,调用的是x$$.next;x$$.next转身马上就forEach转给它的observers。 ``` 顺带提一下`unicast`和`multicast`的资源消耗。 -说`Observable`是`unicast`,而`Subject`是`multicast`,就是因为这个`observers列表` -- 在`Observable`里是没有的这个列表的。 +说`Observable`是`unicast`,而`Subject`是`multicast`,就是因为这个`observers列表` -- 在`Observable`里没有这个属性。 每次运行`Observable.subscribe()`都相当于一个`Function.call()`,是一个独立的运行,需要单独消耗资源。 而`Subject.subscribe()`消耗资源很少。 比如: From 68289063e24f5332f6ac0a7febdb37ae9e1a07f9 Mon Sep 17 00:00:00 2001 From: twincle Date: Tue, 15 Nov 2016 17:35:05 +0800 Subject: [PATCH 057/177] =?UTF-8?q?*=20=E8=B0=83=E6=95=B4=E9=83=A8?= =?UTF-8?q?=E5=88=86=E6=96=87=E5=8F=A5=EF=BC=8C=E4=BF=AE=E6=AD=A3=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E4=BB=A3=E7=A0=81=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 89 ++++++++++++++----- 1 file changed, 65 insertions(+), 24 deletions(-) diff --git "a/src/app/_shared/api/articles/270.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[2]/_index.md" "b/src/app/_shared/api/articles/270.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[2]/_index.md" index 6e13db5..fbfa56a 100644 --- "a/src/app/_shared/api/articles/270.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[2]/_index.md" +++ "b/src/app/_shared/api/articles/270.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[2]/_index.md" @@ -12,33 +12,79 @@ # 二、升级service/factory/provider -> 关于service、factory、provider:相信你在使用ng1的时候一定对这三个概念产生过困惑,网上也有很多相关文章讨论三者之间的差别和联系。但稍微深入研究一下就会知道,这三者本质相同,只是做了不同的语法糖包装。本文以service为例完成升级过程。 +> 关于service、factory、provider:在ng1中,我们可以通过`angular.Module`的这三个方法,来创建自己的服务,并将这些组件注册在ng1环境中,今后通过依赖注入的方式在项目中使用。相信你在使用ng1的时候一定对这三个概念产生过困惑,网上也有很多相关文章讨论三者之间的差别和联系。但稍微深入研究一下就会知道,这三者本质相同,只是做了不同的语法糖包装。本文以service为例完成升级过程。 + +> 扩展阅读,源码探索:上述三者的关系,也可以通过ng1的源代码来更清楚的了解,源码地址:[https://github.com/angular/angular.js/blob/v1.5.8/src/auto/injector.js#L688](https://github.com/angular/angular.js/blob/v1.5.8/src/auto/injector.js#L688)(适用于ng1.5.8,不同版本行号可能有所变化)。简单来说,使用factory需要你返回一个对象,对象的属性可以被外部访问到;使用service需要你定义一个构造函数,在依赖注入时ng1会自动使用`new`关键字调用构造函数并返回对象,因此在创建过程中可以使用`this`关键字设置类的属性和方法;使用provider则要将外部访问的属性和方法定义在`$get`属性上。 首先来定义一个项目中用到的service: -``` +```JavaScript // user.service.js // 一个简单的service,用来获取用户列表 app.service('UserService', ['$http', function ($http) { - var service = {}; - + // 这里假定了一个api地址:/user + this.listUser = function () { + return $http.get('/user').then(function (res) { + return res.data; + }); + }; + +}]); +``` + +> 这里也提供使用factory和provider创建`UserService`的代码版本,供大家参考。 + +```JavaScript +// user.service.js +// 使用factory方法创建UserService + +app.factory('UserService', ['$http', function ($http) { + + // 定义一个对象 + var service = {}; + service.listUser = function () { return $http.get('/user').then(function (res) { return res.data; }); }; + // 返回这个对象 return service; + +}]); +``` + +```JavaScript +// user.service.js +// 使用provider方法创建UserService + +app.provider('UserService', ['$http', function ($http) { + + // 需要将外部调用的属性和方法定义在$get方法中 + this.$get = function () { + var service; + service.listUser = function () { + return $http.get('/user').then(function (res) { + return res.data; + }); + }; + return service; + }; + }]); ``` +> 从代码中也可以看出来,除了创建服务的过程中使用的语法不同,但其核心业务代码并没有区别。 +> 一句话总结一下:factory是provider的$get属性,而service是生成factory所返回的对象的构造函数。 + ## 1、分离框架代码和业务代码 与controller的升级类似,我们先将业务代码剥离成一个单独的文件,并将所有注册service代码集中到一个文件中。 -``` +```JavaScript // app-service.js // 这个文件专门用来注册所有的service @@ -51,15 +97,13 @@ app.service('UserService', ['$http', userService]) // user.service.js var userService = function ($http) { - var service = {}; - service.listUser = function () { + this.listUser = function () { return $http.get('/user').then(function (res) { return res.data; }); }; - - return service; + }; ``` @@ -67,13 +111,13 @@ var userService = function ($http) { ## 2、根据最佳实践处理依赖 -但是和controller不同的是,这个service中所依赖的`$http`并不像`$scope`一样可以通过某种语法,从方法中完全解耦,有时候我们也必须面对这个事实,一些框架相关的API确实必须一定程度的参与到业务代码中。 +和controller不同的是,这个service中所依赖的`$http`并不像`$scope`一样可以通过某种语法(例如`as`语法),从function中完全解耦,有时候我们也必须面对这个事实,一些框架相关的API确实必须一定程度的参与到业务代码中。 -不过好在这个依赖是通过DI的方式注入到方法中,方法也并没有直接对ng1产生依赖,因此到这里为止,关于`$http`这个依赖就这样处理也无伤大雅。 +好在`$http`是ng1中内置的服务,和所有其他服务一样,这个依赖可以通过DI的方式注入到方法中,方法也并没有直接对ng1产生依赖,因此到这里为止,对于`$http`这个服务的依赖就这样处理也无伤大雅。 -不过编写代码我们总希望能够尽可能优化代码。 +不过编写代码我们总希望能够尽可能优化代码,目前为止代码还有进一步优化的空间。 -这里我们会发现一个问题,如果今后`userService`的依赖,除了`$http`外又增加了`$log`依赖,这时你就必须同时修改`app-service.js`文件和`user.service.js`文件两个文件。一处调整涉及到两处修改并不符合最佳实践。设想在多人团队合作的项目中,不同人负责的多个service代码都调整了依赖内容,则会导致`app-service.js`文件被多个人同时修改,在通过版本控制软件提交时也会增加代码review的难度。 +试想这样一个问题,如果今后`userService`的依赖,除了`$http`外又增加了`$log`依赖,这时你就必须同时修改`app-service.js`文件和`user.service.js`文件两个文件。一处调整涉及到两处修改并不符合最佳实践。设想在多人团队合作的项目中,不同人负责的多个service代码都调整了依赖内容,则会导致`app-service.js`文件被多个人同时修改,在通过版本控制软件提交时也会增加代码review的难度。 > 最佳实践:我们希望将service的依赖内容与service代码放在同一处,减少依赖调整所带来的文件修改数量,这也一定程度上符合高内聚和单一职责原则。 @@ -81,21 +125,18 @@ ng1为我们提供了一种实现方式:`$inject`。(官方文档:[https:/ 简单来说,我们将一个__字符串数组__作为`$inject`属性赋值给一个方法,ng1就会按照数组中的字符串对方法注入依赖,我们来看一下代码: -``` +```JavaScript // user.service.js // 这里我们假设service增加了一个$log依赖 var userService = function ($http, $log) { - var service = {}; - - service.listUser = function () { + this.listUser = function () { return $http.get('/user').then(function (res) { return res.data; }); }; - return service; }; // 这里使用$inject属性对service注入依赖 @@ -106,7 +147,7 @@ userService.$inject = ['$http', '$log']; 同时注册service的代码也可以做相应的简化: -``` +```JavaScript // app-service.js // 由于在service文件中已经声明了service所需要的依赖,因此这里直接将service方法作为参数即可 @@ -122,7 +163,7 @@ app.service('UserService', userService) 和之前一样,我们也需要将es3代码升级为typescript代码。 -``` +```TypeScript // user.service.ts // 原来的service方法以class的方式定义 @@ -149,7 +190,7 @@ export default class UserService { } ``` -``` +```TypeScript // app-service.ts import app from './app'; @@ -167,7 +208,7 @@ app.service('UserService', userService) 升级前的重构准备工作都做完了,升级至ng2就指日可待啦。 -``` +```TypeScript // user.service.ts import { Http, Response } from '@angular/http'; @@ -211,7 +252,7 @@ export default class UserService { 这时你可以通过这样来实现: -``` +```TypeScript let someValue : any = { foo : 'bar' }; export default someValue; @@ -219,7 +260,7 @@ export default someValue; 或者这样: -``` +```TypeScript const PI = 3.1415926; export default PI; From effbb30cd7869a4319488ed69782a959fbe1dbf2 Mon Sep 17 00:00:00 2001 From: lhtin Date: Wed, 16 Nov 2016 14:01:51 +0800 Subject: [PATCH 058/177] add --- src/app/_shared/api/articles/index.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 49b89c0..7cb27f1 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -307,6 +307,15 @@ const items: Article[] = [ content: require('./270.构建流式应用—RxJS详解/_index.md'), tags: ['RxJS'], authors: ['joeyguo'], + }, + { + id: 'simple-rxjs', + title: '白话RxJS', + summary: '本文将尝试用白话来解读RxJS。', + content: require('./timliu/simple-rxjs/_index.md'), + first: true, + tags: ['rxjs'], + authors: ['timliu'], } ]; From f77d34f289ff4e4e74dcb371196899d3867c1fcf Mon Sep 17 00:00:00 2001 From: Tin Date: Wed, 16 Nov 2016 14:03:39 +0800 Subject: [PATCH 059/177] Update index.ts --- src/app/_shared/api/articles/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 7cb27f1..65541d8 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -312,7 +312,7 @@ const items: Article[] = [ id: 'simple-rxjs', title: '白话RxJS', summary: '本文将尝试用白话来解读RxJS。', - content: require('./timliu/simple-rxjs/_index.md'), + content: require('./simple-rxjs/_index.md'), first: true, tags: ['rxjs'], authors: ['timliu'], From 405336866599dfecc44159434a79b8a49c3a316d Mon Sep 17 00:00:00 2001 From: twincle Date: Thu, 17 Nov 2016 01:42:29 +0800 Subject: [PATCH 060/177] =?UTF-8?q?*=20=E4=BF=AE=E5=A4=8D=E4=B8=80?= =?UTF-8?q?=E5=A4=84=E4=BB=A3=E7=A0=81=E7=AC=94=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git "a/src/app/_shared/api/articles/270.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[2]/_index.md" "b/src/app/_shared/api/articles/270.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[2]/_index.md" index fbfa56a..a9997a0 100644 --- "a/src/app/_shared/api/articles/270.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[2]/_index.md" +++ "b/src/app/_shared/api/articles/270.\344\273\216ng1\345\210\260ng2\347\232\204\345\271\263\346\273\221\345\215\207\347\272\247[2]/_index.md" @@ -18,7 +18,7 @@ 首先来定义一个项目中用到的service: -```JavaScript +```javascript // user.service.js // 一个简单的service,用来获取用户列表 @@ -36,7 +36,7 @@ app.service('UserService', ['$http', function ($http) { > 这里也提供使用factory和provider创建`UserService`的代码版本,供大家参考。 -```JavaScript +```javascript // user.service.js // 使用factory方法创建UserService @@ -57,7 +57,7 @@ app.factory('UserService', ['$http', function ($http) { }]); ``` -```JavaScript +```javascript // user.service.js // 使用provider方法创建UserService @@ -84,7 +84,7 @@ app.provider('UserService', ['$http', function ($http) { 与controller的升级类似,我们先将业务代码剥离成一个单独的文件,并将所有注册service代码集中到一个文件中。 -```JavaScript +```javascript // app-service.js // 这个文件专门用来注册所有的service @@ -125,7 +125,7 @@ ng1为我们提供了一种实现方式:`$inject`。(官方文档:[https:/ 简单来说,我们将一个__字符串数组__作为`$inject`属性赋值给一个方法,ng1就会按照数组中的字符串对方法注入依赖,我们来看一下代码: -```JavaScript +```javascript // user.service.js // 这里我们假设service增加了一个$log依赖 @@ -147,7 +147,7 @@ userService.$inject = ['$http', '$log']; 同时注册service的代码也可以做相应的简化: -```JavaScript +```javascript // app-service.js // 由于在service文件中已经声明了service所需要的依赖,因此这里直接将service方法作为参数即可 @@ -163,7 +163,7 @@ app.service('UserService', userService) 和之前一样,我们也需要将es3代码升级为typescript代码。 -```TypeScript +```typescript // user.service.ts // 原来的service方法以class的方式定义 @@ -190,7 +190,7 @@ export default class UserService { } ``` -```TypeScript +```typescript // app-service.ts import app from './app'; @@ -208,7 +208,7 @@ app.service('UserService', userService) 升级前的重构准备工作都做完了,升级至ng2就指日可待啦。 -```TypeScript +```typescript // user.service.ts import { Http, Response } from '@angular/http'; @@ -220,7 +220,7 @@ import { Observable } from 'rxjs'; // 如果没有定义,后面的User类型使用any来暂时代替也尚无不可 import User from './user.model'; -@Injectable +@Injectable() export default class UserService { // 这里不再使用ng1的注入方式,而通过在AppModule注解的imports属性引入HttpModule @@ -252,7 +252,7 @@ export default class UserService { 这时你可以通过这样来实现: -```TypeScript +```typescript let someValue : any = { foo : 'bar' }; export default someValue; @@ -260,7 +260,7 @@ export default someValue; 或者这样: -```TypeScript +```typescript const PI = 3.1415926; export default PI; From 71403fc531a590845fb247883e83b098d8c645bf Mon Sep 17 00:00:00 2001 From: lhtin Date: Fri, 18 Nov 2016 13:49:28 +0800 Subject: [PATCH 061/177] add: article topics --- README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.md b/README.md index a2b5e8b..b1d8a73 100644 --- a/README.md +++ b/README.md @@ -30,3 +30,22 @@ Angular中文社区热烈欢迎各位投稿。延续程序员的光荣传统, 然后,请找到`src/app/_shared/api/authors`目录,把你的个人简介(含靓照)放进去,你就是正式的作者了,用户看到你的名字可以点进去查看详情。 最后,如果你想创建自己的专栏,请找到`src/app/_shared/api/columns`目录,编辑`index.ts`,添加你的专栏简介。当然,专栏是一种荣誉,专栏的文章有质量和数量的要求,如果你创建了专栏,我以后可能会追着你催稿哦,不过这都是小意思,对吧! + +## 写文章参考方向 + +大方向:**只要是对用Angular 2做开发有用的,不一定局限在ng2** + +具体方向: + +- Angular2基本概念的介绍(各个功能的解析、组件、依赖注入、模块化、及其相关的历史、小demo展示某个概念) +- RxJS基本概念的介绍(异步、处理异步的方式、及其相关历史、小demo展示某个概念) +- TypeScript/JavaScript语言相关内容(TS语言的基础知识、TS编译器的使用、浏览器相关、小demo展示等) +- 面向对象/函数式编程相关(模式、优缺点分析、最佳实践) +- 构建工具介绍(如何使用各种构建工具打包、原理是啥、angular-cli、webpack) +- Angular2的change log的实时翻译和解释(新特性) +- 工程化相关的实践(构建、打包、发布、调试) +- 优化实践(懒加载、预加载、体积优化、预编译、服务器端渲染等) +- 新的技术和框架分析 +- 前端/全栈协作方式 +- 踩的坑及解决方法 +- 编程复杂度的处理 From 902cc89c316039c42ee74dec7dbd7d9f5da4da08 Mon Sep 17 00:00:00 2001 From: xiedapao <846432362@qq.com> Date: Sat, 19 Nov 2016 17:00:33 +0800 Subject: [PATCH 062/177] =?UTF-8?q?=E5=A6=82=E4=BD=95=E5=B7=A5=E7=A8=8B?= =?UTF-8?q?=E5=8C=96=E5=BC=80=E5=8F=91=E5=A4=A7=E5=9E=8Bng2=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 72 ++++++++++++++++++ .../git.png" | Bin 0 -> 151820 bytes src/app/_shared/api/articles/index.ts | 9 +++ .../authors/67.\345\244\247\347\202\256.md" | 3 + src/app/_shared/api/authors/index.ts | 11 ++- 5 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 "src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" create mode 100644 "src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/git.png" create mode 100644 "src/app/_shared/api/authors/67.\345\244\247\347\202\256.md" diff --git "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" new file mode 100644 index 0000000..b3bddb2 --- /dev/null +++ "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" @@ -0,0 +1,72 @@ +如何工程化开发大型angular2项目(上篇) +=================== +### 前请提要: + 说到前端工程化开发,市面上丰富的工具链都大大提升大家的开发效率,webpack,gulp,ng2自带的ng cli等等工具。从开始构建项目,实时编译scss,代码打包,压缩,混淆,文件名打时间戳等等工作。这些只是项目构建到上线的工作流 + 。以及如何引入第三方库以及样式库,开发环境与编译环境的配置分离,多个开发人员开发同一项目因提交自己开发环境的配置文件引发冲突。这些不仅仅是开发大型angular2应用会遇到的问题,也是其他大型项目会遇到的问题。另外多人开发 + 会存在代码风格不同一,review时异常痛苦的问题。为什么程序员聪明,因为程序员懒,懒到想一切利用工具去解决。所以下面是我开发angular2项目时遇到的一些问题以及自己的一些解决方案以及项目管理的思路。 + +### 项目构建篇: + angular2官方提供ng cli构建工具,但是投入使用后发现并不是符合我们需求。因为我们之前项目是基于gulp整套工作流,所以一直在寻找与gulp相结合的ng2案例。后来找到一个angular-seed项目,于是我将该项目设立为种子项目,依据 + 该种子项目我们开发了7、8个angular2项目。下面简单介绍一下如何利用种子库创建衍生库,只要种子库保持更新,其他库可以同步保持更新. + +##### 建立种子库: +![管理流程图](./git.png) + +上面的图画得比较烂,我还是来好好解释一下。首先我们得有一个主心库,这个库十分重要,里面没有业务逻辑的代码,主要是平时开发时所需要的所有脚本,以及npm的一些基本依赖。另外一些共用组件,共用逻辑代码(例如登录验证等等)。主心库创 +立完后,我们需要建立一个upstream的远端指向angular-seed项目 +``` +git remote add upstream https://github.com/mgechev/angular-seed.git +git pull upstream master +``` +平时我们想要更新主仓库时,只要git pull以下upstram远端,就可以保持最新了。如果不想人工手动去更新的化可以交给jenkins定时去更新,这样主心仓库永远是最新的了。 +#### 创建衍生库: +因为我们所有项目围绕主心库而衍生出来的,所以衍生库和主心库的关心和angular-seed关系一致。我们指定我们衍生库的远端upstream为我们的主心库,这样只要主心库是最新的,这样所有衍生库都可以保持同步更新。可以享受主心库提供的共用配置和 +业务逻辑。看上去过程比较繁琐,其实只需要将整个操作过程的指令集合到bash脚本中,执行脚本是指定参数名为你的项目名称。这样快速就可以构建一个angular2项目,所以整套流程适合有复杂业务的项目。 +``` +git remote add upstream git@192.168.1.1:/git/main-base +git pull upstream master +``` + +### 项目开发篇: + 既然我们构建完项目后,那么马上开工吧。随着前端项目越来越复杂,里面配置文件越来越多。因为开发环境和生产环境需要调用服务端接口地址又是不一样的,像我开发微信项目的,开发环境用测试的appid和生产环境的appid也是不一样的。情况更严重 + 的是我们每个客户都有自己独立的配置信息(所以开始考虑多租户模式,不然下去是大坑)。 + 理想情况下: + +``` + gulp build.dev --color --env-config dev +``` + 执行上述命令,就是启动开发dev环境的配置。利用yargs这个node工具去接收我们传递过去的参数,以此来区分开是开发模式下还是prod模式下。下面贴一段代码举例一下: + +``` + import { argv } from 'yargs'; + ... + export function templateLocals() { + // 这里就是我们通过env-config变量获取参数 + const configEnvName = argv['env-config'] || argv['config-env'] || 'dev'; + const configPath = Config.getPluginConfig('environment-config'); + const baseConfig = getConfig(configPath, 'base'); + // 依据dev和prod以及对应的路径获取对应的配置文件 + const config = getConfig(configPath, configEnvName); + + if (!config) { + throw new Error('Invalid configuration name'); + } + + return Object.assign(Config, { + ENV_CONFIG: JSON.stringify(Object.assign(baseConfig, config)) + }); + } + // 具体代码可以克隆angular-seed去查看 +``` + 另外angular2提供接口能够优化打包出来的代码enableProdMode,但是我们开发时是不需要用到该接口如何去分离开来呢?gulp有个好插件,完美解决该问题,[gulp-template](https://www.npmjs.com/package/gulp-template)。我们只要在我们 + 代码中加入类似<%= BUILD_TYPE %>,这样就可以赋值给BUILD_TYPE,我们可以合理得去控制。 +``` + import { enableProdMode } from '@angular/core'; + ... + if (String('<%= BUILD_TYPE %>') === 'prod') { enableProdMode(); } +``` + 关于开发配置十分细碎,所以不做详述,可以日后咨询。 + +### 下篇预告: + 下篇会涉及项目目录结构管理,以及angular2在移动端开发的经验,项目打包上线的经验 + ps: 正在寻找新的工作机会,感兴趣的朋友加我QQ: 846432362 diff --git "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/git.png" "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/git.png" new file mode 100644 index 0000000000000000000000000000000000000000..1342cd19e25ddf325652577aec3d89fe7377020c GIT binary patch literal 151820 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
    IZuq4t1<0l8t+FxS*L#l47QRZ{9R`-|N2k| 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

    g!c*&n>kr$CZ9G-{Pri? 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 literal 0 HcmV?d00001 diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 6cb33ce..e064c98 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -246,6 +246,15 @@ const items: Article[] = [ tags: ['现在'], authors: ['雪狼'], }, + { + id: '如何工程化开发大型angular2项目', + title: '如何工程化开发大型angular2项目', + summary: 'angular2刚出不久,很多技术主管在观望是否要把angular2投入生存环境,作为一名作死者,从今年3月就投入生存环境,8个月来挖坑经验告诉你,绝对没问题。已经百家大型客户投入使用!', + content: require('./230.如何工程化开发大型angular2项目/_index.md'), + first: true, + tags: ['现在'], + authors: ['大炮'], + }, ]; @Injectable() diff --git "a/src/app/_shared/api/authors/67.\345\244\247\347\202\256.md" "b/src/app/_shared/api/authors/67.\345\244\247\347\202\256.md" new file mode 100644 index 0000000..5a911a7 --- /dev/null +++ "b/src/app/_shared/api/authors/67.\345\244\247\347\202\256.md" @@ -0,0 +1,3 @@ +- 一个拉网线专业毕业(通信工程),误打误撞进入前端行业。硬是用硬件编程理解爱上了前端 +- 爱好广泛,深度学习,虚拟货币。 +- [个人知乎主页](https://www.zhihu.com/people/nong-chao-er-xiao-bin) diff --git a/src/app/_shared/api/authors/index.ts b/src/app/_shared/api/authors/index.ts index 830c575..a278fad 100644 --- a/src/app/_shared/api/authors/index.ts +++ b/src/app/_shared/api/authors/index.ts @@ -50,6 +50,15 @@ const items: Author[] = [ avatar: require('./_images/250.丁乐华.jpg'), columnist: false, homepage: 'https://github.com/lhtin' + }, + { + id: 'dapao', + name: '大炮', + bio: '上天不要移開險峻,請賜予吾攀登之力', + description: require('./67.大炮.md'), + avatar: require(''), + columnist: false, + homepage: 'https://github.com/btcioner/About-ME' } ]; @Injectable() @@ -97,7 +106,7 @@ export class AuthorApi { // authoer found, item = author item = items[index]; } - + return Observable.of(item) } From c47e19a99bfa858e3aaa6d2f35b113ccfe1863f6 Mon Sep 17 00:00:00 2001 From: JohnnyTam Date: Sat, 19 Nov 2016 22:09:35 +0800 Subject: [PATCH 063/177] =?UTF-8?q?=E6=8A=95=E7=A8=BF=EF=BC=9A=20=E5=A6=82?= =?UTF-8?q?=E4=BD=95=E4=BC=98=E9=9B=85=E5=8D=87=E7=BA=A7ng2=E5=B0=8F?= =?UTF-8?q?=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 212 ++++++++++++++++++ ...0.\346\234\250\344\270\201\347\263\226.md" | 2 + .../\346\234\250\344\270\201\347\263\226.jpg" | Bin 0 -> 43012 bytes src/app/_shared/api/authors/index.ts | 9 + 4 files changed, 223 insertions(+) create mode 100644 "src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" create mode 100644 "src/app/_shared/api/authors/270.\346\234\250\344\270\201\347\263\226.md" create mode 100644 "src/app/_shared/api/authors/_images/\346\234\250\344\270\201\347\263\226.jpg" diff --git "a/src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" "b/src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" new file mode 100644 index 0000000..52c3179 --- /dev/null +++ "b/src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" @@ -0,0 +1,212 @@ + +# 前言 +前几天在Angular中文社区群里,有小伙伴询问ng项目升级,出现N多的 `Peer Dependencies`错误,吐槽很是影响coding心情。私下询问,发现对package文件中的版本号有点误会,我之前也遇到类似问题,在此做个小结。 +这里的升级不是指ng1如何升级到ng2,仅以angular 2.0.1升级到当前2.2.0的时候需要注意的小细节。想了解 如何从ng1升级到ng2,请参考公众号之前文章[从ng1到ng2的平滑升级](./articles/260.从ng1到ng2的平滑升级[1]/_index.md) + +# 目标 +## 1. package文件版本号前面的符号有什么鬼? +## 2. 如何从ng2.0.1 优雅升级到 ng2.2.0(当前最新) + +# package依赖包版本号 +先来了解下package.json文件依赖包中常见的标点符号。这里,仅涉及如下符号: `^` `~` `>=` `<= ` + +### 只有版本号 +package.json中,版本号如下: +举栗子: "@angular/core": "2.0.1" +什么鬼: 安装指定版本 + +### 符号 `^` +举栗子: "@angular/core": "^2.0.1" +什么鬼: 安装该版本以及比该版本更新的版本,如: `2.0.1` , `2.0.2`, `2.1.0`, `2.7.0`, 但是,**3.x.x不会安装** + +### 符号`~` +举栗子: "@angular/core": "~2.0.1" +什么鬼: 只能安装 `2.0.1`, `2.0.2`, ... `2.0.9` 但是, **2.1.0就不可以了** + +### 符号 `>= <=` +更有者,可以使用如下形式: >= ... <= +"@angular/core": ">=2.0.1<=3.0.0" +什么鬼: 表示安装的版本是在 2.0.2到3.0.0之前的,上下边界也在内。 + +# 优雅升级常用npm命令 +上述仅是package.json涉及内容的几小点,更多内容,参考npmjs官方文档 [Specifics of npm's package.json handling](https://docs.npmjs.com/files/package.json) 和 [The semantic versioner for npm](https://docs.npmjs.com/misc/semver) +接下来,开始我们的优雅之旅吧!以我自己的ng2入门项目[ng2-starter-webpack](https://github.com/tancolo/angular2/tree/master/ng2-starter-webpack)项目为例子说明,如何优雅升级ng2小版本。 +一句话总结升级步骤: ** 看版本,查依赖,修json,再重复。** + +**package.json 文件内容:** +``` +"dependencies": { + "@angular/common": "2.0.1", + "@angular/compiler": "2.0.1", + "@angular/core": "2.0.1", + "@angular/forms": "2.0.1", + "@angular/http": "2.0.1", + "@angular/platform-browser": "2.0.1", + "@angular/platform-browser-dynamic": "2.0.1", + "@angular/router": "3.0.1", + "@angular/upgrade": "2.0.1", + "angular-in-memory-web-api": "0.1.1", + "bootstrap": "3.3.5", + "core-js": "2.4.1", + "reflect-metadata": "0.1.6", + "rxjs": "5.0.0-beta.12", + "zone.js": "0.6.23" + }, + "devDependencies": { + "html-webpack-plugin": "^2.24.1", + "ts-loader": "^0.9.5", + "typescript": "^2.0.6", + "typings": "^1.5.0", + "webpack": "^1.13.3", + "webpack-dev-server": "^1.16.2" + } +``` + +很显然,ng2包不是最新的,想升级到最新的依赖包,并且尽量避免在升级过程中出现error, 需要如下步骤。 +注意,按照上面的package.json文件,`npm install`会出现问题,莫慌,挖的一个小坑! + +``` +`-- UNMET PEER DEPENDENCY zone.js@0.6.23 +``` +原因是 为了演示错误,有意降低了 zone.js的版本,正确版本是 **0.6.25** + +## npm list --depth 0 +**看版本** +查看当前项目package所记录的依赖包版本, 小伙伴们常用的是 `npm list`, 它的缺点是冗长,`npm list --depth 0`不会展开依赖包所需的依赖包版本。 +``` +$ npm list --depth 0 +ng2-starter-webpack@0.0.1 E:\Project_Dev\Angularjs2\ng2-starter-webpack ++-- @angular/common@2.0.1 ++-- @angular/compiler@2.0.1 ++-- @angular/core@2.0.1 ++-- @angular/forms@2.0.1 ++-- @angular/http@2.0.1 ++-- @angular/platform-browser@2.0.1 ++-- @angular/platform-browser-dynamic@2.0.1 ++-- @angular/router@3.0.1 ++-- @angular/upgrade@2.0.1 ++-- angular-in-memory-web-api@0.1.1 ++-- bootstrap@3.3.5 ++-- core-js@2.4.1 ++-- html-webpack-plugin@2.24.1 ++-- reflect-metadata@0.1.6 ++-- rxjs@5.0.0-beta.12 ++-- ts-loader@0.9.5 ++-- typescript@2.0.10 ++-- typings@1.5.0 ++-- webpack@1.13.3 ++-- webpack-dev-server@1.16.2 +`-- UNMET PEER DEPENDENCY zone.js@0.6.23 + +npm ERR! peer dep missing: zone.js@^0.6.25, required by angular-in-memory-web-api@0.1.1 + +``` + +注意,其中的npm Error: angular-in-memory-web-api@0.1.1需要的zone.js版本是 `0.6.25`, 所以导致出现了错误,这也是常见的 `peer dependencies` 问题。 +``` +npm ERR! peer dep missing: zone.js@^0.6.25, required by angular-in-memory-web-api@0.1.1 +``` + +只要修改为正确的版本`0.6.25`即可! + + +## npm outdated +该命令是查询当前package中有哪些依赖包是过时的,为升级做好准备。 结果如下 +``` +$ npm outdated +Package Current Wanted Latest Location +@angular/common 2.0.1 2.0.1 2.2.0 ng2-starter-webpack +@angular/compiler 2.0.1 2.0.1 2.2.0 ng2-starter-webpack +@angular/core 2.0.1 2.0.1 2.2.0 ng2-starter-webpack +@angular/forms 2.0.1 2.0.1 2.2.0 ng2-starter-webpack +@angular/http 2.0.1 2.0.1 2.2.0 ng2-starter-webpack +@angular/platform-browser 2.0.1 2.0.1 2.2.0 ng2-starter-webpack +@angular/platform-browser-dynamic 2.0.1 2.0.1 2.2.0 ng2-starter-webpack +@angular/router 3.0.1 3.0.1 3.2.0 ng2-starter-webpack +@angular/upgrade 2.0.1 2.0.1 2.2.0 ng2-starter-webpack +angular-in-memory-web-api 0.1.1 0.1.1 0.1.15 ng2-starter-webpack +bootstrap 3.3.5 3.3.5 3.3.7 ng2-starter-webpack +reflect-metadata 0.1.6 0.1.6 0.1.8 ng2-starter-webpack +rxjs 5.0.0-beta.12 5.0.0-beta.12 5.0.0-rc.3 ng2-starter-webpack +ts-loader 0.9.5 0.9.5 1.2.1 ng2-starter-webpack +typescript 2.0.10 2.1.1 2.0.10 ng2-starter-webpack +typings 1.5.0 1.5.0 2.0.0 ng2-starter-webpack +zone.js 0.6.25 0.6.25 0.6.26 ng2-starter-webpack + +``` +一目了然,当前的version, 最新的version。 + +不要猴急把package中的版本号都替换为最新的,要考虑依赖的问题。ng2的core依赖rxjs.js, zone.js, 把ng2升级到`2.2.0`,是否有必要把rxjs 或 zone.js升级为最新的版本呢? 也不一定。 + + +## npm view xxxpackage/xxx@x.x.x peerDependencies +**查依赖** +该命令告诉我们,具体某个包的依赖关系。 +``` +$ npm view @angular/core@2.2.0 peerDependencies +{ rxjs: '5.0.0-beta.12', 'zone.js': '^0.6.21' } +``` +以查看 **@angular/core@2.2.0** 为例,它依赖 ** { rxjs: '5.0.0-beta.12', 'zone.js': '^0.6.21' } **, 也就是说升级**@angular/core** 到 ** 2.2.0 ** 没有必要升级rxjs, zone.js版本,即使他们有更新的版本。 + +再看一个依赖包: ** angular-in-memory-web-api@0.1.1 ** + +``` +$ npm view angular-in-memory-web-api@0.1.1 peerDependencies + +{ '@angular/core': '^2.0.0', + '@angular/http': '^2.0.0', + 'reflect-metadata': '^0.1.3', + rxjs: '5.0.0-beta.12', + 'zone.js': '^0.6.25' } + +``` +以上说明,当升级ng2相关库为 2.2.0的时候,可以不用升级 ** angular-in-memory-web-api@0.1.1 ** + +但是,修改完成 ng相关库为 2.2.0后,再次执行 npm install, 还是有错误 +``` +$ npm list --depth 0 +ng2-starter-webpack@0.0.1 E:\Project_Dev\Angularjs2\ng2-starter-webpack ++-- UNMET PEER DEPENDENCY @angular/common@2.2.0 ++-- @angular/compiler@2.2.0 ++-- UNMET PEER DEPENDENCY @angular/core@2.2.0 ++-- @angular/forms@2.2.0 ++-- @angular/http@2.2.0 ++-- UNMET PEER DEPENDENCY @angular/platform-browser@2.2.0 ++-- @angular/platform-browser-dynamic@2.2.0 ++-- @angular/router@3.0.1 ++-- @angular/upgrade@2.2.0 ++-- angular-in-memory-web-api@0.1.1 ++-- bootstrap@3.3.5 ++-- core-js@2.4.1 ++-- html-webpack-plugin@2.24.1 ++-- reflect-metadata@0.1.6 ++-- rxjs@5.0.0-beta.12 ++-- ts-loader@0.9.5 ++-- typescript@2.0.10 ++-- typings@1.5.0 ++-- webpack@1.13.3 ++-- webpack-dev-server@1.16.2 +`-- zone.js@0.6.25 + +npm ERR! peer dep missing: @angular/common@2.0.1, required by @angular/router@3.0.1 +npm ERR! peer dep missing: @angular/core@2.0.1, required by @angular/router@3.0.1 +npm ERR! peer dep missing: @angular/platform-browser@2.0.1, required by @angular/router@3.0.1 + +``` +本次是angular/router的版本太低了,@3.0.1 要求ng相关库是2.0.1, 2.2.0无法使用,所以需要升级angular/router 为3.2.0 + +## 修改,重复 +上述的** 看版本,查依赖,修json ** 可能会重复多次,完成后,测试的工作也不能少,至少主流程要走一遍,确保升级不会导致出现运行问题。 + +# 小结 +升级版本是个细致的活儿,需要科学的方法。否则容易出现问题,脑壳都会抓掉。再次总结下一般步骤吧! +### step 1 看版本 +npm list --depth 0 +npm outdated + +### step 2 查看依赖 +npm view xxxpackage/xxx@x.x.x peerDependencies + +### step 3 修json +### step 4 再重复 + diff --git "a/src/app/_shared/api/authors/270.\346\234\250\344\270\201\347\263\226.md" "b/src/app/_shared/api/authors/270.\346\234\250\344\270\201\347\263\226.md" new file mode 100644 index 0000000..bf4b96a --- /dev/null +++ "b/src/app/_shared/api/authors/270.\346\234\250\344\270\201\347\263\226.md" @@ -0,0 +1,2 @@ +- ng爱好者 +- Android从业者 \ No newline at end of file diff --git "a/src/app/_shared/api/authors/_images/\346\234\250\344\270\201\347\263\226.jpg" "b/src/app/_shared/api/authors/_images/\346\234\250\344\270\201\347\263\226.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..7311408a7f1ed7915b39570873592d0bd303e7d5 GIT binary patch literal 43012 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

    jn%f_Qv)V~%qy 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%0AY-RmuA!7+my?dQI>OQp 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 ainxf3^jaJ4iYTfQ+#BwSD58Lt=l|LKhQa#) literal 0 HcmV?d00001 diff --git a/src/app/_shared/api/authors/index.ts b/src/app/_shared/api/authors/index.ts index b6925fc..42f61db 100644 --- a/src/app/_shared/api/authors/index.ts +++ b/src/app/_shared/api/authors/index.ts @@ -69,6 +69,15 @@ const items: Author[] = [ columnist: false, homepage: 'https://twincle.github.io/' }, + { + id: '木丁糖', + name: '木丁糖', + bio: '爱好前端开发的Android白面猿', + description: require('./木丁糖.md'), + avatar: require('./_images/270.木丁糖.jpg'), + columnist: false, + homepage: 'http://www.jianshu.com/users/d614825bc8a1/latest_articles' + }, ]; @Injectable() export class AuthorApi { From a23d3ee435b2896622bbf2279f2cdb2837e538f1 Mon Sep 17 00:00:00 2001 From: JohnnyTam Date: Sat, 19 Nov 2016 22:09:35 +0800 Subject: [PATCH 064/177] =?UTF-8?q?=E6=8A=95=E7=A8=BF=EF=BC=9A=20=E5=A6=82?= =?UTF-8?q?=E4=BD=95=E4=BC=98=E9=9B=85=E5=8D=87=E7=BA=A7ng2=E5=B0=8F?= =?UTF-8?q?=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 212 ++++++++++++++++++ src/app/_shared/api/articles/index.ts | 9 + ...0.\346\234\250\344\270\201\347\263\226.md" | 2 + .../\346\234\250\344\270\201\347\263\226.jpg" | Bin 0 -> 43012 bytes src/app/_shared/api/authors/index.ts | 9 + 5 files changed, 232 insertions(+) create mode 100644 "src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" create mode 100644 "src/app/_shared/api/authors/270.\346\234\250\344\270\201\347\263\226.md" create mode 100644 "src/app/_shared/api/authors/_images/\346\234\250\344\270\201\347\263\226.jpg" diff --git "a/src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" "b/src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" new file mode 100644 index 0000000..52c3179 --- /dev/null +++ "b/src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" @@ -0,0 +1,212 @@ + +# 前言 +前几天在Angular中文社区群里,有小伙伴询问ng项目升级,出现N多的 `Peer Dependencies`错误,吐槽很是影响coding心情。私下询问,发现对package文件中的版本号有点误会,我之前也遇到类似问题,在此做个小结。 +这里的升级不是指ng1如何升级到ng2,仅以angular 2.0.1升级到当前2.2.0的时候需要注意的小细节。想了解 如何从ng1升级到ng2,请参考公众号之前文章[从ng1到ng2的平滑升级](./articles/260.从ng1到ng2的平滑升级[1]/_index.md) + +# 目标 +## 1. package文件版本号前面的符号有什么鬼? +## 2. 如何从ng2.0.1 优雅升级到 ng2.2.0(当前最新) + +# package依赖包版本号 +先来了解下package.json文件依赖包中常见的标点符号。这里,仅涉及如下符号: `^` `~` `>=` `<= ` + +### 只有版本号 +package.json中,版本号如下: +举栗子: "@angular/core": "2.0.1" +什么鬼: 安装指定版本 + +### 符号 `^` +举栗子: "@angular/core": "^2.0.1" +什么鬼: 安装该版本以及比该版本更新的版本,如: `2.0.1` , `2.0.2`, `2.1.0`, `2.7.0`, 但是,**3.x.x不会安装** + +### 符号`~` +举栗子: "@angular/core": "~2.0.1" +什么鬼: 只能安装 `2.0.1`, `2.0.2`, ... `2.0.9` 但是, **2.1.0就不可以了** + +### 符号 `>= <=` +更有者,可以使用如下形式: >= ... <= +"@angular/core": ">=2.0.1<=3.0.0" +什么鬼: 表示安装的版本是在 2.0.2到3.0.0之前的,上下边界也在内。 + +# 优雅升级常用npm命令 +上述仅是package.json涉及内容的几小点,更多内容,参考npmjs官方文档 [Specifics of npm's package.json handling](https://docs.npmjs.com/files/package.json) 和 [The semantic versioner for npm](https://docs.npmjs.com/misc/semver) +接下来,开始我们的优雅之旅吧!以我自己的ng2入门项目[ng2-starter-webpack](https://github.com/tancolo/angular2/tree/master/ng2-starter-webpack)项目为例子说明,如何优雅升级ng2小版本。 +一句话总结升级步骤: ** 看版本,查依赖,修json,再重复。** + +**package.json 文件内容:** +``` +"dependencies": { + "@angular/common": "2.0.1", + "@angular/compiler": "2.0.1", + "@angular/core": "2.0.1", + "@angular/forms": "2.0.1", + "@angular/http": "2.0.1", + "@angular/platform-browser": "2.0.1", + "@angular/platform-browser-dynamic": "2.0.1", + "@angular/router": "3.0.1", + "@angular/upgrade": "2.0.1", + "angular-in-memory-web-api": "0.1.1", + "bootstrap": "3.3.5", + "core-js": "2.4.1", + "reflect-metadata": "0.1.6", + "rxjs": "5.0.0-beta.12", + "zone.js": "0.6.23" + }, + "devDependencies": { + "html-webpack-plugin": "^2.24.1", + "ts-loader": "^0.9.5", + "typescript": "^2.0.6", + "typings": "^1.5.0", + "webpack": "^1.13.3", + "webpack-dev-server": "^1.16.2" + } +``` + +很显然,ng2包不是最新的,想升级到最新的依赖包,并且尽量避免在升级过程中出现error, 需要如下步骤。 +注意,按照上面的package.json文件,`npm install`会出现问题,莫慌,挖的一个小坑! + +``` +`-- UNMET PEER DEPENDENCY zone.js@0.6.23 +``` +原因是 为了演示错误,有意降低了 zone.js的版本,正确版本是 **0.6.25** + +## npm list --depth 0 +**看版本** +查看当前项目package所记录的依赖包版本, 小伙伴们常用的是 `npm list`, 它的缺点是冗长,`npm list --depth 0`不会展开依赖包所需的依赖包版本。 +``` +$ npm list --depth 0 +ng2-starter-webpack@0.0.1 E:\Project_Dev\Angularjs2\ng2-starter-webpack ++-- @angular/common@2.0.1 ++-- @angular/compiler@2.0.1 ++-- @angular/core@2.0.1 ++-- @angular/forms@2.0.1 ++-- @angular/http@2.0.1 ++-- @angular/platform-browser@2.0.1 ++-- @angular/platform-browser-dynamic@2.0.1 ++-- @angular/router@3.0.1 ++-- @angular/upgrade@2.0.1 ++-- angular-in-memory-web-api@0.1.1 ++-- bootstrap@3.3.5 ++-- core-js@2.4.1 ++-- html-webpack-plugin@2.24.1 ++-- reflect-metadata@0.1.6 ++-- rxjs@5.0.0-beta.12 ++-- ts-loader@0.9.5 ++-- typescript@2.0.10 ++-- typings@1.5.0 ++-- webpack@1.13.3 ++-- webpack-dev-server@1.16.2 +`-- UNMET PEER DEPENDENCY zone.js@0.6.23 + +npm ERR! peer dep missing: zone.js@^0.6.25, required by angular-in-memory-web-api@0.1.1 + +``` + +注意,其中的npm Error: angular-in-memory-web-api@0.1.1需要的zone.js版本是 `0.6.25`, 所以导致出现了错误,这也是常见的 `peer dependencies` 问题。 +``` +npm ERR! peer dep missing: zone.js@^0.6.25, required by angular-in-memory-web-api@0.1.1 +``` + +只要修改为正确的版本`0.6.25`即可! + + +## npm outdated +该命令是查询当前package中有哪些依赖包是过时的,为升级做好准备。 结果如下 +``` +$ npm outdated +Package Current Wanted Latest Location +@angular/common 2.0.1 2.0.1 2.2.0 ng2-starter-webpack +@angular/compiler 2.0.1 2.0.1 2.2.0 ng2-starter-webpack +@angular/core 2.0.1 2.0.1 2.2.0 ng2-starter-webpack +@angular/forms 2.0.1 2.0.1 2.2.0 ng2-starter-webpack +@angular/http 2.0.1 2.0.1 2.2.0 ng2-starter-webpack +@angular/platform-browser 2.0.1 2.0.1 2.2.0 ng2-starter-webpack +@angular/platform-browser-dynamic 2.0.1 2.0.1 2.2.0 ng2-starter-webpack +@angular/router 3.0.1 3.0.1 3.2.0 ng2-starter-webpack +@angular/upgrade 2.0.1 2.0.1 2.2.0 ng2-starter-webpack +angular-in-memory-web-api 0.1.1 0.1.1 0.1.15 ng2-starter-webpack +bootstrap 3.3.5 3.3.5 3.3.7 ng2-starter-webpack +reflect-metadata 0.1.6 0.1.6 0.1.8 ng2-starter-webpack +rxjs 5.0.0-beta.12 5.0.0-beta.12 5.0.0-rc.3 ng2-starter-webpack +ts-loader 0.9.5 0.9.5 1.2.1 ng2-starter-webpack +typescript 2.0.10 2.1.1 2.0.10 ng2-starter-webpack +typings 1.5.0 1.5.0 2.0.0 ng2-starter-webpack +zone.js 0.6.25 0.6.25 0.6.26 ng2-starter-webpack + +``` +一目了然,当前的version, 最新的version。 + +不要猴急把package中的版本号都替换为最新的,要考虑依赖的问题。ng2的core依赖rxjs.js, zone.js, 把ng2升级到`2.2.0`,是否有必要把rxjs 或 zone.js升级为最新的版本呢? 也不一定。 + + +## npm view xxxpackage/xxx@x.x.x peerDependencies +**查依赖** +该命令告诉我们,具体某个包的依赖关系。 +``` +$ npm view @angular/core@2.2.0 peerDependencies +{ rxjs: '5.0.0-beta.12', 'zone.js': '^0.6.21' } +``` +以查看 **@angular/core@2.2.0** 为例,它依赖 ** { rxjs: '5.0.0-beta.12', 'zone.js': '^0.6.21' } **, 也就是说升级**@angular/core** 到 ** 2.2.0 ** 没有必要升级rxjs, zone.js版本,即使他们有更新的版本。 + +再看一个依赖包: ** angular-in-memory-web-api@0.1.1 ** + +``` +$ npm view angular-in-memory-web-api@0.1.1 peerDependencies + +{ '@angular/core': '^2.0.0', + '@angular/http': '^2.0.0', + 'reflect-metadata': '^0.1.3', + rxjs: '5.0.0-beta.12', + 'zone.js': '^0.6.25' } + +``` +以上说明,当升级ng2相关库为 2.2.0的时候,可以不用升级 ** angular-in-memory-web-api@0.1.1 ** + +但是,修改完成 ng相关库为 2.2.0后,再次执行 npm install, 还是有错误 +``` +$ npm list --depth 0 +ng2-starter-webpack@0.0.1 E:\Project_Dev\Angularjs2\ng2-starter-webpack ++-- UNMET PEER DEPENDENCY @angular/common@2.2.0 ++-- @angular/compiler@2.2.0 ++-- UNMET PEER DEPENDENCY @angular/core@2.2.0 ++-- @angular/forms@2.2.0 ++-- @angular/http@2.2.0 ++-- UNMET PEER DEPENDENCY @angular/platform-browser@2.2.0 ++-- @angular/platform-browser-dynamic@2.2.0 ++-- @angular/router@3.0.1 ++-- @angular/upgrade@2.2.0 ++-- angular-in-memory-web-api@0.1.1 ++-- bootstrap@3.3.5 ++-- core-js@2.4.1 ++-- html-webpack-plugin@2.24.1 ++-- reflect-metadata@0.1.6 ++-- rxjs@5.0.0-beta.12 ++-- ts-loader@0.9.5 ++-- typescript@2.0.10 ++-- typings@1.5.0 ++-- webpack@1.13.3 ++-- webpack-dev-server@1.16.2 +`-- zone.js@0.6.25 + +npm ERR! peer dep missing: @angular/common@2.0.1, required by @angular/router@3.0.1 +npm ERR! peer dep missing: @angular/core@2.0.1, required by @angular/router@3.0.1 +npm ERR! peer dep missing: @angular/platform-browser@2.0.1, required by @angular/router@3.0.1 + +``` +本次是angular/router的版本太低了,@3.0.1 要求ng相关库是2.0.1, 2.2.0无法使用,所以需要升级angular/router 为3.2.0 + +## 修改,重复 +上述的** 看版本,查依赖,修json ** 可能会重复多次,完成后,测试的工作也不能少,至少主流程要走一遍,确保升级不会导致出现运行问题。 + +# 小结 +升级版本是个细致的活儿,需要科学的方法。否则容易出现问题,脑壳都会抓掉。再次总结下一般步骤吧! +### step 1 看版本 +npm list --depth 0 +npm outdated + +### step 2 查看依赖 +npm view xxxpackage/xxx@x.x.x peerDependencies + +### step 3 修json +### step 4 再重复 + diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 65541d8..d828516 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -316,6 +316,15 @@ const items: Article[] = [ first: true, tags: ['rxjs'], authors: ['timliu'], + }, + { + id: '如何优雅升级ng2小版本', + title: '280.如何优雅升级ng2小版本', + summary: '使用npm命令,搞定ng2小版本升级', + content: require('./280.如何优雅升级ng2小版本/_index.md'), + first: true, + tags: ['ng2升级', 'npm 常用命令'], + authors: ['木丁糖'], } ]; diff --git "a/src/app/_shared/api/authors/270.\346\234\250\344\270\201\347\263\226.md" "b/src/app/_shared/api/authors/270.\346\234\250\344\270\201\347\263\226.md" new file mode 100644 index 0000000..bf4b96a --- /dev/null +++ "b/src/app/_shared/api/authors/270.\346\234\250\344\270\201\347\263\226.md" @@ -0,0 +1,2 @@ +- ng爱好者 +- Android从业者 \ No newline at end of file diff --git "a/src/app/_shared/api/authors/_images/\346\234\250\344\270\201\347\263\226.jpg" "b/src/app/_shared/api/authors/_images/\346\234\250\344\270\201\347\263\226.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..7311408a7f1ed7915b39570873592d0bd303e7d5 GIT binary patch literal 43012 zcmeFYbyQr<_BPmfkU$_bZb5=H5Ug=0XmFQ?;MTZHAV`1!jWiY@NN{Zk?gV$2hG4loizZUq5@z8002(_I4A@F)JKH%n8Q(?{f#jmaV!c2;I9(pF(;u={)016 zSO92$*FUyG;r?4*;PE&gh39Wf{D_xOpZ{Ctv2}zU0R3-y0O0f^(|<7P3;=+}rf+BF z>}dC>jUpZRQ3mjrj(`8+-=&R}qn(o-ho`%h8y!C<7biEJioP_Tpf;VZ;N#I>Sw%`p zM)kDJr~_Najg zsQ+9)JOS;W`q%`l|8kdr{crpX07$_3M?NJX{_pEQ_6KTK0{kCbn2_)fuK4mF-MG29 zzM%a3I*(j`LH!TEI6+^~{(~`gzhL|aqt@k;{#S>*f9d}?JRUm`_22b>VYL5&G5(Do zM?*g5f9oH`{z`u}#ed8LkJ<8n$Nc}U?y2|r`==uS9)Zf@Yi4ULPA`;0z3fl zze~Pyd_2Kd4U-)sXqG1B4|89o+h-v;M z`Y(MS@nhZJHW2>1eDzoPU!5P1Fj4-)2Ik|bf4lZd{ijD> zJdX3f)Bj?c?hg z`XMYl;$vh~LSj;K%BR${^xVAsg2JNWlG5s$+PeCN#-`@3?w;Ph{(-@vsp*+nz}`Fe*b0HqbL2#tbZ)~KiNh2XcsCvIvP6GUv{COdOv0~ zLUfE5+?YgC8dzqo&*^!BpAbvKbE-PA8F)2Mf#zf z#H-p6UvJVgp2T}k0N$;Syl%s^WkPR#FNpr|eyBDJDw-bOD8-w8Ih_}jIQq!=1Wl^hNh9et?w_{Fvzw!wM@im6@6Hx}A1j#4`T`CllB-6BX$1<8A(?0-d95u3DU)>`6 zs)J8YuqexB=UmiY2?5a3FXD(wyDJnnsfh6XH4I52$F|Jab2~g3V(UzxiA@?!8t_Cz zeh2KOP_H!@&Ukyhr*2~V@p4)C8!3K^1NiZWWI^VsCfm?m?9^SigljHlsF0 zixSlrCuq2}6hZrfFE`_HXPgWMDWiqN+rlI{^3#py#iY=tS}Fm*UOx3Upf}fL>DzvL zLUmbbDS^kQkBCS~bxj#J34rPuB`+}N;czOQ+l+WGSdD-GsYn_B2e4cbaI}r5BifOd zLGe5Mq;o=Un8Gc(9~|j@dcGiin5ru#h+v%y&~WeKgx$1ldN@#p8q+O!x;Ny z)!aH6#$>H~U!4RWoS2wP?|YJT`-Mm{A82i0B{QEDUl!_0g^qtI8>LL_LK1EI`FN#ksGI zLSv%0W*7H4euZO-%>blt=??%GFHq;Rcoxl~*7QLCk+wU5=7Ekimh&M2C% zQ{x|i_-tM|RKw_3nM%70aXmvL#L~0xJ^g#O(K3POMs95?64*Zo#2Fi9F@mF{_I=17 z8`P1M*m@kbE*Nr%3nw(bbGqJa#46m-Mg`<0iVd7?Qn+}iHUs3|r-G~2NZ{p2o<{vGB3f62>xH`VIX2^W^%mh;)4;i3 zhNBEEY1$z$5R?BrGF>xr{)J>rT<+!g*^bIRanY5Pz8`P*`(O7~hA_w(ZH z&!L$wYK=V^g7(Lr`d4^km+Q8-J{W3o<0AF%G3pF%;Ci8ScJ+$C}g3&cT6lN)elB^ zm({^koKgu@W`0)kyEb!(P{rm}l~bYec8t2KFQU)p4($7k`yEv}_C&Xf6+rz?v2ZOz}n2f>+9Ws zdJGutaaM9msRMiksT^*2f)U;I=KbaaEy9(CfBMYnLdx z<}K=d&|g{S_WRev#J2>xcJ*pk+b`afEYdzp_U@%wR;ws+{+QV! z&ty#kaHRXNM}<$>vG0kD+}QnuD;?l{UDQl1GL;KY=6y#E?q0sX~t;2c^AuN@>ETVA4Uf0CKWnpd=EEf4lw~8;NJ6_!Cgr| zlV5tSPS-gC419*jj!;vb85{^qglHkU;;D0nm~{@-J=!vy>uNt0J0Cm~?Om${frr@x zgLAdyN2|B5O%D(H=j!b41m_m0r5sNzZ}bnBmfJvx=KJ2ebceH(`uI<tX&TBm0AiIZNHE{5xs4D1-8~C`vWL5gZ)MleDttve9H|uXaV|n%<&l8a?AQ) z`~2EjXmECLCo$i0ooa(s*sFA=&c(5(bMuLy0n5l9bj{K$D;XdL!p$4F!N<_TNkS72 zM0bd+gu(PA!nKwLI#r^k8;74)n+@N*KCKp)2=fJVRz;e^Vw(`RF(OVEIM&inIxD<& z!hLcV>5n?sTho&cZ40GGA7DEE9>9rTZqF}+Wr>Mxw=Xq48QA|YQoj|Gd_!O^2Q zr^es8^me7FxGurlGZ7*pr}LF%qiQ*qoNyjSMXJ2qAX#4BkeQN&D3r}P?lqOSw|cL` z58>Mx5olGTnrAO7U5TCGMA&4bEJ_Q!iy=B3EN!DKbg{pW9KS${1sOdcS9h)kCQPxE z0RcFr<))5r3*_y<57}#*MvCjtCB`;m-2x6W+uNG6T;|xZk5%ljmp>PSGF4{FpQ1LR z75HXHGexWUf21RCY;ie$h-$;SsOTHJR;y03UJ5Pnb&hn#IBs$2tgg!Da6Ov48WmF7 z-RccICSh3`&^O(#E`qfCBAB%qPH4w!wrN{C%GZ4z(wDLOunQU^#J3CUMTjlZ6XbPo zyMdg#R=wnyJVjv)dpd;{15Wa7&_RmqW(DS{5{Qv_;AwwjDXb-7GL<+nnXCl4t>4Fw z5Tjq{p>Ws-^gV^OlmwCX@8a`CDw%C2725OABzG4dbzqrcU||4`nX^7cY%B> zu#Qi6ruk|NOgfru8T*TY_=5~0dDb%f_#nCQ9*X25Z2q&|gY=@&Ybk?cPeYT&cS05W z>A*f(wF`0{HP(Lgz-0OE^vU`ea-D$%x3(I{Ly;@^p~l-wCrfeDx`PU7-wGe=t**ew z_tz^i3@KBC-#jptLzXPC9pZBI^b#J1rXF5p9jL-B``z05*LjT#5q4IUc8UQ+tkxQd zhtLjD!gU#FvCK}xz>j7ZKcINs(GUCz(KYeR#=~K9F z>a{B}hR8PM-1lrWQm1FHQ@EI9E<_KaTkiHZPe9BJc6{fls@@I-icY8^G;%T z;=1Cnt#LMbuPTlF0&8(qz}!C=^tyWIuAZSVjByk9`jJdiV~F!G$p zrS!&f7Wn)DG%sVg|D^DkOAkp&z0bsY;h&B0e7b(mvrSZEW<|xrwF}LjYc(jeL&k|b zBX$8$tC@n7ly=l=l?1Gwn(x|q5kQ^(0QT_mEBvC)ZYopAGlU#MW7QaE>VMz&6|F}e zb7nl;S?P(gUQn?>H5RFYLqYE; zQXz+w?`2HDN=`gm{+Wb+kc`asTIVHhWUfKYq`glnO*infE^d6S&@P5XizM->{DxtI z00bw;4cBs2N8XjsteI#hVHL75?@XedP-ko=g$5O7JK|-nG`u4Xa zt>5=2A6Db`6t4F-(45Z;OZDG<;y*m%IQ0Bz)flrG#IIC|9@keDNM|7BT(R=TQmQ_= z2TpiDg>v@?(A6vg4fcjo!br%*=Nb#`k#?o?BMdk+T>7p99e)57CJW(~HNX7Oj?M{h}uo>GiXe(Igf8Wo<(18Ws&E!-JdCv-IM&)@G7y|^+P zs31Aei?LZI!5L|Z%67`FKlD`0o0^lGS-ck(REB5Y?B+H8)+2BySSS!sKc#=qOEWqX z=y{P^%2N<%RXUk1Pv&okj}Y_qyrBu>NFTNUj#e${C5V-3kw4CRIrECk-xAm(&<~us zZm7kz=0lCHISVXdfjad#c16J1x7)B9d3z1SBxy353|`)r1q|7iC+cgGTTP)u5|o9r zO40htqM<&0UFKYtQsIXr5A-mh4gB(5tlNzJbo#Bl$a)-MXORj!_q&TqbrJ9F*2*r! zkp>#}$5-z7*6N;LjF+1p->=;@`2Ipw{%{<>K{{T#??gV^NnyJej$7C%306JnIXG<+pqu&J2;^J0!RU(9Xc)PruK6Pb=O}*b98sFylxTQp$VGJ5ULoY?Z<V z9B0d?#%N>%lq8S1={6tDD2v{*@v8xvRi5+298JH&hr8r2+F!cu4KmqIq8f;u1h~0zKk&fW!I=adC~B$#nrGTw{dxE zLu{@Sq%DkA~gL`dsdafee=1;mMVfz!t+szAiQyxeNuHAucr?P&+-ykSRc z9Or)brug~L*h^S^0RB^70^_HHJuOLiGwk~H1PsUwWV;Q&7O3IwB7W`L?<=y@#lh-h z=CFG*3qHg=_G^ox%P$qeI1R++mQM-My-rll(-enRXWWT%H4?_UaUeMV4 zkTD!O1ZO-z<_;$M+@`dblHsev__fDjGnZ$?!)yWFpw|*8#`2+#%r)t{w-tj;iew8? z-OVXBgiT6~7UNdJ<$}gED|G-gh8>gy;FzQZ|t#H>KM;=3y0D4Gvxc5U%5aE&NN$ z(>xhrV=jT27$Ezpn<}vuaEsi~zVMROzzd!mDpNiy?@Q1&UqQ?b!^u zO-K!<+IdxUtB=gvRGY5GCdnmy{Mq)|TamFS%n8DJ$$RI%daBZVVR>*tK_N>v{D7M5 zu4XdJnVnEl?yq$)CxtvR%9@$1$5&!k7JngDc{xwjZ~P>MG`ZWbWW+(v9_d1on&Wxn z%DyUy;>4K8N5oM2N1MVBfs2a-LPTwnq3M)qF49w^2|Z_oyCZdh^ji}%cwpSFR3c($ z=9mLUVKoUtOCe9R1DriR55AkavenaQZz8PnZfK}n5*RG2H0#{p6^T zJJCwm-_~t<%lYgB-Law=G%IHMNIB{Ur)#fa*2}c&b6vL{I7E7;cXTK5+0$Fs`yK;mo z7t<(WKh2syWKD0y6tHeEj_oFA$Qge-)MR0D;ey@&CMD;*8}8I@5nJ9LR)*Zyp&SY5 zF9C<){jkxA@YxM_5xN|IZACdtn5dI;&H~}FY%awI zD`zKRJreqQnsP*d#4IVY>&fv z-N!~|;*w#8W<9OoK*fxX*V*SD!_7_LD>8QEyD{ejz_Pl_o3O=_*3>q@v`@6j?_ z6DeW&!H=^YU#&}U7GpBD{ATQxMq$Ip%;5>S#Xxo99fUqf@JtH1YnHuwnnoOCrpKlp z)TX4jEl<36t1@KrG?@NOr+OIX)DNEa`O+$Uw29Nf=vZs9%N7wXD*k&e#sg|wAwJST z>e^+Ao6saCc?X(!pu3Z3n|d5>OXQ-rOi2Ria{S@6EaG=wmGV55*i%K1YfY&o@_L)T z_qCebD5OFsM*I}7r>*5~zXXp{!SxU{5boU?_5@#=D-=enLaG2~G~5kNcHfCrh9RsTMBK8&sg85h;vN7Gp&j>-7lC z`GM;{yBu7S#s?bjQ5ltlnSqFes}viq8>GPKLYh!igs zR(mX1CX>vV%e+Jnv{Y_0eL)$wNSzPE_yy0!`4dBLbgq(aVk_s;yP6pX<~M*ukikN4 zW{cc25%!c*hugBpg)+AB(>o&up22A+wTTOZxOW%d`BdHZQRBuCgI=18128YZ#=_Sk zN@Jcya*l3N)Al-j2C+W1A~0Ld0N-KhZ{5v=dQFm!8&?=odCDr*4+(1+V`r=-`|6a;KspT_AM~R6ADF(y1SD`FQ`rD+bq1*P%(y^=vcfzsR!MnZRAtG%&81+>R zuRAGG#w+~i%HOe^Vnjr~_@seczi`-i&nf60#~q=ma5U<0hkdG(=L1!qyW-x$U%q^C(2=9FAy$L6#tSc2UQ%&~ydSeI%MOTe z+hL4N?p;=)uKdWsWI$s#3~8!~@dn zL4I?ZzWXI-sR2JZG6^&Y%}7+#jD+;5^*Zv*=}c}mvSIY#SjwIBYnY&TVOhXU2G5xF zZ%KmPa{ANg&Oc?F5bUL&4syy6J@wQKPp1+LZ;IR)=p#cO#Sx-q%<&R01>ZwWrgm&Q z@AgZ3=ZEm-({&ePpInxgwQ>)T*?TnLxkpv9clM8VmRnGgd~d8q=|7NpQ~Q-MJr6ep zvh$_a0LKWkEs9KW*3ZFJDA8_V^g6L*ab<5Rbtl9!4PPSC@4exrip_d^*}5a!@zBE* zinnWn$6#0C^d0C@Y}B{9OQ1s4_YxuEul3E1b<7PkS@H(!!v|wEKgB~E8XJFGgRhZy z=QbP+EQ={Zf(RXJ3krf{c`|Cd1!GvOlqeAaqjmkpbe?p~Fc+HG!D#Oe*q&1<@X((g zL1uqt?OFc3Mo4HeRzi3tWNh72qht9f>KoMj0Dp(=%O>8;+^71pM*f3#$Yxe|Z1UQW zN=7@f{-x71-M7IMMzU6zx4FPuzw83{-($I)j?7WZA&aR)Umw`vGqYut;>H&>&d$oW zNU_nx_cnuUB{A*JU^R<*f{T^<0!l?lsjm*%n*|kjMTZ}1uYG3+K-`1f_}>i2o3#e1 zRqXfoWg-DPZRX<)T=Z?8CDU#sb!OI_@fq0s*?YQ<+*=7tS#{P^LPnCUnrYEKo(>*D zfT#lNz<19LIKCUj!hd{04$+@V+(J&!3Lw?Nc1ZW<}VwWpZ4=Hr!Ft zr+;~_z5Vs3uHozRTG}w--iOB z0*VprXlW|SRuslZJMtbx`$Gc+-qcprNW!I~@oXi+h*4CklGI9v$pg_}H~&88dY>uB zsdtnubO4W2jrcv&fRi$(vGNjIBjWM-;mL3by!e`}>(66y!nPEdJELJp&i9>Bbu6Or?qlyA!3rst zBMTJOD^raT?3Z)Bck`a_Jlzc0QP8#FfG4J3{2(j+zA`Y$rS0&z0y5>K5>|`rSpZ0> z3BjX_TNd0GtVH?Mf@o@u?OPtIu~vL?5F7MfcqduHH_uxGJQBzKE38&p1PWeH8`6K&g6Za-qcKSXIqbYxx?i1M#>keA;$h-3nr15fPwi?@s9thH)Au8uSr z@hqs^V*v;;;m%Z8B_j-Gc@LdL#3t&-e%#)Aqbs61m7knceS1}r_h$No8@=G54&yfB zyL1`-sY}(lQK7u^R8Do;cAE`jJgM!2F=((vQ;SrB9}f1oGI-+smXik`Q%G<pi zPS6RhM<4@&NZATS`m1`cBvqhwKGcffi6Gj^^Q^RTN4LDN9mScY@Hc4|DU3VbQ|&UG0h!6_zVcepAccdIE7eKOLX8(h1=eiXg!#=>eB;K7nl?9J z8vat7!X?K`1DChOAyBU$6bhkpIiGOgwDEm_a>OhW3*np8FlgdG^Fy z<(>N3bCr_vXHsO3E0RQxv{}%d*-;N9Ma*^1R&*K+LADUqym6qVn+Q$w;N-23n8>0& zGkUu$=d^QvoY%2)JjA`wh7I=mz&_+H^%4zj{u+G#2M}JzzJfsfz*(|9)xNISfBS6T z(DO@ud~~!%hif;=Rb^VT0JZ^59lP|Wz5r^+0F?Ufcw}`2vftrn<%_fW(DGmQ)3>T! zG66+hN3DH}!7)u()E{@D5=y^f3ct^ndkbLb-B!DFl|$aiPgs2@Zmy#{3wJftDiJY2 zU}$C-ZAS~;Qk!gFzwpjk;uX5RzE=&5sGPXig$A8DFF1QDo@~i3zC@XKBQEX)`fIh- zew|@zKfT(ttw|_kS!Cj!qbYr_{GfZp6lxgLz9|3`HJ0Ji*@lwg0V>#rzD@mx?A z3kk5ZeS8(=SwF(O*|G^c12aWuHKDc5V{A3iF9pE6xST96=S>Z1KtuYd&u;a9<09-jZyZ_t+ z;#rm9^QWC^-Nzsi-h@l2{Caw@X9A(H3%i<8B;zk&Y!YNR3(r2hiLXisn2D@Zw;oZDIWSQ3_x1 z8Md3D(ORzgjQP)F>&6XgXW+Sp`WMh!XEvtgenIfldVD=mPei6US5FyAEzN8kt|Qso zkttnk6@&Tk6T42;em*$W(eg?;S-0Gd=yqA1`j;@I@#r^G}#FaQrvFcJ#5vB(xIrH5B9tr9qV&Sp^way@8X%^bINZ zS0Wj9fZ?{TcXGjs&@Jk+Jrl@cC$`T2(?j-VBbW0#pE~wxV!*) z+@TV$bCs>+>4^{=wKI|p18Rg968R-N%^cEsS4x~Y=13aoCC!WE%&D+&#pbF8+SAMy^dsG-(L!xW?ZwJ@#7kL3Zuj zujX$4zjZ!IwScljW^Dx`0aWgWZgIQy= z%Uyo}@zlmg=1&X;pSu|ap_<8y*TLWM!$P2@cN@%bZ7_y$9xeAJFgbW&i_=8@U1Crh zh9s9|Cr0F6REtk`>y4i`IF0x45|IZCz-}slGM`B9pe3sKr*YOjS^q!{zY?oiNwXe8 zid0KkXc)ci#ykE(;y{&nU{w5_I^HYN`t0t;B7(umZT^zFwEc@-1`KvND(}dmI4m^o z9_3KZ3{U3K5QZDdOINzVfAIC7N*DKGsF-&NMkZDX_Noz6zD}bR!TY_QPx7I#Lx864 z-GCBDvH;1u<1slNEW@!@#SH4UKLFufx%2~cC#@`3g9cVQcqsGo-srP*fAo?;GPA<4 zF~xzO`3cw3?kP{F=@AeoOY`}`^_*Ca0nDX1!)0C(v2foJImNr%$(`qObv*jt1vUB& zKPDc)W*O5&NW!`;L}Kh8x2u^LyqOCFpaA!|N@Rup2tx{&;7+23E{?`mIbD%~qyZG` z^`d8$rX2zHAR&hHIXbl1SrMgt0ESPs^1{y-$qcxI{S!LO^R(^ab#CgTi%~`No)~g0 zksL%)%o3a+Iaci3Cc&%n)bO#0^lwgzy9!vuU`M$aCg~w>e(|KsXsil*7Q!Z`;GZYD zl62>@pZTONDy7o-l{!{8#4p!rsra#`(t9uFvX!EfM1}>)nNLd?)P6Qy72~$A;+%?X z=gW(SE);gD_SSanVq%q)_>is1O3~<>1__n4*7X@7M1ZdQ+61kbEH)_eV^6NZ7leW0-Ep=1E-g| zHcnZg$dd7t{YLR*KW(yI%mDjx_*bm3j)U}q9R8+Eo{b>x^sy{1DFCvd6F?OtRQ`Rl zQ}kY}%=X!#&G-{hCpwQ&n>S=yF-tZV2;9gkZW15u4X)w+J*Ldel*mtNa0(g z7+Un%gUn=w+O~n4TBq}xVF6p?>%vh^N!ts@{L8Vvd7ZDWKO04}4q%;BR_&=Y%0*cN zXp`=_>{R!68{3P_5V^hH&o>X##k$e*ynz!wZo3eDGIAGw4{$eU4##q{0VxkaOcWf>LBtHS>J$KhEYmz#h3Wj3)+ke}$uM290yT{jeK|`derr)%qL)kD*<&@I-Ieqj>O2JaRnUffMC8Glj@E|W@17?! z;>;@Y_$5!X19qiKkHd_Z8S!UrteIH8j}md>vQl{n!NU?o(gUbpUIJOwq*br?}Fq#3lhdO?!~+Xp2|Y519u==8P}eFwB3&@-pSI zUGBRpL1jd;9LYL6$iP+h_>&nP+cj_Kn>wleb;I&Av8nz2^w1m72RmrIna`+P_0mup zmYO=rAU{iU1Qfn4i~05%rmq<*Xau#oYVs0!eh0CI7`5qI;q)|h0t5ANhf2R}&O(3n zyhe4;%G%C-4U@kKl$I*J=xRfsw1PPglr2?!dUH`^OX9M#Hm?n^X+4UC_Ko z9Ig=?>LkoBeJfLUB|=A75md8NwYE6GKJpn?X%oObpM6@=7sJ%tm%z#+L{5`@>DV8R z$i^}q*wbH#2sh;+p>sNxl^2c4d6K2bnf1*^cJZg5t3kpp%lQBfUf8lpiEo}9;)7Q3 z!GU(})D!sk@Hbb#b^7j~LV$53?Gt!z{G^qJMKp1nBB&oqR!#Nlmwf`P`qVA21WS+B zd^*Nf>aGK>xexnahk6~i#j8KO*ed^-rwmz?J7~+lE;6${hMP>C*HNVj0 zo!=@^?6mh<5G^!%?SzPh>R2#rcO{5Hvrk)t5nXsOt$K3svoR?#&~QbQ^`WvtD!y-@ zhQIUR;6*bbk_vNBV(ca zy@M?8$*V-$Wor%>#j^|~27KRjpGJU!-@O{1(R}9rETHtO#dL7!N>+JyX16mkWsAUa zd`+39JF`c9n#xl{;W1L_W?Gsa{`HCItk+UUhIx_s4HXVFE{UXn)fO1#rZBwx>9qLu zhuE}!QCB_c5WEwrEO&L$;9#MFQstD7BQ5f1*@1T9dOKl&tASp;A$g9KoIuFxW$9$J zY5cJScR$eJoHRK5-AqCS=9Hhi_NIAz`^-yHHe=H&X1dtfG;Sd#HJW7mwSn<7g21{= zUKg(ttd-_3ur2GM26naKj9VS&B-6m!y-n-Y;EWj|#@J9%J%|Q@yjf>J6Q36TD!vh) zPS{b-6;o{qxMFK(YY7ydK16wtDL28Q_2S|=mAg^1*dkkQ)hbP3c55>X7>oEl6BtIzO59=8=K=Gm|Bafc=do-9=C zs=utsRdLh9gH)kqi6BR>*u-L?GAvVr&LFdo8{oDg@lG;Y){hq_kgR;w?23L;k z_T>EB>2ktKxJHPKo;)zVzCDH*A0PC*vjODnp%d;MTQ@1K+??Y@)~)rS$*Kg*FcaGU z+we1S{HvUot>4u_JHX>C=Gt4`xG>6(kCS^fO<1QpeZ$Yjt4cG@zNdI*7qN2kGDZt3 zyWv`7%xGj4j+?uF{xjE!<{oqz@jTGi*q35jiY+5m2~s-hEA?M2QJRHM)Cs#iW#TtG1Nr3kw)AnYJ2iLbklQx95+3AkWHe!ZVXz2 zBKmc)qmyVt(?R;dos1oMMgo^S)f~v%cETztoMR87Wf=cibsI*iw9k8B7%v?{e;Yh5 zo;)NAVkN#TuQP16nGV(e*niUgqAw25-MY z$x~pjsWM@_TAI$h}mA^*(|A)#?

    jn%f_Qv)V~%qy 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%0AY-RmuA!7+my?dQI>OQp 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 ainxf3^jaJ4iYTfQ+#BwSD58Lt=l|LKhQa#) literal 0 HcmV?d00001 diff --git a/src/app/_shared/api/authors/index.ts b/src/app/_shared/api/authors/index.ts index b6925fc..42f61db 100644 --- a/src/app/_shared/api/authors/index.ts +++ b/src/app/_shared/api/authors/index.ts @@ -69,6 +69,15 @@ const items: Author[] = [ columnist: false, homepage: 'https://twincle.github.io/' }, + { + id: '木丁糖', + name: '木丁糖', + bio: '爱好前端开发的Android白面猿', + description: require('./木丁糖.md'), + avatar: require('./_images/270.木丁糖.jpg'), + columnist: false, + homepage: 'http://www.jianshu.com/users/d614825bc8a1/latest_articles' + }, ]; @Injectable() export class AuthorApi { From f85d4466ee8cac3981215100e05cfba2d89bccb5 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Sat, 19 Nov 2016 06:20:47 -0800 Subject: [PATCH 065/177] article: modifies mock-redux-e2 basing on asnowwolf's comments --- src/app/_shared/api/articles/index.ts | 2 +- .../articles/mock-redux-with-rxjs/_index.md | 5 ++++ .../_index.md | 24 +++++++++++-------- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 980c837..b73adb4 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -310,7 +310,7 @@ const items: Article[] = [ }, { id: '应用RxJS模拟redux-第二集-Todo-App', - title: '应用RxJS模拟redux 第二集 Todo-App', + title: '应用RxJS模拟redux - 第二集 - Todo App', summary: '以Redux的思维,借助RxJS,制作一个Todo App。', content: require('./timliu/mock-redux-with-rxjs-episode-2-todo-app/_index.md'), first: true, diff --git a/src/app/_shared/api/articles/mock-redux-with-rxjs/_index.md b/src/app/_shared/api/articles/mock-redux-with-rxjs/_index.md index d9a67ae..439d2d5 100644 --- a/src/app/_shared/api/articles/mock-redux-with-rxjs/_index.md +++ b/src/app/_shared/api/articles/mock-redux-with-rxjs/_index.md @@ -1,3 +1,5 @@ +# 应用RxJS模拟redux + 初稿日期:2016年10月25日 ## 变量名Style约定 @@ -96,7 +98,10 @@ RxJS的文档里就有答案,就在这里:[RxJS官方教程 - State Stores][ 不同在于Array.prototype.reduce是把Array中所有的数值累积后形成一个值,而Observable.prototype.scan是把当前值和之前的累积值再次累积形成一个值,参见示例: ```js observable$.scan((accumulated, current) => accumulated + current, 0); + // 假设observable$推送的第一个数值为1,在推送第一个数值的时候,accumulated是0,即初始值,current是1,返回值是accumulated = accumulated + current即1; + // observable$每次推送新的数值,都会有一个新的accumulated数值推送,不需要等到observable$运行结束(即调用observer.complete()) // 类似Array.prototype.reduce,比如:[1, 2, 3].reduce((acc, curr) => acc + curr, 0); + // 但是Array.prototype.reduce返回的结果是要把array中的所有数值都积累起来,而Observable.prototype.scan是积累到当前值 ``` ## 编写代码 diff --git a/src/app/_shared/api/articles/timliu/mock-redux-with-rxjs-episode-2-todo-app/_index.md b/src/app/_shared/api/articles/timliu/mock-redux-with-rxjs-episode-2-todo-app/_index.md index 9ddfc75..db5d985 100644 --- a/src/app/_shared/api/articles/timliu/mock-redux-with-rxjs-episode-2-todo-app/_index.md +++ b/src/app/_shared/api/articles/timliu/mock-redux-with-rxjs-episode-2-todo-app/_index.md @@ -1,13 +1,13 @@ -# Mock Redux with RxJS - Episode 2 - Todo App +# 应用RxJS模拟redux - 第二集 - Todo App 初稿日期:2016年11月08日 ## 写作原因/目的 在上集[Mock Redux with RxJS][]里,我们用RxJS模拟了Redux的最基本的功能,即实现了一个`state`为数字的`state store`。 -现实生活中,`state`的内容要复杂的多,而且除了改变`state`,我们还要处理`side effects`,比如更新`dom`、发送`ajax`请求等等。 +现实生活中,`state`的内容要复杂的多,而且除了改变`state`,我们还要处理[“副作用(`side effects`)”][],比如更新`dom`、发送`ajax`请求等等。 - 本集想要说明的是: - **应用RxJS,在改变`state`的同时,我们可以很直接的处理`side effects`,不需要像Redux那样使用`Thunk Middleware`。** + **应用RxJS,在改变`state`的同时,我们可以很直接的处理`side effects`,不需要像Redux那样使用[中间件(middleware)][]。** 落实在代码上就是: ```js // 从上集的 @@ -24,7 +24,7 @@ }) ``` 仅此而已。 -接下来的部分都是上面代码的具体应用,大家赶时间的话,可以全部跳过。 +余下全文都是上面代码的具体应用,大家赶时间的话,可以全部跳过。 本集承接上集,以Redux的思维,借助RxJS,制作一个Todo App。 @@ -130,7 +130,7 @@ = = = = = 分割线 = = = = = -以`app启动`为例,走一遍流程。 +以“app启动”为例,走一遍流程。 页面载入后,app启动,运行`action$$.next({type: CONST.GET_ALL_START})`。 找找这个action的handler, @@ -218,14 +218,18 @@ inputElem.focus(); // 可以输入新的todo了 希望通过此文,能够帮助大家进一步了解RxJS。 ## 参考: -[Mock Redux with RxJS][] -[Repo][] -[`Observable.ajax`运算符][] -[`observers`列表][] -[JSON Server][] +- [Mock Redux with RxJS][] +- [“副作用(`side effects`)”][] +- [中间件(middleware)][] +- [Repo][] +- [`Observable.ajax`运算符][] +- [`observers`列表][] +- [JSON Server][] [Mock Redux with RxJS]: https://wx.angular.cn/library/article/%E5%BA%94%E7%94%A8RxJS%E6%A8%A1%E6%8B%9Fredux [Repo]: https://github.com/rxjs-space/rxjs-typescript-starter [`Observable.ajax`运算符]: https://github.com/ReactiveX/rxjs/blob/master/src/observable/dom/AjaxObservable.ts [`observers`列表]: http://reactivex.io/rxjs/file/es6/Subject.js.html#lineNumber25 [JSON Server]: https://github.com/typicode/json-server +[“副作用(`side effects`)”]: https://en.wikipedia.org/wiki/Side_effect_(computer_science) +[中间件(middleware)]: http://redux.js.org/docs/advanced/Middleware.html From 43f851f73b5b7ede26d8629b1e6e825a4bf66672 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Sat, 19 Nov 2016 15:02:28 -0800 Subject: [PATCH 066/177] article: groups timliu's article in one folder --- src/app/_shared/api/articles/index.ts | 13 ++----------- .../{ => timliu}/mock-redux-with-rxjs/_index.md | 0 .../api/articles/{ => timliu}/simple-rxjs/_index.md | 0 3 files changed, 2 insertions(+), 11 deletions(-) rename src/app/_shared/api/articles/{ => timliu}/mock-redux-with-rxjs/_index.md (100%) rename src/app/_shared/api/articles/{ => timliu}/simple-rxjs/_index.md (100%) diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 65541d8..d7ce3da 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -250,7 +250,7 @@ const items: Article[] = [ id: '应用RxJS模拟redux', title: '应用RxJS模拟redux', summary: '参照RxJS Doc中的state store示例,加入Subject,模拟redux。', - content: require('./mock-redux-with-rxjs/_index.md'), + content: require('./timliu/mock-redux-with-rxjs/_index.md'), first: true, tags: ['RxJS'], authors: ['timliu'], @@ -273,15 +273,6 @@ const items: Article[] = [ tags: ['ng1', 'ng2', '平滑升级', 'es6', 'typescript'], authors: ['王開寧'], }, - { - id: '白话RxJS', - title: '白话RxJS', - summary: '尝试使用“白话”来介绍RxJS。', - content: require('./simple-rxjs/_index.md'), - first: true, - tags: ['RxJS'], - authors: ['timliu'], - }, { id: '一个依赖注入小框架的实现', title: '一个依赖注入小框架的实现', @@ -312,7 +303,7 @@ const items: Article[] = [ id: 'simple-rxjs', title: '白话RxJS', summary: '本文将尝试用白话来解读RxJS。', - content: require('./simple-rxjs/_index.md'), + content: require('./timliu/simple-rxjs/_index.md'), first: true, tags: ['rxjs'], authors: ['timliu'], diff --git a/src/app/_shared/api/articles/mock-redux-with-rxjs/_index.md b/src/app/_shared/api/articles/timliu/mock-redux-with-rxjs/_index.md similarity index 100% rename from src/app/_shared/api/articles/mock-redux-with-rxjs/_index.md rename to src/app/_shared/api/articles/timliu/mock-redux-with-rxjs/_index.md diff --git a/src/app/_shared/api/articles/simple-rxjs/_index.md b/src/app/_shared/api/articles/timliu/simple-rxjs/_index.md similarity index 100% rename from src/app/_shared/api/articles/simple-rxjs/_index.md rename to src/app/_shared/api/articles/timliu/simple-rxjs/_index.md From 7f0357ef5b9750d839734f27bca92bcf7c3c7d5e Mon Sep 17 00:00:00 2001 From: timeCoiner <846432362@qq.com> Date: Sun, 20 Nov 2016 09:18:38 +0800 Subject: [PATCH 067/177] Update _index.md --- .../_index.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" index b3bddb2..b6f9b26 100644 --- "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" +++ "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" @@ -1,5 +1,5 @@ -如何工程化开发大型angular2项目(上篇) -=================== +# 如何工程化开发大型angular2项目(上篇) + ### 前请提要: 说到前端工程化开发,市面上丰富的工具链都大大提升大家的开发效率,webpack,gulp,ng2自带的ng cli等等工具。从开始构建项目,实时编译scss,代码打包,压缩,混淆,文件名打时间戳等等工作。这些只是项目构建到上线的工作流 。以及如何引入第三方库以及样式库,开发环境与编译环境的配置分离,多个开发人员开发同一项目因提交自己开发环境的配置文件引发冲突。这些不仅仅是开发大型angular2应用会遇到的问题,也是其他大型项目会遇到的问题。另外多人开发 From 002e8e2904b6271eb54c7f50fbd8b076ced46056 Mon Sep 17 00:00:00 2001 From: timeCoiner <846432362@qq.com> Date: Sun, 20 Nov 2016 09:23:02 +0800 Subject: [PATCH 068/177] Update _index.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 调整标题样式 --- .../_index.md" | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" index b6f9b26..820d506 100644 --- "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" +++ "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" @@ -1,15 +1,12 @@ # 如何工程化开发大型angular2项目(上篇) -### 前请提要: - 说到前端工程化开发,市面上丰富的工具链都大大提升大家的开发效率,webpack,gulp,ng2自带的ng cli等等工具。从开始构建项目,实时编译scss,代码打包,压缩,混淆,文件名打时间戳等等工作。这些只是项目构建到上线的工作流 - 。以及如何引入第三方库以及样式库,开发环境与编译环境的配置分离,多个开发人员开发同一项目因提交自己开发环境的配置文件引发冲突。这些不仅仅是开发大型angular2应用会遇到的问题,也是其他大型项目会遇到的问题。另外多人开发 - 会存在代码风格不同一,review时异常痛苦的问题。为什么程序员聪明,因为程序员懒,懒到想一切利用工具去解决。所以下面是我开发angular2项目时遇到的一些问题以及自己的一些解决方案以及项目管理的思路。 +## 前请提要: + 说到前端工程化开发,市面上丰富的工具链都大大提升大家的开发效率,webpack,gulp,ng2自带的ng cli等等工具。从开始构建项目,实时编译scss,代码打包,压缩,混淆,文件名打时间戳等等工作。这些只是项目构建到上线的工作流。以及如何引入第三方库以及样式库,开发环境与编译环境的配置分离,多个开发人员开发同一项目因提交自己开发环境的配置文件引发冲突。这些不仅仅是开发大型angular2应用会遇到的问题,也是其他大型项目会遇到的问题。另外多人开发会存在代码风格不同一,review时异常痛苦的问题。为什么程序员聪明,因为程序员懒,懒到想一切利用工具去解决。所以下面是我开发angular2项目时遇到的一些问题以及自己的一些解决方案以及项目管理的思路。 -### 项目构建篇: - angular2官方提供ng cli构建工具,但是投入使用后发现并不是符合我们需求。因为我们之前项目是基于gulp整套工作流,所以一直在寻找与gulp相结合的ng2案例。后来找到一个angular-seed项目,于是我将该项目设立为种子项目,依据 - 该种子项目我们开发了7、8个angular2项目。下面简单介绍一下如何利用种子库创建衍生库,只要种子库保持更新,其他库可以同步保持更新. +## 项目构建篇: + angular2官方提供ng cli构建工具,但是投入使用后发现并不是符合我们需求。因为我们之前项目是基于gulp整套工作流,所以一直在寻找与gulp相结合的ng2案例。后来找到一个angular-seed项目,于是我将该项目设立为种子项目,依据该种子项目我们开发了7、8个angular2项目。下面简单介绍一下如何利用种子库创建衍生库,只要种子库保持更新,其他库可以同步保持更新. -##### 建立种子库: +### 建立种子库: ![管理流程图](./git.png) 上面的图画得比较烂,我还是来好好解释一下。首先我们得有一个主心库,这个库十分重要,里面没有业务逻辑的代码,主要是平时开发时所需要的所有脚本,以及npm的一些基本依赖。另外一些共用组件,共用逻辑代码(例如登录验证等等)。主心库创 @@ -19,7 +16,7 @@ git remote add upstream https://github.com/mgechev/angular-seed.git git pull upstream master ``` 平时我们想要更新主仓库时,只要git pull以下upstram远端,就可以保持最新了。如果不想人工手动去更新的化可以交给jenkins定时去更新,这样主心仓库永远是最新的了。 -#### 创建衍生库: +### 创建衍生库: 因为我们所有项目围绕主心库而衍生出来的,所以衍生库和主心库的关心和angular-seed关系一致。我们指定我们衍生库的远端upstream为我们的主心库,这样只要主心库是最新的,这样所有衍生库都可以保持同步更新。可以享受主心库提供的共用配置和 业务逻辑。看上去过程比较繁琐,其实只需要将整个操作过程的指令集合到bash脚本中,执行脚本是指定参数名为你的项目名称。这样快速就可以构建一个angular2项目,所以整套流程适合有复杂业务的项目。 ``` @@ -27,10 +24,8 @@ git remote add upstream git@192.168.1.1:/git/main-base git pull upstream master ``` -### 项目开发篇: - 既然我们构建完项目后,那么马上开工吧。随着前端项目越来越复杂,里面配置文件越来越多。因为开发环境和生产环境需要调用服务端接口地址又是不一样的,像我开发微信项目的,开发环境用测试的appid和生产环境的appid也是不一样的。情况更严重 - 的是我们每个客户都有自己独立的配置信息(所以开始考虑多租户模式,不然下去是大坑)。 - 理想情况下: +## 项目开发篇: + 既然我们构建完项目后,那么马上开工吧。随着前端项目越来越复杂,里面配置文件越来越多。因为开发环境和生产环境需要调用服务端接口地址又是不一样的,像我开发微信项目的,开发环境用测试的appid和生产环境的appid也是不一样的。情况更严重的是我们每个客户都有自己独立的配置信息(所以开始考虑多租户模式,不然下去是大坑)。理想情况下: ``` gulp build.dev --color --env-config dev @@ -67,6 +62,6 @@ git pull upstream master ``` 关于开发配置十分细碎,所以不做详述,可以日后咨询。 -### 下篇预告: +## 下篇预告: 下篇会涉及项目目录结构管理,以及angular2在移动端开发的经验,项目打包上线的经验 ps: 正在寻找新的工作机会,感兴趣的朋友加我QQ: 846432362 From 6b2fe7f8e5f68fd8a8f0b768ca90c9a781b21b7e Mon Sep 17 00:00:00 2001 From: timeCoiner <846432362@qq.com> Date: Sun, 20 Nov 2016 10:27:24 +0800 Subject: [PATCH 069/177] Update _index.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修改前情提要 --- .../_index.md" | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" index 820d506..6321182 100644 --- "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" +++ "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" @@ -1,8 +1,7 @@ # 如何工程化开发大型angular2项目(上篇) ## 前请提要: - 说到前端工程化开发,市面上丰富的工具链都大大提升大家的开发效率,webpack,gulp,ng2自带的ng cli等等工具。从开始构建项目,实时编译scss,代码打包,压缩,混淆,文件名打时间戳等等工作。这些只是项目构建到上线的工作流。以及如何引入第三方库以及样式库,开发环境与编译环境的配置分离,多个开发人员开发同一项目因提交自己开发环境的配置文件引发冲突。这些不仅仅是开发大型angular2应用会遇到的问题,也是其他大型项目会遇到的问题。另外多人开发会存在代码风格不同一,review时异常痛苦的问题。为什么程序员聪明,因为程序员懒,懒到想一切利用工具去解决。所以下面是我开发angular2项目时遇到的一些问题以及自己的一些解决方案以及项目管理的思路。 - + 目前前端项目越来越复杂,管理一个前端项目需要考虑的方面越来越多,例如工具选择、项目构建、代码自动review工具、代码打包上线、开发生产环境分离、项目结构管理以及第三库引入管理等等之类问题,。所以下面是我开发angular2项目时遇到的一些问题以及自己的一些解决方案以及项目管理的思路。 ## 项目构建篇: angular2官方提供ng cli构建工具,但是投入使用后发现并不是符合我们需求。因为我们之前项目是基于gulp整套工作流,所以一直在寻找与gulp相结合的ng2案例。后来找到一个angular-seed项目,于是我将该项目设立为种子项目,依据该种子项目我们开发了7、8个angular2项目。下面简单介绍一下如何利用种子库创建衍生库,只要种子库保持更新,其他库可以同步保持更新. @@ -13,7 +12,8 @@ 立完后,我们需要建立一个upstream的远端指向angular-seed项目 ``` git remote add upstream https://github.com/mgechev/angular-seed.git -git pull upstream master + git fetch upstream + git merge upstream/master ``` 平时我们想要更新主仓库时,只要git pull以下upstram远端,就可以保持最新了。如果不想人工手动去更新的化可以交给jenkins定时去更新,这样主心仓库永远是最新的了。 ### 创建衍生库: @@ -21,7 +21,8 @@ git pull upstream master 业务逻辑。看上去过程比较繁琐,其实只需要将整个操作过程的指令集合到bash脚本中,执行脚本是指定参数名为你的项目名称。这样快速就可以构建一个angular2项目,所以整套流程适合有复杂业务的项目。 ``` git remote add upstream git@192.168.1.1:/git/main-base -git pull upstream master + git fetch upstream + git merge upstream/master ``` ## 项目开发篇: From 8be52df4148ec517cec19d532c726b2762a80b85 Mon Sep 17 00:00:00 2001 From: timeCoiner <846432362@qq.com> Date: Sun, 20 Nov 2016 10:28:33 +0800 Subject: [PATCH 070/177] Update _index.md --- .../_index.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" index 6321182..b0a46db 100644 --- "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" +++ "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" @@ -1,7 +1,7 @@ # 如何工程化开发大型angular2项目(上篇) ## 前请提要: - 目前前端项目越来越复杂,管理一个前端项目需要考虑的方面越来越多,例如工具选择、项目构建、代码自动review工具、代码打包上线、开发生产环境分离、项目结构管理以及第三库引入管理等等之类问题,。所以下面是我开发angular2项目时遇到的一些问题以及自己的一些解决方案以及项目管理的思路。 + 目前前端项目越来越复杂,管理一个前端项目需要考虑的方面越来越多,例如工具选择、项目构建、代码自动review工具、代码打包上线、开发生产环境分离、项目结构管理以及第三库引入管理等等之类问题。所以下面是我开发angular2项目时遇到的一些问题以及自己的一些解决方案以及项目管理的思路。这些内容将会以一个系列展开。 ## 项目构建篇: angular2官方提供ng cli构建工具,但是投入使用后发现并不是符合我们需求。因为我们之前项目是基于gulp整套工作流,所以一直在寻找与gulp相结合的ng2案例。后来找到一个angular-seed项目,于是我将该项目设立为种子项目,依据该种子项目我们开发了7、8个angular2项目。下面简单介绍一下如何利用种子库创建衍生库,只要种子库保持更新,其他库可以同步保持更新. From 98c4e18958c44542b1ddaa724d1beb704d9e47e1 Mon Sep 17 00:00:00 2001 From: timeCoiner <846432362@qq.com> Date: Sun, 20 Nov 2016 10:33:32 +0800 Subject: [PATCH 071/177] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=8F=A5=E5=AD=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" index b0a46db..4fe7bd5 100644 --- "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" +++ "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" @@ -54,7 +54,7 @@ git remote add upstream git@192.168.1.1:/git/main-base } // 具体代码可以克隆angular-seed去查看 ``` - 另外angular2提供接口能够优化打包出来的代码enableProdMode,但是我们开发时是不需要用到该接口如何去分离开来呢?gulp有个好插件,完美解决该问题,[gulp-template](https://www.npmjs.com/package/gulp-template)。我们只要在我们 +   另外angular2提供[enableProdMode](https://angular.io/docs/ts/latest/api/core/index/enableProdMode-function.html)接口能够优化打包出来的代码,但是我们开发时是不需要用到该接口如何去分离开来呢?gulp有个好插件,完美解决该问题,[gulp-template](https://www.npmjs.com/package/gulp-template)。我们只要在我们 代码中加入类似<%= BUILD_TYPE %>,这样就可以赋值给BUILD_TYPE,我们可以合理得去控制。 ``` import { enableProdMode } from '@angular/core'; From 841ca6bd11dbe923552f90d7306913e74f607c96 Mon Sep 17 00:00:00 2001 From: JohnnyTam Date: Sun, 20 Nov 2016 13:29:49 +0800 Subject: [PATCH 072/177] =?UTF-8?q?=E5=A6=82=E4=BD=95=E4=BC=98=E9=9B=85?= =?UTF-8?q?=E5=8D=87=E7=BA=A7ng2=E5=B0=8F=E7=89=88=E6=9C=AC--=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E7=89=88=EF=BC=8C=20=E4=BF=AE=E6=94=B9=E5=9F=BA?= =?UTF-8?q?=E7=A1=80md=E6=96=87=E7=AB=A0=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git "a/src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" "b/src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" index 52c3179..c9bf99c 100644 --- "a/src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" +++ "b/src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" @@ -1,13 +1,14 @@ +# 如何优雅升级ng2小版本 -# 前言 +## 前言 前几天在Angular中文社区群里,有小伙伴询问ng项目升级,出现N多的 `Peer Dependencies`错误,吐槽很是影响coding心情。私下询问,发现对package文件中的版本号有点误会,我之前也遇到类似问题,在此做个小结。 这里的升级不是指ng1如何升级到ng2,仅以angular 2.0.1升级到当前2.2.0的时候需要注意的小细节。想了解 如何从ng1升级到ng2,请参考公众号之前文章[从ng1到ng2的平滑升级](./articles/260.从ng1到ng2的平滑升级[1]/_index.md) -# 目标 -## 1. package文件版本号前面的符号有什么鬼? -## 2. 如何从ng2.0.1 优雅升级到 ng2.2.0(当前最新) +## 目标 +1. package文件版本号前面的符号有什么鬼? +2. 如何从ng2.0.1 优雅升级到 ng2.2.0(当前最新) -# package依赖包版本号 +## package依赖包版本号 先来了解下package.json文件依赖包中常见的标点符号。这里,仅涉及如下符号: `^` `~` `>=` `<= ` ### 只有版本号 @@ -28,7 +29,7 @@ package.json中,版本号如下: "@angular/core": ">=2.0.1<=3.0.0" 什么鬼: 表示安装的版本是在 2.0.2到3.0.0之前的,上下边界也在内。 -# 优雅升级常用npm命令 +## 优雅升级常用npm命令 上述仅是package.json涉及内容的几小点,更多内容,参考npmjs官方文档 [Specifics of npm's package.json handling](https://docs.npmjs.com/files/package.json) 和 [The semantic versioner for npm](https://docs.npmjs.com/misc/semver) 接下来,开始我们的优雅之旅吧!以我自己的ng2入门项目[ng2-starter-webpack](https://github.com/tancolo/angular2/tree/master/ng2-starter-webpack)项目为例子说明,如何优雅升级ng2小版本。 一句话总结升级步骤: ** 看版本,查依赖,修json,再重复。** @@ -70,7 +71,7 @@ package.json中,版本号如下: ``` 原因是 为了演示错误,有意降低了 zone.js的版本,正确版本是 **0.6.25** -## npm list --depth 0 +### npm list --depth 0 **看版本** 查看当前项目package所记录的依赖包版本, 小伙伴们常用的是 `npm list`, 它的缺点是冗长,`npm list --depth 0`不会展开依赖包所需的依赖包版本。 ``` @@ -110,7 +111,7 @@ npm ERR! peer dep missing: zone.js@^0.6.25, required by angular-in-memory-web-ap 只要修改为正确的版本`0.6.25`即可! -## npm outdated +### npm outdated 该命令是查询当前package中有哪些依赖包是过时的,为升级做好准备。 结果如下 ``` $ npm outdated @@ -139,7 +140,7 @@ zone.js 0.6.25 0.6.25 0.6.26 ng2 不要猴急把package中的版本号都替换为最新的,要考虑依赖的问题。ng2的core依赖rxjs.js, zone.js, 把ng2升级到`2.2.0`,是否有必要把rxjs 或 zone.js升级为最新的版本呢? 也不一定。 -## npm view xxxpackage/xxx@x.x.x peerDependencies +### npm view xxxpackage/xxx@x.x.x peerDependencies **查依赖** 该命令告诉我们,具体某个包的依赖关系。 ``` @@ -195,18 +196,18 @@ npm ERR! peer dep missing: @angular/platform-browser@2.0.1, required by @angular ``` 本次是angular/router的版本太低了,@3.0.1 要求ng相关库是2.0.1, 2.2.0无法使用,所以需要升级angular/router 为3.2.0 -## 修改,重复 +### 修改,重复 上述的** 看版本,查依赖,修json ** 可能会重复多次,完成后,测试的工作也不能少,至少主流程要走一遍,确保升级不会导致出现运行问题。 -# 小结 +## 小结 升级版本是个细致的活儿,需要科学的方法。否则容易出现问题,脑壳都会抓掉。再次总结下一般步骤吧! -### step 1 看版本 +#### step 1 看版本 npm list --depth 0 npm outdated -### step 2 查看依赖 +#### step 2 查看依赖 npm view xxxpackage/xxx@x.x.x peerDependencies -### step 3 修json -### step 4 再重复 +#### step 3 修json +#### step 4 再重复 From c0e15442ea43ef4060a36c681b96adc149dbb547 Mon Sep 17 00:00:00 2001 From: Trotyl Date: Mon, 21 Nov 2016 02:58:01 +0800 Subject: [PATCH 073/177] Add article: Communication in Angular 2. --- .../_index.md" | 459 ++++++++++++++++++ src/app/_shared/api/articles/index.ts | 9 + 2 files changed, 468 insertions(+) create mode 100644 "src/app/_shared/api/articles/280.Angular2\344\270\255\347\232\204\351\200\232\344\277\241\346\226\271\345\274\217/_index.md" diff --git "a/src/app/_shared/api/articles/280.Angular2\344\270\255\347\232\204\351\200\232\344\277\241\346\226\271\345\274\217/_index.md" "b/src/app/_shared/api/articles/280.Angular2\344\270\255\347\232\204\351\200\232\344\277\241\346\226\271\345\274\217/_index.md" new file mode 100644 index 0000000..106b2cb --- /dev/null +++ "b/src/app/_shared/api/articles/280.Angular2\344\270\255\347\232\204\351\200\232\344\277\241\346\226\271\345\274\217/_index.md" @@ -0,0 +1,459 @@ +# Angular 2 中的通信方式 + +软件工程中,随着应用规模的不断扩大,必然需要进行 Code Splitting。在 Web 开发中,组件化和模块化的观念已经被越来越多的人所熟知,从而编写出更高质量的代码。 + +同时,随着实体职责的分离,我们也就会不可避免地需要进行实体间的相互通信,因为我们的应用仍然需要作为一个整体存在。因此,在本文中,将对 Angular 2 中的实体间通信方式进行简要介绍,以帮助读者编写更易于维护的代码。 + +## 术语表 + ++ 输入/Input:组件中的外部输入,通常由 [@Input()](https://angular.io/docs/ts/latest/api/core/index/Input-interface.html) 属性装饰器或 [@Component()](https://angular.io/docs/ts/latest/api/core/index/Component-decorator.html) 类装饰器参数中的 inputs 属性指定。 ++ 数据/Data(Datum):信息本身或其直接载体,后者通常为基本类型或其他直接携带信息的实体类型的实例。*为可数名词,通常使用其复数形式。* ++ 材料/Material:所有由 Provider 所产生的具体内容,如通过 useClass 注册并生成的 Service 的实例等。 ++ 提供商/Provider:用于产生某种 Material 的实体。使用 useClass 时,Provider 通常为 Material 的类;使用 useFactory 时,Provider 通常为返回 Material 的函数;使用 useValue 时,Provider 通常为 Material 本身。其中,通过 useClass 方式注册的 Provider 通常使用 [@Injectable()](https://angular.io/docs/ts/latest/api/core/index/Injectable-decorator.html) 装饰器修饰。 + +## 通信方式介绍 + +下面列出一些常用的通信方式并进行简要说明。 + +### 输入:数据 + ++ 通信源:父组件与子组件 ++ 数据方向:父组件 => 子组件 ++ 信号方向:父组件 => 子组件 + +数据输入是最为常用的通信方式,对于父组件与子组件/指令而言,由子指令配置所需的输入项,默认为必须,可由 [@Optional()](https://angular.io/docs/ts/latest/api/core/index/Optional-decorator.html) 装饰器配置为可选。同时在父组件模版中使用属性绑定语法(使用 [prop]="expression" 绑定到表达式或 prop="literal" 绑定到字面值)指定绑定源。随后,于子组件/指令的构造函数与 [OnInit](https://angular.io/docs/ts/latest/api/core/index/OnInit-class.html) 生命周期之间,子组件/指令的输入属性绑定完成。每当绑定源发生变化时,子组件/指令的输入属性也会发生对应变化。例如: + +```typescript +@Component({ + template: ` + + ` +}) +class Parent { } + +@Component({ + selector: 'child' +}) +class Child implements OnInit { + @Input() propOne: number + @Input() propTwo: string + + ngOnInit(): void { + console.log(this.propOne) // 2 + console.log(this.propTwo) // "1 + 1" + } +} + +@Directive({ + selector: '[propOne][propTwo]' +}) +class Spy implements OnInit { + @Input() propOne: number + @Input() propTwo: string + + ngOnInit(): void { + console.log(this.propOne) // 2 + console.log(this.propTwo) // "1 + 1" + } +} +``` + +这里可以看到,每个组件/指令都可以定义自己所需的输入,对于同宿主的若干个指令(或一个组件和若干指令,同一个宿主不可以出现多个组件)如果有同名的输入会被共享。 + +另外,ng2 中的输入(属性绑定)在某种意义上来说是 "强类型" 的,拥有严格的检查机制,如果使用了一个不存在的输入会被视为语法错误(如果同时使用了原生的 [CustomElements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Custom_Elements) 或其他库来扩展 HTML 则需要在模块定义中注册自定义扩展语法)。 + +同时,在默认的变化监测策略中并且没有主动调用 changeDetector 的相关状态修改方法时,输入是动态绑定的,即一旦数据源发生变化就会对目标组件/指令的对应属性重新赋值。 + +通过自 ES6 引入的 [Getter](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/get)/[Setter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set) 语法(ES5 中 [Object#defineProperty](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty) 的语法糖),我们可以很方便地在每次输入变化时得到通知: + +```typescript +@Component({ + selector: 'child' +}) +class Child implements OnInit { + @Input() set propOne(value: number) { + console.log(`Property one changed to ${value}`) + } + + // ... +} +``` + +但是我们这里发现了一个问题,如果输入属性的值没有变化的话,我们又想要通知到目标(子)组件/指令,那要怎么办呢?事实上,由于 Angular 2 采用脏检测的机制,我们并没有办法直接应用一个 "变化后的值与变化前相同" 的变化。诚然,我们可以对绑定的数据进行一层封装,然后绑定封装对象,但有一些时候,我们并不想传递什么数据,只是需要单纯地传递一个信号,即一个 Void Input,这时候,除了使用封装对象,我们还可以有另一些方式供选择。 + + +### 输入:事件 + ++ 通信源:父组件与子组件 ++ 数据方向:父组件 => 子组件(可空) ++ 信号方向:父组件 => 子组件 + +我们已经知道(后文中也会提到),输出属性(事件绑定)使用了 [Observable](http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html) 这个事件流来实现下级到上级的信号传递。和输入属性不同,输出属性的 "变化" 不依赖于脏检测,而是基于主动的事件通知。 + +事实上,对输入属性,我们也同样可以使用事件流来绑定我们传递输入内容: + +```typescript +@Component({ + selector: 'child' +}) +class Child implements OnInit, OnDestroy { + @Input() set propOne(value: Observable) { + if (this.propOneSubscription) { + this.propOneSubscription.unsubscribe() + } + + this.propOneSubscription = value.subscribe(/* Some Logic */) + // Or use AsyncPipe in template + } + + private propOneSubscription: Subscription + + ngOnDestroy(): void { + this.propOneSubscription.unsubscribe() + } + + //... +} +``` + +当然,由于不像输出属性那样由 ng 自动管理,因此我们需要自行管理订阅,以免产生内存泄漏。 + +这样,我们可以实现不需要对应数据的(父组件到子组件的)纯事件传递。 + +相比于直接的数据输入而言,事件流输入更有利于对组件内部状态的控制。 + + +### 实例访问:向下 + ++ 通信源:父组件与子组件 ++ 数据方向:父组件 <=> 子组件(可任意方向或双向同时) ++ 信号方向:父组件 => 子组件 + +输入属性的一个优势是低耦合性,父组件无需知晓子组件/指令的类型信息,只需要已经子组件的一个或几个输入项即可。 + +但是有些时候,当组件/指令间有明确的固定关系,并且我们需要细粒度操作的时候,我们也可以选择提升耦合性来简化通信过程。 + +ng1 中,我们可以在 [Directive Definition Object](https://docs.angularjs.org/api/ng/service/$compile#directive-definition-object) 中指定 `require` 属性来获取同宿主或父指令(的控制器)的实例。而在 ng2 中我们还可以获取子组件的实例,并且配置更为简单,只需要借助 [@ViewChild()](https://angular.io/docs/ts/latest/api/core/index/ViewChild-decorator.html)/[@ViewChildren()](https://angular.io/docs/ts/latest/api/core/index/ViewChildren-decorator.html) 或 [@ContentChild()](https://angular.io/docs/ts/latest/api/core/index/ContentChild-decorator.html)/[@ContentChildren()](https://angular.io/docs/ts/latest/api/core/index/ContentChildren-decorator.html) 声明属性即可: + +```typescript +@Component({ + template: ` + + ` +}) +class Parent implements AfterViewInit { + @ViewChild(Child) child: Child + + ngAfterViewInit(): void { + const someChildProp = this.child.someProp + const result = this.child.someMethod('abc') + } +} + +@Component({ + selector: 'child' +}) +class Child implements OnInit { + someProp: number + + someMethod(input: string): string { + return `${input} operated by child` + } +} +``` + +上面的代码中,我们在父组件中获取到了子组件的实例,并且直接访问子组件的公开属性和方法(TypeScript 不加可访问性修饰符即默认为 public)。之所以需要在 [AfterViewInit](https://angular.io/docs/ts/latest/api/core/index/AfterViewInit-class.html) 这个生命周期后才能操作,是由于父组件的初始化过程在子组件之前,因此在父组件的构造函数或 OnInit 阶段子组件还未实例化,当然也就无从获取。 + +这样可以较为方便的实现复杂操作,例如同时输入或输出多项数据(如果使用多个输出属性会很 Tricky,因为事件响应相互独立),还能够进行实时反馈(即双向数据传输)。 + +一个常见的例子是我们基于 [NgModel](https://angular.io/docs/ts/latest/api/forms/index/NgModel-directive.html) 封装自己的输入控件,其中往往会需要对 NgModel 的 API 进行细粒度操作。对于这样的复杂操作而言,基于数据绑定和事件绑定会让代码过于复杂,工程上几乎不可行。 + +### 实例访问:向上 + ++ 通信源:父组件与子组件/同宿主组件与指令 ++ 数据方向:父组件 <=> 子组件/任一组件或指令 <=> 任一组件或指令 ++ 信号方向:父组件 <= 子组件/任一组件或指令(使用依赖方) => 任一组件或指令(作为依赖方) + +同样的,我们也能够从子组件/指令获取父组件或同宿主组件/指令的实例,具体的方式对于大家来说既熟悉又陌生,那就是依赖注入: + +```typescript +@Component({ + template: ` + + + + ` +}) +class Parent implements AfterViewInit { + children: Child[] = [] + + register(child: Child) { + this.children.push(child) + } +} + +@Component({ + selector: 'child' +}) +class Child implements OnInit { + constructor(private parent: Parent) {} + + ngOnInit(): void { + this.parent.register(this) + } +} +``` + +上面的代码中,我们在子组件的构造函数中注入了父组件的实例,如果有需要我们还可以通过 [@Self()](https://angular.io/docs/ts/latest/api/core/index/Self-decorator.html),[@SkipSelf()](https://angular.io/docs/ts/latest/api/core/index/SkipSelf-decorator.html) 和 [@Host()](https://angular.io/docs/ts/latest/api/core/index/Host-decorator.html) 来限制该实例的来源,比 ng1 中的 `^` 符号组合显然清晰的多。 + +由于子组件/指令构造时父组件早已构造完成,因此可以无需等待直接获取到父组件的实例。 + +这里我们使用了一个子组件自行向父组件登记自身存在的例子,相比于父组件一次性获取所有子组件实例,这样的优势是能够动态增删子组件列表。一个应用实例就是 [NgForm](https://angular.io/docs/ts/latest/api/forms/index/NgForm-directive.html) 与 [NgControl](https://angular.io/docs/ts/latest/api/forms/index/NgControl-class.html) 之间的交互,由于表单可能在使用过程中动态变化,所以无法在表单初始化时一次性获取所有控件实例,而需要支持使用中动态注册与注销控件的功能。 + + +### 实例访问:服务 + ++ 通信源:组件与服务 ++ 数据方向:组件 <=> 服务 ++ 信号方向:组件 <=> 服务 + +事实上,实例操纵这种方式我们一直都在使用,例如组件对服务的访问: + +```typescript +@Component({ + template: ` +

    Whatever

    + ` +}) +class SomeComponent implements OnInit { + constructor(private someService: SomeService) { } + + ngOnInit(): void { + this.someService.someMethod() + } +} + +@Injectable() +class SomeService { + someMethod(): void { } +} +``` + +上面的代码中,我们使用 [@Injectable()](https://angular.io/docs/ts/latest/api/core/index/Injectable-decorator.html) 来修饰我们的服务。不过事实上,@Injectable() 并不是指可以被注入到别的内容中,而是指别的内容可以被注入进来,由于我们这里 SomeService 并不依赖于其他内容,故完全可以不使用 @Injectable()。但为了代码一致性,对全体服务都使用 @Injectable() 装饰能够让代码更加清晰。 + +此外,服务也一样能够配合 Observable 使用,例如 [Location](https://angular.io/docs/ts/latest/api/common/index/Location-class.html) 和 [ActivatedRoute](https://angular.io/docs/ts/latest/api/router/index/ActivatedRoute-interface.html) 就提供了持续的事件流,因此也能够实现服务到组件的信号传递。 + + +### 输出:事件 + ++ 通信源:父组件与子组件 ++ 数据方向:父组件 <= 子组件(可空) ++ 信号方向:父组件 <= 子组件 + +与输入属性相对应,每个组件/指令都可以通过 [@Output](https://angular.io/docs/ts/latest/api/core/index/Output-interface.html) 来指定输出属性,每个输出属性都是 [EventEmitter](https://angular.io/docs/ts/latest/api/core/index/EventEmitter-class.html) 的一个实例,前者继承自 Reactive Extensions 中的 [Subject](http://reactivex.io/rxjs/class/es6/Subject.js~Subject.html)。 + +```typescript +@Component({ + template: ` + + ` +}) +class Parent { + onOutput(event: number): void { + console.log(event) + } +} + +@Component({ + selector: 'child' +}) +class Child implements OnInit { + @Output() output = new EventEmitter() + + onInit(): void { + this.output.emit(123) + } +} +``` + +由于这里的 Subject 由 ng 进行管理,我们无需关心 subscribe 和 unsubscribe 的调用,只需要简单应对事件侦听即可。 + + +### 提供商:单值 + ++ 通信源:父组件与子组件 ++ 数据方向:父组件 => 子组件 ++ 信号方向:父组件 => 子组件 + +归功于 ng2 引入的 [Hierarchical Injector](https://angular.io/docs/ts/latest/guide/hierarchical-dependency-injection.html) 机制,每个组件/指令都可以有独立(并继承)的 Injector。相比于 ng1 中的全局唯一的 Injector 而言,在 ng2 中我们可以对提供商进行细粒度控制。 + +我们可以使用 @Optional 的依赖来进行数据传递(或者在模块/根组件中提供默认内容): + +```typescript +@Component({ + template: ` + + `, + providers: [ + { provide: 'someToken', useValue: 123 } + ] +}) +class Parent { } + +@Component({ + selector: 'child' +}) +class Child implements OnInit { + constructor(@Inject('someToken') private someProp: number) { } +} +``` + +通过提供商(默认为单值)进行通信的一个特点是静态性,即所需传输的内容一经确定就不可再更改(我们这里使用了 useValue 提供常量,实际上还能通过 useFactory 即时生成内容),并且具有明确的层次性,上层能够对所有下层提供数据,并且中间层能够覆盖上层内容。 + +一个很常见的例子就是用于制作开关(或其他辅助标识),或者应用策略模式。 + + +### 提供商:多值 + ++ 通信源:同宿主组件与指令 ++ 数据方向:任一组件/指令 <= 若干组件/指令 ++ 信号方向:任一组件/指令 => 若干组件/指令 + +上面我们已经知道了 @ViewChildren() ,可以一次性获取到全体某个类型的子组件/指令列表。同时也知道了依赖注入可以得到同宿主的组件/指令实例。 + +但还有一个场景解决不了,就是我们需要得到同宿主的多个同 "类型" 的全体指令。(当然,这里的类型并不是真的 JavaScript 类型,因为一个指令在一个元素上至多只会被应用一次,可以理解为相同标识) + +在 ng2 中,有一个黑魔法可以解决这个问题,就是设置了 `multi: true` 的提供商,这类提供商可以被多次注册,并且不会被覆盖,而是会进行汇总: + +```typescript +@Component({ + template: ` +

    Whatever

    + ` +}) +class SomeComponent { + constructor(@Inject('magicNumber') tokens: number[]) { + console.log(tokens) // [1, 2] + } +} + +@Directive({ + selector: '[propOne]', + providers: [ + { provide: 'magicNumber', useValue: 1, multi: true } + ] +}) +class DirectiveOne { } + +@Directive({ + selector: '[propTwo]', + providers: [ + { provide: 'magicNumber', useValue: 2, multi: true } + ] +}) +class DirectiveTwo { } +``` + +这样,通过某个共同的 Token,每个组件/指令都可以得到其他组件/指令给出的材料,而无需知晓其他组件/指令的具体存在。 + +一个应用实例是 [FormControlName](https://angular.io/docs/ts/latest/api/forms/index/FormControlName-directive.html) 与 [Validator](https://angular.io/docs/ts/latest/api/forms/index/NG_VALIDATORS-let.html) 及 [AsyncValidator](https://angular.io/docs/ts/latest/api/forms/index/NG_ASYNC_VALIDATORS-let.html) 之间的交互,所有 Validator 指令都直接应用在 FromControl 所在的元素上,而 FormControl 无需知道每个 Validator 指令的具体形式(无论是内置的还是自定义的),只需要收集每个 Validator 指令所提供的验证函数即可。 + +当然,这并不是 `multi: true` 的唯一作用,比如我们还能通过 [APP_BOOTSTRAP_LISTENER](https://angular.io/docs/ts/latest/api/core/index/APP_BOOTSTRAP_LISTENER-let.html) 来监听应用的启动等等。 + + +## 速查表 + +说了这么多,那么我们在应用中应该如何选择这些通信方式呢?这里提供了简单的决策树,以帮助读者快速进行查阅。(仅仅提供参考,并不一定是具体场景下最优选择,实际项目请以自身实际情况为准) + +```text +1.是否为组件/指令间通信? +| +|- T +| |- 2. 是否有位置关系? +| | +| |- T +| | |- 3. 是否有明确的行为关联(固定搭配)? +| | | +| | |- T +| | | |- 4. 是否具有固定的上下级关系 +| | | | +| | | |- T +| | | | |- 5. 是否仅需由上至下提供不可变内容? +| | | | | +| | | | |- T +| | | | | |- (提供商:单值) +| | | | | +| | | | |- F +| | | | |- 6. 子组件/指令是否会动态变化? +| | | | | +| | | | |- T +| | | | | |- (实例访问:向上) +| | | | | +| | | | |- F +| | | | |- (实例访问:向下) +| | | |- F +| | | |- 7. 是否明确处于同一宿主内? +| | | | +| | | |- T +| | | | |- 8. 是否有多个组件/指令同时作为数据源? +| | | | | +| | | | |- T +| | | | | |- 9. 是否仅需提供不可变内容? +| | | | | | +| | | | | |- T +| | | | | | |- (提供商:多值) +| | | | | | +| | | | | |- F +| | | | | |- (/*借助父组件/指令通信*/) +| | | | |- F +| | | | |- 10. 是否仅需提供不可变内容? +| | | | | +| | | | |- T +| | | | | |- (提供商:单值) +| | | | | +| | | | |- F +| | | | |- (实例访问:向上) +| | | |- F +| | | |- 11. 是否明确为兄弟关系? +| | | |- T +| | | | |- (/*借助父组件/指令通信*/) +| | | | +| | | |- F +| | | |- 那还叫什么固定搭配! +| | |- F +| | |- 12. 方向是否为由父向子? +| | | +| | |- T +| | | |- 13. 输入是否影响自身以外的其他子组件内部状态? +| | | | +| | | |- T +| | | | |- (输入:事件) +| | | | +| | | |- F +| | | |- (输入:数据) +| | |- F +| | |- 方向是否为由子向父? +| | | +| | |- T +| | | |- (输出:事件) +| | | +| | |- F +| | |- (/*借助父组件/指令通信*/) +| |- F +| |- (/*借助服务通信*/) +| +|- F + |- 是否为组件与服务间通信 + |- T + | |- (实例访问:服务) + | + |- F + |- 并不确定你要做什么~ +``` + + +## 总结 + +1. ng2 应用结构基于组件树; +2. 组件/指令相互之间,组件/指令与服务之间需要相互通信; +3. 通信方式有很多种,选择合适的通信方式对应用实现会有很大帮助。 diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 65541d8..e5ca27a 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -316,6 +316,15 @@ const items: Article[] = [ first: true, tags: ['rxjs'], authors: ['timliu'], + }, + { + id: 'Angular2中的通信方式', + title: 'Angular2中的通信方式', + summary: 'Angular 2 中,我们难免需要进行组件间的相互通信,但是这些通信方式你真的都知道吗?', + content: require('./280.Angular2中的通信方式/_index.md'), + first: true, + tags: ['ng2'], + authors: ['trotyl'], } ]; From 46f5fbaa9b35e4a4453bd1327d2d1e4295fbdc04 Mon Sep 17 00:00:00 2001 From: Trotyl Date: Mon, 21 Nov 2016 03:07:04 +0800 Subject: [PATCH 074/177] Fix missing parenthesis. --- .../_index.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/src/app/_shared/api/articles/280.Angular2\344\270\255\347\232\204\351\200\232\344\277\241\346\226\271\345\274\217/_index.md" "b/src/app/_shared/api/articles/280.Angular2\344\270\255\347\232\204\351\200\232\344\277\241\346\226\271\345\274\217/_index.md" index 106b2cb..06d7ada 100644 --- "a/src/app/_shared/api/articles/280.Angular2\344\270\255\347\232\204\351\200\232\344\277\241\346\226\271\345\274\217/_index.md" +++ "b/src/app/_shared/api/articles/280.Angular2\344\270\255\347\232\204\351\200\232\344\277\241\346\226\271\345\274\217/_index.md" @@ -287,7 +287,7 @@ class Child implements OnInit { 归功于 ng2 引入的 [Hierarchical Injector](https://angular.io/docs/ts/latest/guide/hierarchical-dependency-injection.html) 机制,每个组件/指令都可以有独立(并继承)的 Injector。相比于 ng1 中的全局唯一的 Injector 而言,在 ng2 中我们可以对提供商进行细粒度控制。 -我们可以使用 @Optional 的依赖来进行数据传递(或者在模块/根组件中提供默认内容): +我们可以使用 @Optional() 的依赖来进行数据传递(或者在模块/根组件中提供默认内容): ```typescript @Component({ From 0f3ac54195e813ddbbc57e2c5d27e7c3df865b94 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Sun, 20 Nov 2016 21:10:34 -0800 Subject: [PATCH 075/177] simple-prototype-chain wip --- .../timliu/simple-prototype-chain/_index.md | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md diff --git a/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md new file mode 100644 index 0000000..34bb7ad --- /dev/null +++ b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md @@ -0,0 +1,54 @@ +# 白话 JS 的原型链 + + +## 写作原因/目的 +> 本文记录笔者学习 JS 原型链的过程中的一些心得。了解原型链的教授们可以跳过本文,想看干货的同学们可以跳到第二部分。 + +对于在当前环境下的 Web 前端的初学者来说,一个很容易忽略的学习点是 JS 的原型链(别问我是怎么知道的)。 +为什么会这样?我觉得有这样两方面原因: + +1. 技术进步了,我们在不了解 JS 底层(比如原型链,我的底线比较高)的情况下,就可以做出产品,不用自己造轮子。 + 而技术进步至少体现在: + - 现在有 ES6,应用 extends 关键字扩展一个 class,实际上就是在应用原型链,即使我们不知道什么是原型链; + - 现在有强大的框架,比如在 Angular 里,我们有现成的 directive、component 等等,不需要知道 component 是怎样继承了 directive。 +2. 这个原型链的技术文档真的是太...太...底层了,大家来体会一下: + > 根据 ECMAScript 标准,someObject.[[Prototype]] 符号是用于指派 someObject 的原型。 + 这个等同于 JavaScript 的 \_\_proto__ 属性(现已弃用)。 + It should not be confused with the func.prototype property of functions, + which instead specifies the [[Prototype]] of all instances of the given function. + 从 ECMAScript 6 开始, [[Prototype]] 可以用Object.getPrototypeOf()和Object.setPrototypeOf()访问器来访问。 + + 上面这段摘自MDN的文档《[继承与原型链][]》,英文版文档比中文的多了一句,插播在这里,没有翻译。 + 这段里,形似 proto 的东西有三个: + - `someObject.[[Prototype]]内部属性`:这个是大写的 Prototype 被“双重方括号”括起来,我在console里敲一个,SyntaxError?! + - `someObject.__proto__属性`:这个是 proto 的左右两边各有两个下划线,“现已弃用”?那学它干啥?! + - `func.prototype属性`:这个是 func 的一个属性,“not to be confused with ...”?我很 confuse ,好吗!?! + + 真是够底层的,还是交给 Angular 们吧,我要去做网站了。 + +就这样,初学者可能每天和原型链打着交道,却不想多看它一眼,至少我是这样的。 +不过呢,有这样一种场景,使得你不得不去了解原型链 -- 应聘时的笔试。 +当然,这只是开玩笑。了解原型链是学习 JS 不可或缺的一环,就像学习编程必须要明白什么事“面向对象”(我先去搜索引擎上看看)。 +本文尝试使用白话(尽量不使用术语)来解释原型链。 + +## 干货区 +- `[[Prototype]]内部属性`: +proto即“‘我没有找他’指针” +[[Prototype]]就是被proto指着的那个 +func.prototype是被func的实例的proto指着的那个 + +## “\_\_proto__”属性和“[[Prototype]]”内部属性 + +## func.prototype + +## 案例 - 单线继承 + +## 一些operators + + +## 参考 +- [继承与原型链][] +- [Inheritance and the prototype chain][] + +[继承与原型链]: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain +[Inheritance and the prototype chain]:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain \ No newline at end of file From a6b335add4b0df26d901411402340dd0bcb670c5 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Mon, 21 Nov 2016 19:27:28 -0800 Subject: [PATCH 076/177] wip - table and non-table co-exists --- .../timliu/simple-prototype-chain/_index.md | 237 ++++++++++++++++-- 1 file changed, 219 insertions(+), 18 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md index 34bb7ad..0891550 100644 --- a/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md @@ -1,8 +1,8 @@ # 白话 JS 的原型链 +> 本文记录笔者学习 JS 原型链的过程中的一些心得。了解原型链的教授们可以跳过本文,想看干货的同学们可以从[第二部分](#干货区)开始。 ## 写作原因/目的 -> 本文记录笔者学习 JS 原型链的过程中的一些心得。了解原型链的教授们可以跳过本文,想看干货的同学们可以跳到第二部分。 对于在当前环境下的 Web 前端的初学者来说,一个很容易忽略的学习点是 JS 的原型链(别问我是怎么知道的)。 为什么会这样?我觉得有这样两方面原因: @@ -13,42 +13,243 @@ - 现在有强大的框架,比如在 Angular 里,我们有现成的 directive、component 等等,不需要知道 component 是怎样继承了 directive。 2. 这个原型链的技术文档真的是太...太...底层了,大家来体会一下: > 根据 ECMAScript 标准,someObject.[[Prototype]] 符号是用于指派 someObject 的原型。 - 这个等同于 JavaScript 的 \_\_proto__ 属性(现已弃用)。 + 这个等同于 JavaScript 的 `__proto__` 属性(现已弃用)。 It should not be confused with the func.prototype property of functions, which instead specifies the [[Prototype]] of all instances of the given function. 从 ECMAScript 6 开始, [[Prototype]] 可以用Object.getPrototypeOf()和Object.setPrototypeOf()访问器来访问。 上面这段摘自MDN的文档《[继承与原型链][]》,英文版文档比中文的多了一句,插播在这里,没有翻译。 这段里,形似 proto 的东西有三个: - - `someObject.[[Prototype]]内部属性`:这个是大写的 Prototype 被“双重方括号”括起来,我在console里敲一个,SyntaxError?! - - `someObject.__proto__属性`:这个是 proto 的左右两边各有两个下划线,“现已弃用”?那学它干啥?! - - `func.prototype属性`:这个是 func 的一个属性,“not to be confused with ...”?我很 confuse ,好吗!?! + - `someObject.[[Prototype]]内部属性`:大写的 Prototype 被“双重方括号”括起来,我在console里敲一个,SyntaxError?! + - `someObject.__proto__属性`:proto 的左右两边各有两个下划线(跟markdown没关系),“现已弃用”?那学它干啥?! + - `func.prototype属性`:func是啥?func.prototype又是啥?“not to be confused with ...”?我很 confuse ,好吗!?! - 真是够底层的,还是交给 Angular 们吧,我要去做网站了。 + 真是够底层的,还是交给 Angular 们来对付这些 proto 吧,我要去做网站了。 -就这样,初学者可能每天和原型链打着交道,却不想多看它一眼,至少我是这样的。 +就这样,初学者可能每天使用着原型链,却不想多看它一眼,至少我是这样的。 不过呢,有这样一种场景,使得你不得不去了解原型链 -- 应聘时的笔试。 -当然,这只是开玩笑。了解原型链是学习 JS 不可或缺的一环,就像学习编程必须要明白什么事“面向对象”(我先去搜索引擎上看看)。 -本文尝试使用白话(尽量不使用术语)来解释原型链。 +当然,这只是开玩笑。了解原型链是学习 JS 不可或缺的一环,就像学习编程必须要明白什么是“面向对象”(我先去搜索引擎上看看)。 +本文尝试使用白话(即尽量不使用术语)来解释原型链。 ## 干货区 -- `[[Prototype]]内部属性`: -proto即“‘我没有找他’指针” -[[Prototype]]就是被proto指着的那个 -func.prototype是被func的实例的proto指着的那个 +(看不明白没关系,后面的段落会一一解释,希望我能解释明白。) +- `[[Prototype]] 内部属性`:我称它为“我没有找它指针”,这个指针是链式的,“我没有?找它;它没有?找它的它...”。 +- `__proto__ 属性`:这个是 [[Prototype]] 的访问器,既是getter,又是setter,即负责读取和设置 [[Prototype]]。 +- `func.prototype`:这可不是 func 的 [[Prototype]]。func是个构造函数,func.prototype是一个人为指定的对象,func的实例的 [[Prototype]] 指向这个 func.prototype。 +- 原型链的尽头是null。 +- 原型链不要太长,没必要的情况下不要改变一个对象的 [[Prototype]],因为: + > The lookup time for properties that are high up on the prototype chain can have a negative impact on performance ... -## “\_\_proto__”属性和“[[Prototype]]”内部属性 + -摘自MDN之《[Inheritance and the prototype chain][]》 + > Changing the [[Prototype]] of an object is ... a very slow operation ... -## func.prototype + -摘自MDN之《[Object.prototype.\_\_proto__][]》 -## 案例 - 单线继承 -## 一些operators +## [[Prototype]] 与 \_\_proto__ +[[Prototype]] 是一个[内部属性][](关于内部属性的定义,参看链接),我们不能直接读取或设置一个内部属性,那需要读取或设置的时候怎么办?用 `__proto__`。 +`__proto__` 是 [[Prototype]] 的访问器,既是getter,又是setter,即同时负责读取和设置 [[Prototype]]。 +如果我们能过直接访问 [[Prototype]],那么会有以下代码: +```js +someObject.[[Prototype]] === someObject.__proto__ // __proto__ 在这里是getter,读取 [[Prototype]] +// 下面两行等效 +someObject.[[Prototype]] = anotherObject; +someObject.__proto__ = anotherObject; // __proto__ 在这里是setter,设置 [[Prototype]] +``` + +我称 [[Prototype]] 为“我没有找它指针”,这个指针究竟有什么用呢? +看栗子(F12打开浏览器console,贴入下面代码)(例1): +```js +var lurenJia = {x: 0, y: 0}, ObjA = {x: 1, a: 1}; +lurenJia.__proto__ = ObjA; // 将 lurenJia 的 [[Prototype]] 指向ObjA,此时,我们可以说 ObjA 就是 lurenJia 的原型 +var assert0 = lurenJia.__proto__ === ObjA; +var assert1 = lurenJia.x !== ObjA.x; // lurenJia 有 x 属性,不用 ObjA 的 x +var assert2 = lurenJia.a === ObjA.a // lurenJia 没有 a 属性,“我没有找它指针”指向 ObjA,ObjA 上有,就用 ObjA.a + +var ObjB = {y: 2, a: 2, b: 2}; +ObjA.__proto__ = ObjB // 将 ObjA 的 [[Prototype]] 设置为ObjB +var assert3 = ObjA.__proto__ === ObjB; +var assert4 = lurenJia.__proto__ !== ObjB; +var assert5 = lurenJia.__proto__.__proto__ === ObjB; // 看到链了吗?不是烤串哦。 + +var assert6 = lurenJia.y !== ObjB.y; // lurenJia 有 y 属性,不去 ObjA 或 ObjB 上找 +var assert7 = lurenJia.a !== ObjB.a; // lurenJia 没有 a,ObjA 有,就用 ObjA.a,就不去 ObjB上找了 +var assert8 = lurenJia.b === ObjB.b; // lurenJia 没有 b,“我没有找ObjA”,“ObjA 没有找 ObjB”,在 ObjB上找到了 +// 原型链在行动 + +var assertCombined = assert0 && assert1 && assert2 && assert3 && assert4 && assert5 && assert6 && assert7 && assert8; +console.log(assertCombined); //true +``` +someObject的 [[Prototype]] 指向someObject的原型,它的作用就是当我们在 someObject 上找不到某个属性的时候,就去其 [[Prototype]] 指向的对象上去找; +比如,要访问 lurenjia.b,先在 lurenjia 上找,没到到,去 lurenjia 的 [[Prototype]] 指向的对象即 ObjA 上找,ObjA上也没有,就去 ObjA 的 [[Prototype]] 指向的对象(ObjB)上找,直到世界的尽头(参看后面的[原型链的尽头](#原型链的尽头)一节)。 + +## func.prototype 与 new 运算符 +在“例1”里,我们看到了原型链在行动,不过,好像还缺点什么。比如,我们需要一个lurenYi,它和lurenJia很像,只是有自己的 y 属性。我们要怎么做呢?看例子: + +第n行|例2 |例3 +-----|--------------------------|-------------------------- +1 |`var ObjA = {x: 1, a: 1};`|`var ObjA = {x: 1, a: 1};` + |`// 略去若干行` +2 |空 |`var func = function(n) {this.y = n;}` +3 |空 |`func.prototype = ObjA;` +4 |`var lurenYi = {};` |`var lurenYi = {};` +5 |`lurenYi.__proto__ = ObjA;`|`lurenYi.__proto__ = func.prototype;` +6 |`lurenYi.y = 9;` |`func.call(lurenYi, 9);` + +“例2”表述直白,第4行让 lurenYi 指向一个空的 object,然后设置 lurenYi 的 [[Prototype]] 指向 ObjA,然后向 lurenYi 添加属性 y。 +“例3”看上去有些麻烦,在第2行新建了一个函数(这个就是“构造函数”,后面会详细说明),然后,注意这里是重点,然后在这个函数上, +人为的加上了一个 prototype 属性(这个 prototype 属性与 [[Prototype]] 是没有任何关系的),然后让 func.prototype 指向 ObjA。 +而后,设置 lurenYi 的 [[Prototype]] 指向 func.prototype。再调用 func,以 lurenYi 为 this。为什么要这样做?继续看例子: + +第n行|例3 |例4 +-----|------------------------------------- |-------------------------- +1 |`var ObjA = {x: 1, a: 1};` |`var ObjA = {x: 1, a: 1};` + |`// 略去若干行` +2 |`var func = function(n) {this.y = n;}`|`var func = function(n) {this.y = n;}` +3 |`func.prototype = ObjA;` |`func.prototype = ObjA;` +4 |`var lurenYi = {};` |`var lurenYi = new func(9);` +5 |`lurenYi.__proto__ = func.prototype;` |空 +6 |`func.call(lurenYi, 9);` |空 + + +我们可以这样(例2): +```js +var ObjA = {x: 1, a: 1}; +// ... 略去若干行 +var lurenYi = {}; // 新建一个空的object +lurenYi.__proto__ = ObjA; // 将 lurenYi 的 [[Prototype]] 设置为 ObjA +lurenYi.y = 9; +``` +我们还可以这样(看上去好麻烦)(例3): +```js +var ObjA = {x: 1, a: 1}; +// ... 略去若干行 +var func = function(n) {this.y = n;} // 创建一个“构造函数” func,构造函数(constructor)是用来生成实例的函数 +func.prototype = ObjA; // 人为的在 func 上添加一个 prototype 属性,并让 prototype 属性指向 ObjA +// 其实JavaScript在 func 生成时自动设置了 func 的 prototype 属性,我们这里做的是改变这个 prototype 属性 + +// 后面3行,例4里没有,被 new 运算符代替 +var lurenYi = {}; +lurenYi.__proto__ = func.prototype; // 将 lurenYi 的 [[Prototype]] 设置为 func.prototype,即 ObjA +func.call(lurenYi, 9); // 使用构造函数来设置 lurenYi.y + +lurenYi.y === 9 // true +``` +我们还可以这样(简单了一些,可是有啥用?)(例4): +```js +var ObjA = {x: 1, a: 1}; +// ... 略去若干行 +var func = function(n) {this.y = n;} // 与“例3”相同 +func.prototype = ObjA; // 与“例3”相同 +var lurenYi = new func(9); // 很厉害的样子 +lurenYi.y === 9 // true +``` +一个 new 运算符,就搞定了“新建实例为空对象、设置实例 [[Prototype]] 指向构造函数的 prototype 属性、运行 `func.call(lunrenYi)`”三个步骤。 +new 运算符怎么这么牛?答:JavaScript就是这么设计的。注意第二步,根据“设计”,实例的 [[Prototype]] 指向的必须是 prototype 属性。 +显而易见,后面如果我们需要 lurenBing,可以`var lurenBing = new func(10);`,新建实例变得简单多了。 + +所以呢,func.prototype 是一个人为设定的属性(JavaScript会自动设置这个属性,但也是根据事先设定好的剧本来设置的,而且我们可以事后更改), +new 一个 func 的实例的时候,实例的 [[Prototype]] 指向 func.prototype。 + +## 使用构造函数的情况下的原型链 +在使用构造函数的情况下,原型链是什么样的呢? 一个构造函数又是如何继承另一个构造函数的呢(这个问题问的不妥,后面解释)? + +回顾“例1”,其中的原型链是这样:`lurenJia --> ObjA --> ObjB`,写成 assertion 就是: +```js +lurenJia.__proto__ === ObjA; +ObjA.__proto__ === ObjB; +``` + +经过上一节,我们已经有了 func 这个构造函数,假设我们还有一个 funcFoo 构造函数,它继承了func(这个说法不妥,后面解释),而foo是funcFoo的一个实例,原型链是什么样的呢? +`foo --> funcFoo --> func`,是这样的吗?No no no! +应该是这样的:`foo --> funcFoo.prototype --> func.prototype`。写成 assertion 是: +```js +foo.__proto__ === funcFoo.prototype; // 这是实例的 [[Prototype]] 指向其构造函数的 prototype 属性,这个在“例3”里看过了 +funcFoo.prototype.__proto__ === func.prototype; // 后代构造函数的 prototype 属性的 [[Prototype]] 指向上一级构造函数的 prototype 属性 +``` +我们看到,说“构造函数继承另一个构造函数”是不妥的,应该是后代构造函数的 prototype 属性的 [[Prototype]] 继承了(指向)上级构造函数的 prototype 属性。 +为什么原型链是`foo --> funcFoo.prototype --> func.prototype`?答案还是:JavaScript就是这样设计的,这样可以配合 new,简化建立实例的过程。 + +那么,怎么才能让`funcFoo.prototype.__proto__ === func.prototype;`的结果是 true 呢? +赋值(value assignment)咯:`funcFoo.prototype.__proto__ = func.prototype`。这样原型链就有了。 + +原型链保证了每个实例共享链上的属性、方法,但是新建实例的时候,每个实例不同于其他实例的属性怎么设置呢?还记得“例3”里的 `lurenYi.y` 是怎么来的么? +调用构造函数咯,不过在后代构造函数里还要调用上一级构造函数,即`var funcFoo = function() {func.call(this); ...}`。 +让我们看例子吧(改编自MDN文档《[Object.prototype][]》中的一个示例)(例5): + +```js +var Person = function() { + this.canTalk = true; +}; // 这个是上级构造函数 + +Person.prototype.greet = function() { + if (this.canTalk) { + console.log('Hi, I am ' + this.name); + } +}; // 这是上级构造函数的prototype上的一个方法 + +var Employee = function(name, title) { + Person.call(this); // 后代构造函数中调用上一级构造函数 + this.name = name; + this.title = title; +}; // 这是后代构造函数 + +Employee.prototype.__proto__ = Person.prototype; // 设置后代构造函数的 prototype 的 [[Prototype]] 指向上一级的 prototype +Employee.prototype.constructor = Employee; // 这个后面的func.prototype.constructor会解释 + +var john = new Employee('John', 'CXO'); // 新建一个实例,原型链是 john --> Employee.prototype --> Person.prototype +// new 相当于:var john = {}; john.__proto__ = Employee.prototype; Employee.call(john); +john.canTalk === true; // true. 这是调用了上级构造函数得到的 +john.greet(); // Hi, I am John. 这是上级构造函数prototype上的方法 +``` + +## 杂项 +以上是本篇主要内容,下面提一些杂七杂八的东西: + +### 性能考量 +重复干货部分的内容:原型链不要太长;没必要的话不要改变一个对象的[[Prototype]]。 + +### 几个相关方法、运算符 +- `__proto__` 已被弃用,读取 [[Prototype]] 的时候用 `Object.getPrototypeOf(someObject)` ,设置 [[Prototype]] 的时候用 `Object.setPrototypeOf(someObject)`。 +因为在浏览器的console里,在所有的Object上还是可以看到 `__proto__`,本文暂且还是使用 `__proto__` 来读取或设置 [[Prototype]]。 +- 另外,在“例5中”,`Employee.prototype.__proto__ = Person.prototype;`,《[Object.prototype][]》中用的是`Employee.prototype = Object.create()`,这两个是等效的。 +- SomeType.isPrototypeOf(someObject) +- someObject instanceof SomeType +- someObject.constructor +## 构造函数 return 一个 object 的时候 + +### 原生构造函数 +Object, Function, Array, String, Number,Boolean,RegExp等等。 + + +箭头function +### 原型链的尽头 + +### func.prototype.constructor +这个没啥用,除非真的想用。参看《[Why is it necessary to set the prototype constructor?][]》。 +这里说明一下“例5”的`Employee.prototype.constructor = Employee;`,为什么会有这么一行呢? +如果没有这一行,Employee.prototype.constructor 就会继承 Person.prototype.constructor,这样很奇怪。 +那 `Person.prototype.constructor === Person` 是怎么来的呢?是 JavaScript 自动设置的。 +为什么?管他呢,我们现在有了 ES6 的 `class Employee extends Person {}`。 + + + + +## 总结 +[[Prototype]] 是“我没有找它”指针,`__proto__` 是 [[Prototype]] 的访问器,func 的实例的 [[Prototype]] 指向 func.prototype。 ## 参考 - [继承与原型链][] - [Inheritance and the prototype chain][] +- [内部属性][] +- [Object.prototype.\_\_proto__][] +- [Object.prototype][] +- [Why is it necessary to set the prototype constructor?][] [继承与原型链]: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain -[Inheritance and the prototype chain]:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain \ No newline at end of file +[Inheritance and the prototype chain]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain +[内部属性]: http://stackoverflow.com/questions/17174786/what-is-the-significance-of-the-double-brackets-for-the-prototype-property-i +[Object.prototype.\_\_proto__]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto +[Object.prototype]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype +[Why is it necessary to set the prototype constructor?]: http://stackoverflow.com/questions/8453887/why-is-it-necessary-to-set-the-prototype-constructor From da47b7499c8db87fd9d34192ff02a7bfecaa62f1 Mon Sep 17 00:00:00 2001 From: timeCoiner <846432362@qq.com> Date: Tue, 22 Nov 2016 17:17:35 +0800 Subject: [PATCH 077/177] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=94=99=E5=88=AB?= =?UTF-8?q?=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" index 4fe7bd5..a6a6c14 100644 --- "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" +++ "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" @@ -15,7 +15,7 @@ git remote add upstream https://github.com/mgechev/angular-seed.git git fetch upstream git merge upstream/master ``` -平时我们想要更新主仓库时,只要git pull以下upstram远端,就可以保持最新了。如果不想人工手动去更新的化可以交给jenkins定时去更新,这样主心仓库永远是最新的了。 +平时我们想要更新主仓库时,只要git pull一下upstram远端,就可以保持最新了。如果不想人工手动去更新的化可以交给jenkins定时去更新,这样主心仓库永远是最新的了。 ### 创建衍生库: 因为我们所有项目围绕主心库而衍生出来的,所以衍生库和主心库的关心和angular-seed关系一致。我们指定我们衍生库的远端upstream为我们的主心库,这样只要主心库是最新的,这样所有衍生库都可以保持同步更新。可以享受主心库提供的共用配置和 业务逻辑。看上去过程比较繁琐,其实只需要将整个操作过程的指令集合到bash脚本中,执行脚本是指定参数名为你的项目名称。这样快速就可以构建一个angular2项目,所以整套流程适合有复杂业务的项目。 From af37850d8f73f831f131da5a4e9f06340cf93d86 Mon Sep 17 00:00:00 2001 From: timeCoiner <846432362@qq.com> Date: Tue, 22 Nov 2016 17:23:02 +0800 Subject: [PATCH 078/177] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E7=BC=A9=E8=BF=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" index a6a6c14..ba47060 100644 --- "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" +++ "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" @@ -11,7 +11,7 @@ 上面的图画得比较烂,我还是来好好解释一下。首先我们得有一个主心库,这个库十分重要,里面没有业务逻辑的代码,主要是平时开发时所需要的所有脚本,以及npm的一些基本依赖。另外一些共用组件,共用逻辑代码(例如登录验证等等)。主心库创 立完后,我们需要建立一个upstream的远端指向angular-seed项目 ``` -git remote add upstream https://github.com/mgechev/angular-seed.git + git remote add upstream https://github.com/mgechev/angular-seed.git git fetch upstream git merge upstream/master ``` @@ -20,7 +20,7 @@ git remote add upstream https://github.com/mgechev/angular-seed.git 因为我们所有项目围绕主心库而衍生出来的,所以衍生库和主心库的关心和angular-seed关系一致。我们指定我们衍生库的远端upstream为我们的主心库,这样只要主心库是最新的,这样所有衍生库都可以保持同步更新。可以享受主心库提供的共用配置和 业务逻辑。看上去过程比较繁琐,其实只需要将整个操作过程的指令集合到bash脚本中,执行脚本是指定参数名为你的项目名称。这样快速就可以构建一个angular2项目,所以整套流程适合有复杂业务的项目。 ``` -git remote add upstream git@192.168.1.1:/git/main-base + git remote add upstream git@192.168.1.1:/git/main-base git fetch upstream git merge upstream/master ``` @@ -31,7 +31,7 @@ git remote add upstream git@192.168.1.1:/git/main-base ``` gulp build.dev --color --env-config dev ``` - 执行上述命令,就是启动开发dev环境的配置。利用yargs这个node工具去接收我们传递过去的参数,以此来区分开是开发模式下还是prod模式下。下面贴一段代码举例一下: + 执行上述命令,就是启动开发dev环境的配置。利用yargs这个node工具去接收我们传递过去的参数,以此来区分开是开发模式下还是prod模式下。下面贴一段代码举例一下: ``` import { argv } from 'yargs'; @@ -64,5 +64,5 @@ git remote add upstream git@192.168.1.1:/git/main-base 关于开发配置十分细碎,所以不做详述,可以日后咨询。 ## 下篇预告: - 下篇会涉及项目目录结构管理,以及angular2在移动端开发的经验,项目打包上线的经验 - ps: 正在寻找新的工作机会,感兴趣的朋友加我QQ: 846432362 +下篇会涉及项目目录结构管理,以及angular2在移动端开发的经验,项目打包上线的经验 +ps: 正在寻找新的工作机会,感兴趣的朋友加我QQ: 846432362 From 310f454d65346307be9b633dc8854b6d2a58dbc4 Mon Sep 17 00:00:00 2001 From: timeCoiner <846432362@qq.com> Date: Tue, 22 Nov 2016 17:30:11 +0800 Subject: [PATCH 079/177] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=BC=A9=E8=BF=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" index ba47060..bf679d4 100644 --- "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" +++ "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" @@ -54,14 +54,14 @@ } // 具体代码可以克隆angular-seed去查看 ``` -   另外angular2提供[enableProdMode](https://angular.io/docs/ts/latest/api/core/index/enableProdMode-function.html)接口能够优化打包出来的代码,但是我们开发时是不需要用到该接口如何去分离开来呢?gulp有个好插件,完美解决该问题,[gulp-template](https://www.npmjs.com/package/gulp-template)。我们只要在我们 + 另外angular2提供[enableProdMode](https://angular.io/docs/ts/latest/api/core/index/enableProdMode-function.html)接口能够优化打包出来的代码,但是我们开发时是不需要用到该接口如何去分离开来呢?gulp有个好插件,完美解决该问题,[gulp-template](https://www.npmjs.com/package/gulp-template)。我们只要在我们 代码中加入类似<%= BUILD_TYPE %>,这样就可以赋值给BUILD_TYPE,我们可以合理得去控制。 ``` import { enableProdMode } from '@angular/core'; ... if (String('<%= BUILD_TYPE %>') === 'prod') { enableProdMode(); } ``` - 关于开发配置十分细碎,所以不做详述,可以日后咨询。 + 关于开发配置十分细碎,所以不做详述,可以日后咨询。 ## 下篇预告: 下篇会涉及项目目录结构管理,以及angular2在移动端开发的经验,项目打包上线的经验 From b869601d81298adfb7f5358a02bd788b8c90cbb5 Mon Sep 17 00:00:00 2001 From: timeCoiner <846432362@qq.com> Date: Tue, 22 Nov 2016 17:45:16 +0800 Subject: [PATCH 080/177] =?UTF-8?q?=E8=B0=83=E6=95=B4=E7=BC=A9=E8=BF=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" index bf679d4..2a11726 100644 --- "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" +++ "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" @@ -11,55 +11,55 @@ 上面的图画得比较烂,我还是来好好解释一下。首先我们得有一个主心库,这个库十分重要,里面没有业务逻辑的代码,主要是平时开发时所需要的所有脚本,以及npm的一些基本依赖。另外一些共用组件,共用逻辑代码(例如登录验证等等)。主心库创 立完后,我们需要建立一个upstream的远端指向angular-seed项目 ``` - git remote add upstream https://github.com/mgechev/angular-seed.git - git fetch upstream - git merge upstream/master + git remote add upstream https://github.com/mgechev/angular-seed.git + git fetch upstream + git merge upstream/master ``` 平时我们想要更新主仓库时,只要git pull一下upstram远端,就可以保持最新了。如果不想人工手动去更新的化可以交给jenkins定时去更新,这样主心仓库永远是最新的了。 ### 创建衍生库: 因为我们所有项目围绕主心库而衍生出来的,所以衍生库和主心库的关心和angular-seed关系一致。我们指定我们衍生库的远端upstream为我们的主心库,这样只要主心库是最新的,这样所有衍生库都可以保持同步更新。可以享受主心库提供的共用配置和 业务逻辑。看上去过程比较繁琐,其实只需要将整个操作过程的指令集合到bash脚本中,执行脚本是指定参数名为你的项目名称。这样快速就可以构建一个angular2项目,所以整套流程适合有复杂业务的项目。 ``` - git remote add upstream git@192.168.1.1:/git/main-base - git fetch upstream - git merge upstream/master + git remote add upstream git@192.168.1.1:/git/main-base + git fetch upstream + git merge upstream/master ``` ## 项目开发篇: 既然我们构建完项目后,那么马上开工吧。随着前端项目越来越复杂,里面配置文件越来越多。因为开发环境和生产环境需要调用服务端接口地址又是不一样的,像我开发微信项目的,开发环境用测试的appid和生产环境的appid也是不一样的。情况更严重的是我们每个客户都有自己独立的配置信息(所以开始考虑多租户模式,不然下去是大坑)。理想情况下: ``` - gulp build.dev --color --env-config dev + gulp build.dev --color --env-config dev ``` 执行上述命令,就是启动开发dev环境的配置。利用yargs这个node工具去接收我们传递过去的参数,以此来区分开是开发模式下还是prod模式下。下面贴一段代码举例一下: ``` - import { argv } from 'yargs'; - ... - export function templateLocals() { - // 这里就是我们通过env-config变量获取参数 - const configEnvName = argv['env-config'] || argv['config-env'] || 'dev'; - const configPath = Config.getPluginConfig('environment-config'); - const baseConfig = getConfig(configPath, 'base'); - // 依据dev和prod以及对应的路径获取对应的配置文件 - const config = getConfig(configPath, configEnvName); + import { argv } from 'yargs'; + ... + export function templateLocals() { + // 这里就是我们通过env-config变量获取参数 + const configEnvName = argv['env-config'] || argv['config-env'] || 'dev'; + const configPath = Config.getPluginConfig('environment-config'); + const baseConfig = getConfig(configPath, 'base'); + // 依据dev和prod以及对应的路径获取对应的配置文件 + const config = getConfig(configPath, configEnvName); - if (!config) { - throw new Error('Invalid configuration name'); - } + if (!config) { + throw new Error('Invalid configuration name'); + } - return Object.assign(Config, { - ENV_CONFIG: JSON.stringify(Object.assign(baseConfig, config)) - }); - } + return Object.assign(Config, { + ENV_CONFIG: JSON.stringify(Object.assign(baseConfig, config)) + }); + } // 具体代码可以克隆angular-seed去查看 ``` 另外angular2提供[enableProdMode](https://angular.io/docs/ts/latest/api/core/index/enableProdMode-function.html)接口能够优化打包出来的代码,但是我们开发时是不需要用到该接口如何去分离开来呢?gulp有个好插件,完美解决该问题,[gulp-template](https://www.npmjs.com/package/gulp-template)。我们只要在我们 代码中加入类似<%= BUILD_TYPE %>,这样就可以赋值给BUILD_TYPE,我们可以合理得去控制。 ``` - import { enableProdMode } from '@angular/core'; - ... - if (String('<%= BUILD_TYPE %>') === 'prod') { enableProdMode(); } + import { enableProdMode } from '@angular/core'; + ... + if (String('<%= BUILD_TYPE %>') === 'prod') { enableProdMode(); } ``` 关于开发配置十分细碎,所以不做详述,可以日后咨询。 From 119c1dd2b9ef40d0b409b6c90ad1234c083a5692 Mon Sep 17 00:00:00 2001 From: timeCoiner <846432362@qq.com> Date: Tue, 22 Nov 2016 17:46:37 +0800 Subject: [PATCH 081/177] Update _index.md --- .../_index.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" index 2a11726..874af66 100644 --- "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" +++ "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" @@ -65,4 +65,4 @@ ## 下篇预告: 下篇会涉及项目目录结构管理,以及angular2在移动端开发的经验,项目打包上线的经验 -ps: 正在寻找新的工作机会,感兴趣的朋友加我QQ: 846432362 +ps: 感兴趣的朋友加我QQ: 846432362 From 2751e6ce0599613719e4e15e82aaed66f7bb9465 Mon Sep 17 00:00:00 2001 From: timeCoiner <846432362@qq.com> Date: Tue, 22 Nov 2016 04:18:17 -0600 Subject: [PATCH 082/177] update --- .../_index.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" index 874af66..2f0b603 100644 --- "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" +++ "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" @@ -65,4 +65,4 @@ ## 下篇预告: 下篇会涉及项目目录结构管理,以及angular2在移动端开发的经验,项目打包上线的经验 -ps: 感兴趣的朋友加我QQ: 846432362 +ps: 正在找工作,朋友可以加我QQ: 846432362 From c5aecdf795d04ee5d034d363dca3efc08e3077d6 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Tue, 22 Nov 2016 02:26:16 -0800 Subject: [PATCH 083/177] simple prototype chain rc-0 --- .../timliu/simple-prototype-chain/_index.md | 290 ++++++++++-------- 1 file changed, 161 insertions(+), 129 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md index 0891550..1a10654 100644 --- a/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md @@ -1,55 +1,52 @@ # 白话 JS 的原型链 -> 本文记录笔者学习 JS 原型链的过程中的一些心得。了解原型链的教授们可以跳过本文,想看干货的同学们可以从[第二部分](#干货区)开始。 +> 本文记录笔者学习 JS 原型链的过程中的一些心得。了解原型链的教授们可以跳过本文,想看干货的同学们可以从[干货区](#干货区)开始。 ## 写作原因/目的 对于在当前环境下的 Web 前端的初学者来说,一个很容易忽略的学习点是 JS 的原型链(别问我是怎么知道的)。 为什么会这样?我觉得有这样两方面原因: -1. 技术进步了,我们在不了解 JS 底层(比如原型链,我的底线比较高)的情况下,就可以做出产品,不用自己造轮子。 - 而技术进步至少体现在: - - 现在有 ES6,应用 extends 关键字扩展一个 class,实际上就是在应用原型链,即使我们不知道什么是原型链; - - 现在有强大的框架,比如在 Angular 里,我们有现成的 directive、component 等等,不需要知道 component 是怎样继承了 directive。 +1. 技术进步了,我们在不了解 JS 底层(比如原型链,我的底线比较高)的情况下,就可以做出产品,不用自己造轮子。而技术进步至少体现在: + - 现在有 ES6,应用 extends 关键字扩展一个 class,实际上就是在应用原型链,即使我们不知道什么是原型链; + - 现在有强大的框架,比如在 Angular 里,我们有现成的 Directive、Component 等等,不需要知道 Component 是怎样继承了 Directive。 2. 这个原型链的技术文档真的是太...太...底层了,大家来体会一下: - > 根据 ECMAScript 标准,someObject.[[Prototype]] 符号是用于指派 someObject 的原型。 - 这个等同于 JavaScript 的 `__proto__` 属性(现已弃用)。 - It should not be confused with the func.prototype property of functions, - which instead specifies the [[Prototype]] of all instances of the given function. + > 根据 ECMAScript 标准,someObject.[[Prototype]] 符号是用于指派 someObject 的原型。这个等同于 JavaScript 的 \_\_proto__ 属性(现已弃用)。 + It should not be confused with the func.prototype property of functions, which instead specifies the [[Prototype]] of all instances of the given function. 从 ECMAScript 6 开始, [[Prototype]] 可以用Object.getPrototypeOf()和Object.setPrototypeOf()访问器来访问。 上面这段摘自MDN的文档《[继承与原型链][]》,英文版文档比中文的多了一句,插播在这里,没有翻译。 这段里,形似 proto 的东西有三个: - - `someObject.[[Prototype]]内部属性`:大写的 Prototype 被“双重方括号”括起来,我在console里敲一个,SyntaxError?! - - `someObject.__proto__属性`:proto 的左右两边各有两个下划线(跟markdown没关系),“现已弃用”?那学它干啥?! - - `func.prototype属性`:func是啥?func.prototype又是啥?“not to be confused with ...”?我很 confuse ,好吗!?! + - someObject.[[Prototype]] 内部属性:大写的 Prototype 被“双重方括号”括起来,我在console里敲一个,SyntaxError?! + - someObject.\_\_proto__ 属性:proto 的左右两边各有两个下划线(跟markdown没关系),“现已弃用”?那学它干啥?! + - func.prototype 属性:func是啥?func.prototype又是啥?“not to be confused with ...”?我很 confuse ,好吗!?! 真是够底层的,还是交给 Angular 们来对付这些 proto 吧,我要去做网站了。 -就这样,初学者可能每天使用着原型链,却不想多看它一眼,至少我是这样的。 -不过呢,有这样一种场景,使得你不得不去了解原型链 -- 应聘时的笔试。 +就这样,初学者可能每天都在使用原型链,却不想多看它一眼,至少我是这样的。不过呢,有这样一种场景,使得你不得不去了解原型链 -- 应聘时的笔试。 当然,这只是开玩笑。了解原型链是学习 JS 不可或缺的一环,就像学习编程必须要明白什么是“面向对象”(我先去搜索引擎上看看)。 本文尝试使用白话(即尽量不使用术语)来解释原型链。 +## 读者指引 +假设我们有 Foo 和 foo 两个对象,下面几个说法在本文中意思是一样的: +- foo 继承 Foo +- foo --> Foo +- foo 的 [[Prototype]] 指向 Foo +- foo.[[Prototype]] === Foo +- foo.\_\_proto__ === Foo +- Foo 是 foo 的原型 + ## 干货区 (看不明白没关系,后面的段落会一一解释,希望我能解释明白。) -- `[[Prototype]] 内部属性`:我称它为“我没有找它指针”,这个指针是链式的,“我没有?找它;它没有?找它的它...”。 -- `__proto__ 属性`:这个是 [[Prototype]] 的访问器,既是getter,又是setter,即负责读取和设置 [[Prototype]]。 -- `func.prototype`:这可不是 func 的 [[Prototype]]。func是个构造函数,func.prototype是一个人为指定的对象,func的实例的 [[Prototype]] 指向这个 func.prototype。 +- someObject.[[Prototype]] 内部属性:我称它为“我没有找它指针”,这个指针是链式的,“我没有?找它;它也没有?找它的它...”。原型链由这个内部属性串起。 +- someObject.\_\_proto__ 属性:这个是 [[Prototype]] 的访问器,可以认为 \_\_proto__ 和 [[Prototype]] 等效。 +- func.prototype 属性:func是个构造函数,func的实例的 [[Prototype]] 指向这个 func.prototype,即 func.prototype 是 func 的实例的原型。 - 原型链的尽头是null。 -- 原型链不要太长,没必要的情况下不要改变一个对象的 [[Prototype]],因为: - > The lookup time for properties that are high up on the prototype chain can have a negative impact on performance ... - - -摘自MDN之《[Inheritance and the prototype chain][]》 - > Changing the [[Prototype]] of an object is ... a very slow operation ... - - -摘自MDN之《[Object.prototype.\_\_proto__][]》 +- 关于性能:原型链不要太长,没必要的情况下不要改变一个对象的 [[Prototype]]。 - -## [[Prototype]] 与 \_\_proto__ -[[Prototype]] 是一个[内部属性][](关于内部属性的定义,参看链接),我们不能直接读取或设置一个内部属性,那需要读取或设置的时候怎么办?用 `__proto__`。 -`__proto__` 是 [[Prototype]] 的访问器,既是getter,又是setter,即同时负责读取和设置 [[Prototype]]。 -如果我们能过直接访问 [[Prototype]],那么会有以下代码: +## [[Prototype]] 内部属性 与 \_\_proto__ 属性 +[[Prototype]] 是一个[内部属性][](什么是内部属性?参看链接),我们不能直接读取或设置一个内部属性,需要读取或设置的时候怎么办?那就要看有没有访问器了。 +\_\_proto__ 属性就是 [[Prototype]] 的访问器,它既是getter,又是setter,同时负责读取和设置 [[Prototype]]。如果我们能过直接访问 [[Prototype]],那么会有以下代码: ```js someObject.[[Prototype]] === someObject.__proto__ // __proto__ 在这里是getter,读取 [[Prototype]] // 下面两行等效 @@ -57,8 +54,7 @@ someObject.[[Prototype]] = anotherObject; someObject.__proto__ = anotherObject; // __proto__ 在这里是setter,设置 [[Prototype]] ``` -我称 [[Prototype]] 为“我没有找它指针”,这个指针究竟有什么用呢? -看栗子(F12打开浏览器console,贴入下面代码)(例1): +我称 [[Prototype]] 为“我没有找它指针”,这个指针究竟有什么用呢?看栗子(F12打开浏览器console,贴入下面代码)(例1): ```js var lurenJia = {x: 0, y: 0}, ObjA = {x: 1, a: 1}; lurenJia.__proto__ = ObjA; // 将 lurenJia 的 [[Prototype]] 指向ObjA,此时,我们可以说 ObjA 就是 lurenJia 的原型 @@ -67,7 +63,7 @@ var assert1 = lurenJia.x !== ObjA.x; // lurenJia 有 x 属性,不用 ObjA 的 var assert2 = lurenJia.a === ObjA.a // lurenJia 没有 a 属性,“我没有找它指针”指向 ObjA,ObjA 上有,就用 ObjA.a var ObjB = {y: 2, a: 2, b: 2}; -ObjA.__proto__ = ObjB // 将 ObjA 的 [[Prototype]] 设置为ObjB +ObjA.__proto__ = ObjB // 将 ObjA 的 [[Prototype]] 指向ObjB var assert3 = ObjA.__proto__ === ObjB; var assert4 = lurenJia.__proto__ !== ObjB; var assert5 = lurenJia.__proto__.__proto__ === ObjB; // 看到链了吗?不是烤串哦。 @@ -80,11 +76,13 @@ var assert8 = lurenJia.b === ObjB.b; // lurenJia 没有 b,“我没有找ObjA var assertCombined = assert0 && assert1 && assert2 && assert3 && assert4 && assert5 && assert6 && assert7 && assert8; console.log(assertCombined); //true ``` -someObject的 [[Prototype]] 指向someObject的原型,它的作用就是当我们在 someObject 上找不到某个属性的时候,就去其 [[Prototype]] 指向的对象上去找; -比如,要访问 lurenjia.b,先在 lurenjia 上找,没到到,去 lurenjia 的 [[Prototype]] 指向的对象即 ObjA 上找,ObjA上也没有,就去 ObjA 的 [[Prototype]] 指向的对象(ObjB)上找,直到世界的尽头(参看后面的[原型链的尽头](#原型链的尽头)一节)。 +someObject.[[Prototype]] 的作用就是:当我们在 someObject 上找不到某个属性的时候,就去其 [[Prototype]] 指向的对象上去找,如此往复。 +比如,要访问 lurenJia.b,先在 lurenJia 上找,没到到,去 lurenJia.[[Prototype]] 指向的对象即 ObjA 上找,ObjA上也没有,就去 ObjA.[[Prototype]] 指向的对象(ObjB)上找,直到原型链的尽头(剧透:尽头 === null)。 +如果 lurenJia.[[Prototype]] 指向 ObjA,我们就可以说 lurenJia 继承了 ObjA,或者,ObjA 是 lurenJia 的原型。 -## func.prototype 与 new 运算符 -在“例1”里,我们看到了原型链在行动,不过,好像还缺点什么。比如,我们需要一个lurenYi,它和lurenJia很像,只是有自己的 y 属性。我们要怎么做呢?看例子: +## func.prototype 属性 与 new 运算符 与 构造函数 +在“例1”里,我们看到了原型链在行动,不过,好像还缺点什么。比如,我们需要一个 lurenYi,它和 lurenJia 很像,都是以 ObjA 为原型。 +但是 lurenYi 有自己的 y 属性,不同于 lurenJia。我们要怎么做呢?看例子: 第n行|例2 |例3 -----|--------------------------|-------------------------- @@ -96,12 +94,14 @@ someObject的 [[Prototype]] 指向someObject的原型,它的作用就是当我 5 |`lurenYi.__proto__ = ObjA;`|`lurenYi.__proto__ = func.prototype;` 6 |`lurenYi.y = 9;` |`func.call(lurenYi, 9);` -“例2”表述直白,第4行让 lurenYi 指向一个空的 object,然后设置 lurenYi 的 [[Prototype]] 指向 ObjA,然后向 lurenYi 添加属性 y。 -“例3”看上去有些麻烦,在第2行新建了一个函数(这个就是“构造函数”,后面会详细说明),然后,注意这里是重点,然后在这个函数上, -人为的加上了一个 prototype 属性(这个 prototype 属性与 [[Prototype]] 是没有任何关系的),然后让 func.prototype 指向 ObjA。 -而后,设置 lurenYi 的 [[Prototype]] 指向 func.prototype。再调用 func,以 lurenYi 为 this。为什么要这样做?继续看例子: +“例2”表述直白,第4行先让 lurenYi 指向一个空的 object,然后设置 lurenYi 的 [[Prototype]] 指向 ObjA,然后向 lurenYi 添加属性 y。 +“例2”直白,但是如果我们需要 lurenBing、lurenDing ... ,是不是只能每次重复这3行?看后面。 +“例3”看上去有些麻烦,在第2行新建了一个构造函数(后面会说明什么是构造函数),然后(注意这里是重点),在这个构造函数上, +人为的加上了一个 prototype 属性(func.prototype 与 func.[[Prototype]] 没有任何关系),然后让 func.prototype 指向 ObjA; +而后,设置 lurenYi.[[Prototype]] 指向 func.prototype(最终指向 ObjA);再调用 func,并以 lurenYi 为 this。 +为什么要这样做?继续看例子: -第n行|例3 |例4 +第n行|例3(重复) |例4 -----|------------------------------------- |-------------------------- 1 |`var ObjA = {x: 1, a: 1};` |`var ObjA = {x: 1, a: 1};` |`// 略去若干行` @@ -111,133 +111,163 @@ someObject的 [[Prototype]] 指向someObject的原型,它的作用就是当我 5 |`lurenYi.__proto__ = func.prototype;` |空 6 |`func.call(lurenYi, 9);` |空 +“例4”的第4行,取代了“例3”的第4、第5、第6行,一个 new 运算符,搞定了下面三个步骤: +1. 新建实例,指向空object。 +2. 设置实例的 [[Prototype]] 指向“构造函数”的 prototype 属性(不是指向什么别的属性)。 +3. 调用构造函数,以新建的实例为 this。 -我们可以这样(例2): -```js -var ObjA = {x: 1, a: 1}; -// ... 略去若干行 -var lurenYi = {}; // 新建一个空的object -lurenYi.__proto__ = ObjA; // 将 lurenYi 的 [[Prototype]] 设置为 ObjA -lurenYi.y = 9; -``` -我们还可以这样(看上去好麻烦)(例3): -```js -var ObjA = {x: 1, a: 1}; -// ... 略去若干行 -var func = function(n) {this.y = n;} // 创建一个“构造函数” func,构造函数(constructor)是用来生成实例的函数 -func.prototype = ObjA; // 人为的在 func 上添加一个 prototype 属性,并让 prototype 属性指向 ObjA -// 其实JavaScript在 func 生成时自动设置了 func 的 prototype 属性,我们这里做的是改变这个 prototype 属性 - -// 后面3行,例4里没有,被 new 运算符代替 -var lurenYi = {}; -lurenYi.__proto__ = func.prototype; // 将 lurenYi 的 [[Prototype]] 设置为 func.prototype,即 ObjA -func.call(lurenYi, 9); // 使用构造函数来设置 lurenYi.y - -lurenYi.y === 9 // true -``` -我们还可以这样(简单了一些,可是有啥用?)(例4): -```js -var ObjA = {x: 1, a: 1}; -// ... 略去若干行 -var func = function(n) {this.y = n;} // 与“例3”相同 -func.prototype = ObjA; // 与“例3”相同 -var lurenYi = new func(9); // 很厉害的样子 -lurenYi.y === 9 // true -``` -一个 new 运算符,就搞定了“新建实例为空对象、设置实例 [[Prototype]] 指向构造函数的 prototype 属性、运行 `func.call(lunrenYi)`”三个步骤。 -new 运算符怎么这么牛?答:JavaScript就是这么设计的。注意第二步,根据“设计”,实例的 [[Prototype]] 指向的必须是 prototype 属性。 -显而易见,后面如果我们需要 lurenBing,可以`var lurenBing = new func(10);`,新建实例变得简单多了。 +new 运算符怎么这么牛?为什么new 可以设置实例的 [[Prototype]] 指向构造函数的 prototype 属性? +答:JavaScript就是这么设计的,构造函数的 prototype 属性就是为了配合 new 运算符而存在的。 +后面如果我们需要 lurenBing,可以`var lurenBing = new func(10);`,新建实例变得简单多了。 -所以呢,func.prototype 是一个人为设定的属性(JavaScript会自动设置这个属性,但也是根据事先设定好的剧本来设置的,而且我们可以事后更改), -new 一个 func 的实例的时候,实例的 [[Prototype]] 指向 func.prototype。 +所以呢,func.prototype 是一个人为设定的属性,new 一个 func 的实例的时候,自动设置实例的 [[Prototype]] 指向 func.prototype。 +我们可以说,func.prototype 是它的实例的原型,反过来说就是:实例继承了func.prototype。 +原型链就是:`lurenYi --> func.prototype`,assertion 就是:`lurenYi.__proto__ === func.prototype`。 -## 使用构造函数的情况下的原型链 -在使用构造函数的情况下,原型链是什么样的呢? 一个构造函数又是如何继承另一个构造函数的呢(这个问题问的不妥,后面解释)? +===== 分隔线 ===== -回顾“例1”,其中的原型链是这样:`lurenJia --> ObjA --> ObjB`,写成 assertion 就是: -```js -lurenJia.__proto__ === ObjA; -ObjA.__proto__ === ObjB; -``` +前面提到了构造函数,什么是构造函数呢? +构造函数就用来构造实例的函数,它的任务包括: +1. 初始化一个实例的自有属性(比如 lurenYi.y),所以要求构造函数有一个函数体(即`var func = function(n) {this.y = n;}`)。 +2. 设置实例的 [[Prototype]] 指向构造函数的 prototype 属性,所以要求构造函数有 prototype 属性(即`func.prototype = ObjA;`)。 +另外,在生成一个构造函数的时候,JavaScript会自动给它分配一个 prototype 属性,这一点会在后面“[原生构造函数](#原生构造函数)”一节里说明。 -经过上一节,我们已经有了 func 这个构造函数,假设我们还有一个 funcFoo 构造函数,它继承了func(这个说法不妥,后面解释),而foo是funcFoo的一个实例,原型链是什么样的呢? -`foo --> funcFoo --> func`,是这样的吗?No no no! -应该是这样的:`foo --> funcFoo.prototype --> func.prototype`。写成 assertion 是: -```js -foo.__proto__ === funcFoo.prototype; // 这是实例的 [[Prototype]] 指向其构造函数的 prototype 属性,这个在“例3”里看过了 -funcFoo.prototype.__proto__ === func.prototype; // 后代构造函数的 prototype 属性的 [[Prototype]] 指向上一级构造函数的 prototype 属性 -``` -我们看到,说“构造函数继承另一个构造函数”是不妥的,应该是后代构造函数的 prototype 属性的 [[Prototype]] 继承了(指向)上级构造函数的 prototype 属性。 -为什么原型链是`foo --> funcFoo.prototype --> func.prototype`?答案还是:JavaScript就是这样设计的,这样可以配合 new,简化建立实例的过程。 +## 使用构造函数的情况下的原型链 +在使用构造函数的情况下,原型链是什么样的呢?一个构造函数又是如何继承另一个构造函数的呢(这个问题问的不妥,后面解释)? -那么,怎么才能让`funcFoo.prototype.__proto__ === func.prototype;`的结果是 true 呢? -赋值(value assignment)咯:`funcFoo.prototype.__proto__ = func.prototype`。这样原型链就有了。 +假设我们有一个 Employee 构造函数,我们用 new 运算符生成一个实例 john,根据上一节,他们之间的原型链应该是`john --> Employee.prototype`。 +如果还有一个构造函数 Person,我们有两点需求: +1. 当请求 john.something 属性的时候,如果在 john 上和 Employee.prototype 上都找不到,还要去 Peroson.prototype 上找, + 即原型链是`john --> Employee.prototype --> Person.prototype`; +2. john 的初始化不仅受 Employee 影响,还受 Person 影响(暂且称这个过程为多重初始化)。 -原型链保证了每个实例共享链上的属性、方法,但是新建实例的时候,每个实例不同于其他实例的属性怎么设置呢?还记得“例3”里的 `lurenYi.y` 是怎么来的么? -调用构造函数咯,不过在后代构造函数里还要调用上一级构造函数,即`var funcFoo = function() {func.call(this); ...}`。 -让我们看例子吧(改编自MDN文档《[Object.prototype][]》中的一个示例)(例5): +这个该怎么设置?看例子(改编自MDN文档《[Object.prototype][]》中的一个示例)(例5): ```js var Person = function() { this.canTalk = true; }; // 这个是上级构造函数 +// JavaScript自动给 Person 加上了 prototype 属性(会在后面“原生构造函数”一节里说明) Person.prototype.greet = function() { if (this.canTalk) { console.log('Hi, I am ' + this.name); } -}; // 这是上级构造函数的prototype上的一个方法 +}; // 在上级构造函数的 prototype 属性上添加一个方法 var Employee = function(name, title) { - Person.call(this); // 后代构造函数中调用上一级构造函数 + Person.call(this); // 在后代构造函数中调用上一级构造函数 this.name = name; this.title = title; }; // 这是后代构造函数 -Employee.prototype.__proto__ = Person.prototype; // 设置后代构造函数的 prototype 的 [[Prototype]] 指向上一级的 prototype -Employee.prototype.constructor = Employee; // 这个后面的func.prototype.constructor会解释 +Employee.prototype.__proto__ = Person.prototype; // 这一行与《Object.prototype》不一样 +// 设置后代构造函数的 prototype 的 [[Prototype]] 指向上一级的 prototype,即 Employee.prototype 继承 Person.prototype -var john = new Employee('John', 'CXO'); // 新建一个实例,原型链是 john --> Employee.prototype --> Person.prototype +var john = new Employee('John', 'CXO'); // new 相当于:var john = {}; john.__proto__ = Employee.prototype; Employee.call(john); -john.canTalk === true; // true. 这是调用了上级构造函数得到的 +john.canTalk === true; // true. 这是调用了上级构造函数初始化实例得到的 +john.title === 'CXO'; // true. 这是调用了后代构造函数初始化实例得到的 john.greet(); // Hi, I am John. 这是上级构造函数prototype上的方法 ``` -## 杂项 -以上是本篇主要内容,下面提一些杂七杂八的东西: +对应前面的两点需求: +1. 如何实现原型链?设置:`Employee.prototype.__proto__ = Person.prototype;`。 +2. 如何实现多重初始化?在 Employee 构造函数里调用:`Person.call(this);`。 -### 性能考量 -重复干货部分的内容:原型链不要太长;没必要的话不要改变一个对象的[[Prototype]]。 +这样我们就有了原型链 `john --> Employee.prototype --> Person.prototype`。 +Person.prototype 长什么样呢?见下一节。 -### 几个相关方法、运算符 -- `__proto__` 已被弃用,读取 [[Prototype]] 的时候用 `Object.getPrototypeOf(someObject)` ,设置 [[Prototype]] 的时候用 `Object.setPrototypeOf(someObject)`。 -因为在浏览器的console里,在所有的Object上还是可以看到 `__proto__`,本文暂且还是使用 `__proto__` 来读取或设置 [[Prototype]]。 -- 另外,在“例5中”,`Employee.prototype.__proto__ = Person.prototype;`,《[Object.prototype][]》中用的是`Employee.prototype = Object.create()`,这两个是等效的。 -- SomeType.isPrototypeOf(someObject) -- someObject instanceof SomeType -- someObject.constructor -## 构造函数 return 一个 object 的时候 +## 原生构造函数 与 原型链的尽头 与 func.prototype 出生时的样子 +[JavaScript的内建对象][],有很多自身就是构造函数,比如Object, Function, Array, String, Number,Boolean,RegExp等等。 +怎么知道一个内建对象是不是构造函数呢? +比如,Object,在console里敲入`Object`,看到`function Object() { [native code] }`,那么,Object 就是一个构造函数。 +比如,Math,在console里敲入`Math`,看不到`function`字样,那么,Math 就不是一个构造函数。 +那么多原生构造函数,具体都是做什么的?大家可以参看MDN的文档。这里简单提一下 Object 和 Function这两个构造函数。 -### 原生构造函数 -Object, Function, Array, String, Number,Boolean,RegExp等等。 +===== 分隔线 ===== +Object 构造函数 +下面这2行得到的结果不完全相同,但也差不多: +```js +var bar = {}; // Object 字面标记(Object literal) +var bar = new Object(); // 新建 Object 实例 +``` +就是说,运行 Object 字面标记的时候,JavaScript在幕后调用了 Object 构造函数。眼见为实(例6): +```js +var bar = {}; +bar.__proto__ === Object.prototype; // true +``` +即运行`var bar = {};`之后,即使没有手动调用 Object 构造函数,我们还是有了原型链`bar --> Object.prototype`。 -箭头function -### 原型链的尽头 +Object.prototype 又继承了谁呢?console 里敲一下:`Object.prototype.__proto__ // 得到 null`。 +即 Object.prototype 的原型是 null。完整的原型链:`bar --> Object.prototype --> null`。 -### func.prototype.constructor -这个没啥用,除非真的想用。参看《[Why is it necessary to set the prototype constructor?][]》。 -这里说明一下“例5”的`Employee.prototype.constructor = Employee;`,为什么会有这么一行呢? -如果没有这一行,Employee.prototype.constructor 就会继承 Person.prototype.constructor,这样很奇怪。 -那 `Person.prototype.constructor === Person` 是怎么来的呢?是 JavaScript 自动设置的。 -为什么?管他呢,我们现在有了 ES6 的 `class Employee extends Person {}`。 +===== 分隔线 ===== +Function 构造函数 +下面这3行得到的结果不完全相同,但也差不多: +```js +function Foo() {}; // 函数声明(function declaration) +var Foo = function() {}; // 函数表达式(function expression) +var Foo = new Function(); // 新建Function实例 +``` +即在运行函数声明和函数表达式的时候,JavaScript 都在幕后调用了 Function 构造函数。眼见为实(例7): +```js +function Foo() {}; +Foo.__proto__ === Function.prototype; // true +``` +前面提过,在生成构造函数的时候,JavaScript 会自动给它配置一个 prototype 属性。Foo.prototype长什么样呢? (例8): +```js +function Foo() {}; +Foo.prototype; // 回车 +// { +// constructor: function Foo(), +// __proto__: Object... +// } +``` +Foo.prototype 在出生的时候,有两个属性: +1. \_\_proto__:指向某个 Object,即 Foo.prototype 继承了某个 Object。 + 这个 Obejct 又是什么?想一下,Foo.prototype 是JavaScript自动设置的,会不会是通过 Object 构造函数设置的呢?验证: + `Foo.prototype.__proto__ === Object.prototype; // true`,果然是。所以,根据 Object 构造函数,我们在这里有一个原型链: + `Foo.prototype --> Object.prototype --> null`。 +2. constructor: 指向 Foo。让我们完整的说一下:构造函数的 prototype 属性的 constructor 属性 指向 构造函数本身。这有什么用? + 我们运行一下`new foo = Foo();`,如果我们想知道是哪个构造哈书创建的 foo,我们可以用`foo.constructor`,但是在 foo 上是没有 constructor 属性的,就要到 Foo.prototype 上找,找到了 Foo.prototype.constructor,指向 Foo,因为JavaScript 帮我们设置好了。 + 除此以外,prototype.constructor 没啥用,除非真的想用。参看《[Why is it necessary to set the prototype constructor?][]》。 +插播:`var Foo = () => {};`,运行这行(箭头函数)之后,Foo 不会成为一个构造函数,并且 JavaScript 不会自动配置 Foo.prototype,`Foo.prototype === undefined`。 +敲敲看:`var Foo = function() {return {}}; var foo = new Foo();`,Foo 里返回对象的时候,foo.\_\_proto__ 是什么?foo.constructor又是什么? +===== 分隔线 ===== +原型链的尽头 -## 总结 -[[Prototype]] 是“我没有找它”指针,`__proto__` 是 [[Prototype]] 的访问器,func 的实例的 [[Prototype]] 指向 func.prototype。 +我来念一段经: +- JavaScript里的“东西”都是对象,对象继承构造函数的 prototype(`foo.__proto__ === Foo.prototype;`), +- 构造函数的 prototype 继承 Object.prototype (`Foo.prototype.__proto__ === Object.prototype;` ), +- Object.prototype 继承 null (`Object.prototype.__proto__ === null;`), +- null.[[Prototype]] 不存在(`null.__proto__; // throw`)。 + +所以,原型链的尽头是 null。万物皆 null,null 即万物。善哉善哉。 + +### 几个相关方法、运算符 +(详情参考MDN文档) +- Object.getPrototypeOf(someObject):取代 \_\_proto__ 的 getter 功能(\_\_proto__ 已被弃用); +- Object.setPrototypeOf(someObject):取代 \_\_proto__ 的 setter 功能(\_\_proto__ 已被弃用); +- Object.create():`var targeObject = Object.create(sourceObject)`,这行与后面等效: `targetObject = {__proto__: sourceObject}`; +- SomeType.isPrototypeOf(someObject):`Foo.prototype.isPrototypeOf(foo); // true`; +- someObject instanceof SomeType:`foo instanceof Foo; // true`。 +## 性能考量 +引用两段话: +> The lookup time for properties that are high up on the prototype chain can have a negative impact on performance ... + +-摘自MDN之《[Inheritance and the prototype chain][]》 +> Changing the [[Prototype]] of an object is ... a very slow operation ... + +-摘自MDN之《[Object.prototype.\_\_proto__][]》 + +## 总结 +[[Prototype]] 是“我没有找它”指针;\_\_proto__ 和 [[Prototype]] 等效;func 的实例的原型是 func.prototype。 ## 参考 - [继承与原型链][] @@ -246,6 +276,7 @@ Object, Function, Array, String, Number,Boolean,RegExp等等。 - [Object.prototype.\_\_proto__][] - [Object.prototype][] - [Why is it necessary to set the prototype constructor?][] +- [JavaScript的内建对象][] [继承与原型链]: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain [Inheritance and the prototype chain]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain @@ -253,3 +284,4 @@ Object, Function, Array, String, Number,Boolean,RegExp等等。 [Object.prototype.\_\_proto__]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto [Object.prototype]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype [Why is it necessary to set the prototype constructor?]: http://stackoverflow.com/questions/8453887/why-is-it-necessary-to-set-the-prototype-constructor +[JavaScript的内建对象]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects From ec8e100c33ab3e1f420237f2d4a236aad78efe73 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Tue, 22 Nov 2016 03:04:04 -0800 Subject: [PATCH 084/177] simple-prototype-chain rc1 --- src/app/_shared/api/articles/index.ts | 10 ++ .../timliu/simple-prototype-chain/_index.md | 93 +++++++++---------- 2 files changed, 54 insertions(+), 49 deletions(-) diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 45ebe0d..12a50ca 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -316,7 +316,17 @@ const items: Article[] = [ first: true, tags: ['RxJS'], authors: ['timliu'] + }, + { + id: 'simple-prototype-chain', + title: '白话 JS 的原型链', + summary: '本文记录笔者学习 JS 原型链的过程中的一些心得。', + content: require('./timliu/simple-prototype-chain/_index.md'), + first: true, + tags: ['JavaScript', 'prototype', 'prototype chain'], + authors: ['timliu'] } + ]; @Injectable() diff --git a/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md index 1a10654..83507aa 100644 --- a/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md @@ -1,6 +1,8 @@ # 白话 JS 的原型链 -> 本文记录笔者学习 JS 原型链的过程中的一些心得。了解原型链的教授们可以跳过本文,想看干货的同学们可以从[干货区](#干货区)开始。 +初稿日期:2016-11-22 + +> 本文记录笔者学习 JS 原型链的过程中的一些心得。了解原型链的教授们可以跳过本文,想看干货的同学们可以从第3节干货区开始。 ## 写作原因/目的 @@ -23,8 +25,8 @@ 真是够底层的,还是交给 Angular 们来对付这些 proto 吧,我要去做网站了。 -就这样,初学者可能每天都在使用原型链,却不想多看它一眼,至少我是这样的。不过呢,有这样一种场景,使得你不得不去了解原型链 -- 应聘时的笔试。 -当然,这只是开玩笑。了解原型链是学习 JS 不可或缺的一环,就像学习编程必须要明白什么是“面向对象”(我先去搜索引擎上看看)。 +就这样,初学者可能每天都在使用原型链,却不想多看它一眼,至少我是这样的。不过呢,有这样一种场景,使得你不得不去了解原型链 -- 应聘时的笔试。当然,这只是开玩笑。了解原型链是学习 JS 不可或缺的一环,就像学习编程必须要明白什么是“面向对象”(我先去搜索引擎上看看)。即使我们不会自己来写library,了解原型链有助于我们理解其他library和框架的工作原理。 + 本文尝试使用白话(即尽量不使用术语)来解释原型链。 ## 读者指引 @@ -45,7 +47,7 @@ - 关于性能:原型链不要太长,没必要的情况下不要改变一个对象的 [[Prototype]]。 ## [[Prototype]] 内部属性 与 \_\_proto__ 属性 -[[Prototype]] 是一个[内部属性][](什么是内部属性?参看链接),我们不能直接读取或设置一个内部属性,需要读取或设置的时候怎么办?那就要看有没有访问器了。 +[[Prototype]] 是一个[内部属性][](详情参看链接),我们不能直接读取或设置一个内部属性,需要读取或设置内部属性的时候就要看有没有相关的访问器了。 \_\_proto__ 属性就是 [[Prototype]] 的访问器,它既是getter,又是setter,同时负责读取和设置 [[Prototype]]。如果我们能过直接访问 [[Prototype]],那么会有以下代码: ```js someObject.[[Prototype]] === someObject.__proto__ // __proto__ 在这里是getter,读取 [[Prototype]] @@ -84,61 +86,57 @@ someObject.[[Prototype]] 的作用就是:当我们在 someObject 上找不到 在“例1”里,我们看到了原型链在行动,不过,好像还缺点什么。比如,我们需要一个 lurenYi,它和 lurenJia 很像,都是以 ObjA 为原型。 但是 lurenYi 有自己的 y 属性,不同于 lurenJia。我们要怎么做呢?看例子: -第n行|例2 |例3 ------|--------------------------|-------------------------- -1 |`var ObjA = {x: 1, a: 1};`|`var ObjA = {x: 1, a: 1};` +第n行 |例2 | |例3 +-----|--------------------------|---|-------------------------- +1 |`var ObjA = {x: 1, a: 1};`||`var ObjA = {x: 1, a: 1};` |`// 略去若干行` -2 |空 |`var func = function(n) {this.y = n;}` -3 |空 |`func.prototype = ObjA;` -4 |`var lurenYi = {};` |`var lurenYi = {};` -5 |`lurenYi.__proto__ = ObjA;`|`lurenYi.__proto__ = func.prototype;` -6 |`lurenYi.y = 9;` |`func.call(lurenYi, 9);` - -“例2”表述直白,第4行先让 lurenYi 指向一个空的 object,然后设置 lurenYi 的 [[Prototype]] 指向 ObjA,然后向 lurenYi 添加属性 y。 -“例2”直白,但是如果我们需要 lurenBing、lurenDing ... ,是不是只能每次重复这3行?看后面。 -“例3”看上去有些麻烦,在第2行新建了一个构造函数(后面会说明什么是构造函数),然后(注意这里是重点),在这个构造函数上, -人为的加上了一个 prototype 属性(func.prototype 与 func.[[Prototype]] 没有任何关系),然后让 func.prototype 指向 ObjA; +2 |`// 空` ||`var func = function(n) {this.y = n;}` +3 |`// 空` ||`func.prototype = ObjA;` +4 |`var lurenYi = {};` ||`var lurenYi = {};` +5 |`lurenYi.__proto__ = ObjA;`||`lurenYi.__proto__ = func.prototype;` +6 |`lurenYi.y = 9;` ||`func.call(lurenYi, 9);` +  +“例2”表述直白,第4行先让 lurenYi 指向一个空的 object,然后设置 lurenYi 的 [[Prototype]] 指向 ObjA,然后向 lurenYi 添加属性 y。“例2”直白,但是如果我们需要 lurenBing、lurenDing ... ,是不是只能每次重复这3行?看后面。 +“例3”看上去有些麻烦,在第2行新建了一个构造函数(后面会说明什么是构造函数),然后(注意这里是重点),在这个构造函数上,人为的加上了一个 prototype 属性(func.prototype 与 func.[[Prototype]] 没有任何关系),然后让 func.prototype 指向 ObjA; 而后,设置 lurenYi.[[Prototype]] 指向 func.prototype(最终指向 ObjA);再调用 func,并以 lurenYi 为 this。 为什么要这样做?继续看例子: -第n行|例3(重复) |例4 ------|------------------------------------- |-------------------------- -1 |`var ObjA = {x: 1, a: 1};` |`var ObjA = {x: 1, a: 1};` +第n行 |例3(重复) | |例4 +-----|------------------------------------- |---|-------------------------- +1 |`var ObjA = {x: 1, a: 1};` ||`var ObjA = {x: 1, a: 1};` |`// 略去若干行` -2 |`var func = function(n) {this.y = n;}`|`var func = function(n) {this.y = n;}` -3 |`func.prototype = ObjA;` |`func.prototype = ObjA;` -4 |`var lurenYi = {};` |`var lurenYi = new func(9);` -5 |`lurenYi.__proto__ = func.prototype;` |空 -6 |`func.call(lurenYi, 9);` |空 - +2 |`var func = function(n) {this.y = n;}`||`var func = function(n) {this.y = n;}` +3 |`func.prototype = ObjA;` ||`func.prototype = ObjA;` +4 |`var lurenYi = {};` ||`var lurenYi = new func(9);` +5 |`lurenYi.__proto__ = func.prototype;` ||`// 空` +6 |`func.call(lurenYi, 9);` ||`// 空` +  “例4”的第4行,取代了“例3”的第4、第5、第6行,一个 new 运算符,搞定了下面三个步骤: 1. 新建实例,指向空object。 2. 设置实例的 [[Prototype]] 指向“构造函数”的 prototype 属性(不是指向什么别的属性)。 3. 调用构造函数,以新建的实例为 this。 new 运算符怎么这么牛?为什么new 可以设置实例的 [[Prototype]] 指向构造函数的 prototype 属性? -答:JavaScript就是这么设计的,构造函数的 prototype 属性就是为了配合 new 运算符而存在的。 -后面如果我们需要 lurenBing,可以`var lurenBing = new func(10);`,新建实例变得简单多了。 +答:JavaScript就是这么设计的,构造函数的 prototype 属性就是为了配合 new 运算符而存在的。后面如果我们需要 lurenBing,可以`var lurenBing = new func(10);`,新建实例变得简单多了。 -所以呢,func.prototype 是一个人为设定的属性,new 一个 func 的实例的时候,自动设置实例的 [[Prototype]] 指向 func.prototype。 -我们可以说,func.prototype 是它的实例的原型,反过来说就是:实例继承了func.prototype。 +所以呢,func.prototype 是一个人为设定的属性,new 一个 func 的实例的时候,自动设置实例的 [[Prototype]] 指向 func.prototype。我们可以说,func.prototype 是它的实例的原型,反过来说就是:实例继承了func.prototype。 原型链就是:`lurenYi --> func.prototype`,assertion 就是:`lurenYi.__proto__ === func.prototype`。 ===== 分隔线 ===== -前面提到了构造函数,什么是构造函数呢? -构造函数就用来构造实例的函数,它的任务包括: -1. 初始化一个实例的自有属性(比如 lurenYi.y),所以要求构造函数有一个函数体(即`var func = function(n) {this.y = n;}`)。 -2. 设置实例的 [[Prototype]] 指向构造函数的 prototype 属性,所以要求构造函数有 prototype 属性(即`func.prototype = ObjA;`)。 +前面提到了构造函数,什么是构造函数呢?构造函数就用来构造实例的函数,它的任务包括: +1. 初始化一个实例的自有属性(比如 lurenYi.y),所以要求构造函数有一个函数体,如: + `var func = function(n) {this.y = n;}`。 +2. 设置实例的 [[Prototype]] 指向构造函数的 prototype 属性,所以要求构造函数有 prototype 属性,如: + `func.prototype = ObjA;`。 另外,在生成一个构造函数的时候,JavaScript会自动给它分配一个 prototype 属性,这一点会在后面“[原生构造函数](#原生构造函数)”一节里说明。 ## 使用构造函数的情况下的原型链 在使用构造函数的情况下,原型链是什么样的呢?一个构造函数又是如何继承另一个构造函数的呢(这个问题问的不妥,后面解释)? -假设我们有一个 Employee 构造函数,我们用 new 运算符生成一个实例 john,根据上一节,他们之间的原型链应该是`john --> Employee.prototype`。 -如果还有一个构造函数 Person,我们有两点需求: -1. 当请求 john.something 属性的时候,如果在 john 上和 Employee.prototype 上都找不到,还要去 Peroson.prototype 上找, - 即原型链是`john --> Employee.prototype --> Person.prototype`; +假设我们有一个 Employee 构造函数,我们用 new 运算符生成一个实例 john,根据上一节,他们之间的原型链应该是`john --> Employee.prototype`。假设还有一个构造函数 Person,而且现在我们有两点需求: +1. 当请求 john.something 属性的时候,如果在 john 上和 Employee.prototype 上都找不到,还要去 Peroson.prototype 上找,即原型链是: + `john --> Employee.prototype --> Person.prototype`; 2. john 的初始化不仅受 Employee 影响,还受 Person 影响(暂且称这个过程为多重初始化)。 这个该怎么设置?看例子(改编自MDN文档《[Object.prototype][]》中的一个示例)(例5): @@ -179,8 +177,7 @@ john.greet(); // Hi, I am John. 这是上级构造函数prototype上的方法 Person.prototype 长什么样呢?见下一节。 ## 原生构造函数 与 原型链的尽头 与 func.prototype 出生时的样子 -[JavaScript的内建对象][],有很多自身就是构造函数,比如Object, Function, Array, String, Number,Boolean,RegExp等等。 -怎么知道一个内建对象是不是构造函数呢? +[JavaScript的内建对象][],有很多自身就是构造函数,比如Object, Function, Array, String, Number,Boolean,RegExp等等。怎么知道一个内建对象是不是构造函数呢? 比如,Object,在console里敲入`Object`,看到`function Object() { [native code] }`,那么,Object 就是一个构造函数。 比如,Math,在console里敲入`Math`,看不到`function`字样,那么,Math 就不是一个构造函数。 那么多原生构造函数,具体都是做什么的?大家可以参看MDN的文档。这里简单提一下 Object 和 Function这两个构造函数。 @@ -232,8 +229,7 @@ Foo.prototype 在出生的时候,有两个属性: `Foo.prototype.__proto__ === Object.prototype; // true`,果然是。所以,根据 Object 构造函数,我们在这里有一个原型链: `Foo.prototype --> Object.prototype --> null`。 2. constructor: 指向 Foo。让我们完整的说一下:构造函数的 prototype 属性的 constructor 属性 指向 构造函数本身。这有什么用? - 我们运行一下`new foo = Foo();`,如果我们想知道是哪个构造哈书创建的 foo,我们可以用`foo.constructor`,但是在 foo 上是没有 constructor 属性的,就要到 Foo.prototype 上找,找到了 Foo.prototype.constructor,指向 Foo,因为JavaScript 帮我们设置好了。 - 除此以外,prototype.constructor 没啥用,除非真的想用。参看《[Why is it necessary to set the prototype constructor?][]》。 + 我们运行一下`new foo = Foo();`,如果我们想知道是哪个构造哈书创建的 foo,我们可以用`foo.constructor`,但是在 foo 上是没有 constructor 属性的,就要到 Foo.prototype 上找,找到了 Foo.prototype.constructor,指向 Foo,因为JavaScript 帮我们设置好了。除此以外,prototype.constructor 没啥用,除非真的想用。 插播:`var Foo = () => {};`,运行这行(箭头函数)之后,Foo 不会成为一个构造函数,并且 JavaScript 不会自动配置 Foo.prototype,`Foo.prototype === undefined`。 敲敲看:`var Foo = function() {return {}}; var foo = new Foo();`,Foo 里返回对象的时候,foo.\_\_proto__ 是什么?foo.constructor又是什么? @@ -249,12 +245,13 @@ Foo.prototype 在出生的时候,有两个属性: 所以,原型链的尽头是 null。万物皆 null,null 即万物。善哉善哉。 -### 几个相关方法、运算符 +## 几个相关方法、运算符 (详情参考MDN文档) -- Object.getPrototypeOf(someObject):取代 \_\_proto__ 的 getter 功能(\_\_proto__ 已被弃用); -- Object.setPrototypeOf(someObject):取代 \_\_proto__ 的 setter 功能(\_\_proto__ 已被弃用); -- Object.create():`var targeObject = Object.create(sourceObject)`,这行与后面等效: `targetObject = {__proto__: sourceObject}`; -- SomeType.isPrototypeOf(someObject):`Foo.prototype.isPrototypeOf(foo); // true`; +- Object.getPrototypeOf(someObject):取代 \_\_proto__ 的 getter 功能(\_\_proto__ 已被弃用)。 +- Object.setPrototypeOf(someObject):取代 \_\_proto__ 的 setter 功能(\_\_proto__ 已被弃用)。 +- Object.create():`var targeObject = Object.create(sourceObject)`,这行相当于: `targetObject = {__proto__: sourceObject}`。 + “例5”的原型(《[Object.prototype][]》的示例)使用了 Object.create(),而且还有一行: `Employee.prototype.constructor = Employee;`。大家想想为什么要两行? +- SomeType.isPrototypeOf(someObject):`Foo.prototype.isPrototypeOf(foo); // true`。 - someObject instanceof SomeType:`foo instanceof Foo; // true`。 ## 性能考量 @@ -275,7 +272,6 @@ Foo.prototype 在出生的时候,有两个属性: - [内部属性][] - [Object.prototype.\_\_proto__][] - [Object.prototype][] -- [Why is it necessary to set the prototype constructor?][] - [JavaScript的内建对象][] [继承与原型链]: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain @@ -283,5 +279,4 @@ Foo.prototype 在出生的时候,有两个属性: [内部属性]: http://stackoverflow.com/questions/17174786/what-is-the-significance-of-the-double-brackets-for-the-prototype-property-i [Object.prototype.\_\_proto__]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto [Object.prototype]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype -[Why is it necessary to set the prototype constructor?]: http://stackoverflow.com/questions/8453887/why-is-it-necessary-to-set-the-prototype-constructor [JavaScript的内建对象]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects From 2e648a4e16ea23473656398e6b6cadae1f5b0cd8 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Tue, 22 Nov 2016 03:15:14 -0800 Subject: [PATCH 085/177] amend summary --- .../api/articles/timliu/simple-prototype-chain/_index.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md index 83507aa..2c169d4 100644 --- a/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md @@ -264,7 +264,8 @@ Foo.prototype 在出生的时候,有两个属性: -摘自MDN之《[Object.prototype.\_\_proto__][]》 ## 总结 -[[Prototype]] 是“我没有找它”指针;\_\_proto__ 和 [[Prototype]] 等效;func 的实例的原型是 func.prototype。 +- 如果 A 是 B 的原型,那么原型链是 `B --> A`,assertion 是 `B.__proto__ === A`。 +- 如果 Foo 是构造函数,foo 是它的一个实例,那么原型链是 `foo --> Foo.prototype`,assertion 是 `foo.__proto__ === Foo.prototype`。 ## 参考 - [继承与原型链][] From 617a80460d6c68206d6fba19dbf6377b64007bbf Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Tue, 22 Nov 2016 03:25:15 -0800 Subject: [PATCH 086/177] deletes inline hash anchor --- .../api/articles/timliu/simple-prototype-chain/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md index 2c169d4..da68193 100644 --- a/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md @@ -129,7 +129,7 @@ new 运算符怎么这么牛?为什么new 可以设置实例的 [[Prototype]] `var func = function(n) {this.y = n;}`。 2. 设置实例的 [[Prototype]] 指向构造函数的 prototype 属性,所以要求构造函数有 prototype 属性,如: `func.prototype = ObjA;`。 -另外,在生成一个构造函数的时候,JavaScript会自动给它分配一个 prototype 属性,这一点会在后面“[原生构造函数](#原生构造函数)”一节里说明。 +另外,在生成一个构造函数的时候,JavaScript会自动给它分配一个 prototype 属性,这一点会在后面“原生构造函数”一节里说明。 ## 使用构造函数的情况下的原型链 在使用构造函数的情况下,原型链是什么样的呢?一个构造函数又是如何继承另一个构造函数的呢(这个问题问的不妥,后面解释)? From c409e61df8a0dd15a4be944c4960c85b738aa537 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Tue, 22 Nov 2016 03:33:53 -0800 Subject: [PATCH 087/177] small fixes --- .../articles/timliu/simple-prototype-chain/_index.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md index da68193..5d2f026 100644 --- a/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md @@ -159,13 +159,13 @@ var Employee = function(name, title) { this.title = title; }; // 这是后代构造函数 -Employee.prototype.__proto__ = Person.prototype; // 这一行与《Object.prototype》不一样 +Employee.prototype.__proto__ = Person.prototype; // 这一行与《Object.prototype》原文不一样 // 设置后代构造函数的 prototype 的 [[Prototype]] 指向上一级的 prototype,即 Employee.prototype 继承 Person.prototype var john = new Employee('John', 'CXO'); // new 相当于:var john = {}; john.__proto__ = Employee.prototype; Employee.call(john); -john.canTalk === true; // true. 这是调用了上级构造函数初始化实例得到的 -john.title === 'CXO'; // true. 这是调用了后代构造函数初始化实例得到的 +john.canTalk === true; // true. 这是调用了上级构造函数得到的 +john.title === 'CXO'; // true. 这是调用了后代构造函数得到的 john.greet(); // Hi, I am John. 这是上级构造函数prototype上的方法 ``` @@ -176,7 +176,7 @@ john.greet(); // Hi, I am John. 这是上级构造函数prototype上的方法 这样我们就有了原型链 `john --> Employee.prototype --> Person.prototype`。 Person.prototype 长什么样呢?见下一节。 -## 原生构造函数 与 原型链的尽头 与 func.prototype 出生时的样子 +## 原生构造函数 与 func.prototype 出生时的样子 与 原型链的尽头 [JavaScript的内建对象][],有很多自身就是构造函数,比如Object, Function, Array, String, Number,Boolean,RegExp等等。怎么知道一个内建对象是不是构造函数呢? 比如,Object,在console里敲入`Object`,看到`function Object() { [native code] }`,那么,Object 就是一个构造函数。 比如,Math,在console里敲入`Math`,看不到`function`字样,那么,Math 就不是一个构造函数。 @@ -238,7 +238,7 @@ Foo.prototype 在出生的时候,有两个属性: 原型链的尽头 我来念一段经: -- JavaScript里的“东西”都是对象,对象继承构造函数的 prototype(`foo.__proto__ === Foo.prototype;`), +- JavaScript里的“东西”都是对象,对象 继承 构造函数的 prototype(`foo.__proto__ === Foo.prototype;`), - 构造函数的 prototype 继承 Object.prototype (`Foo.prototype.__proto__ === Object.prototype;` ), - Object.prototype 继承 null (`Object.prototype.__proto__ === null;`), - null.[[Prototype]] 不存在(`null.__proto__; // throw`)。 @@ -250,7 +250,7 @@ Foo.prototype 在出生的时候,有两个属性: - Object.getPrototypeOf(someObject):取代 \_\_proto__ 的 getter 功能(\_\_proto__ 已被弃用)。 - Object.setPrototypeOf(someObject):取代 \_\_proto__ 的 setter 功能(\_\_proto__ 已被弃用)。 - Object.create():`var targeObject = Object.create(sourceObject)`,这行相当于: `targetObject = {__proto__: sourceObject}`。 - “例5”的原型(《[Object.prototype][]》的示例)使用了 Object.create(),而且还有一行: `Employee.prototype.constructor = Employee;`。大家想想为什么要两行? + “例5”的原型(《[Object.prototype][]》的示例)使用了 Object.create(),而且还有一行: `Employee.prototype.constructor = Employee;`。大家想想为什么要后面这行? - SomeType.isPrototypeOf(someObject):`Foo.prototype.isPrototypeOf(foo); // true`。 - someObject instanceof SomeType:`foo instanceof Foo; // true`。 From cf31106b8905551d1cb97e4a7f34ee70c533aa8a Mon Sep 17 00:00:00 2001 From: timeCoiner <846432362@qq.com> Date: Tue, 22 Nov 2016 22:46:58 +0800 Subject: [PATCH 088/177] Update _index.md --- .../_index.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" index 2f0b603..341d4cd 100644 --- "a/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" +++ "b/src/app/_shared/api/articles/230.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256/_index.md" @@ -65,4 +65,4 @@ ## 下篇预告: 下篇会涉及项目目录结构管理,以及angular2在移动端开发的经验,项目打包上线的经验 -ps: 正在找工作,朋友可以加我QQ: 846432362 +ps: 正在找工作,加我QQ: 846432362 From ff74fbb0de8e279881ba0e219d8acd131b23fc02 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Tue, 22 Nov 2016 10:19:55 -0800 Subject: [PATCH 089/177] updates the article basing on articles published earlier --- .../a-simple-rxjs-test-spec/_index.md | 149 ------------------ src/app/_shared/api/articles/index.ts | 4 +- .../timliu/a-simple-rxjs-test-spec/_index.md | 138 ++++++++++++++++ 3 files changed, 140 insertions(+), 151 deletions(-) delete mode 100644 src/app/_shared/api/articles/a-simple-rxjs-test-spec/_index.md create mode 100644 src/app/_shared/api/articles/timliu/a-simple-rxjs-test-spec/_index.md diff --git a/src/app/_shared/api/articles/a-simple-rxjs-test-spec/_index.md b/src/app/_shared/api/articles/a-simple-rxjs-test-spec/_index.md deleted file mode 100644 index e5fc6fa..0000000 --- a/src/app/_shared/api/articles/a-simple-rxjs-test-spec/_index.md +++ /dev/null @@ -1,149 +0,0 @@ -# 一个简单的RxJS Test Spec - -## 写作原因: -Testing除了可以帮助我们远离bug以外,也能帮我们了解小到一段陌生的代码大到一个陌生的库是如何运转的。 -这一点同样适用于RxJS。 -那么,一个RxJS的Test Spec该怎么写?Spec写好了,该怎么运行呢? -关于这个过程官方文档中暂时没有的完整的介绍。 -而本文提到的测试环境搭建与spec编写方法,是笔者通过各种尝试摸索出来的。 -难免出错,仅供参考,并希望以此抛砖引玉。 - -## Testing就是Assertion -Testing要做的事情就是Assertion:比较**我们的代码生成的结果**与**我们期望的结果**。 -比如:`expect(我们的代码生成的结果).toBe(我们期望的结果)`。 -具体到RxJS,我们要测试的其实是Observable,比如: -`expectObservable(我们的Observable$).toBe(一个什么东西)` 。 - -[RxJS Repo的Spec目录][]里,有详尽的Unit Test Spec。 -我们来看一下[interval operator的spec][]: - - describe('Observable.interval', () => { - it('should create an observable emitting periodically', () => { - const e1 = Observable.interval(20, rxTestScheduler) - .take(6) // make it actually finite, so it can be rendered - .concat(Observable.never()); // but pretend it's infinite by not completing - const expected = '--a-b-c-d-e-f-'; - const values = {a: 0, b: 1, c: 2, d: 3, e: 4, f: 5, }; - expectObservable(e1).toBe(expected, values); - }); - // ... - }) - -即使你不知道什么是Observable,也不知道这个interval这个operator是做什么的,但通过上面的代码,你大概能猜到: -expected里面的字符会被values里面的对应的数值替换掉, -同时我们期望*e1*这个Observable与*加载了values的expected*等价。 - -接下来,我们先说相关概念,然后是简略的测试环境搭建,最后是分析上面这段代码。 - -大家也可以下先看一下官方的[Writing Marble Tests][],然后再听我唠叨。 - -## 相关概念 -以下为粗略理解,详情参见[官方文档][]。 -* Observer: - 一个Object,可以有3种callback,形如`{next: nextFn, error: errorFn: complete: completeFn}`。 - 3个callback都不是必要的,`{next: nextFn}`, `{next: undefined, error: errorFn}`甚至`{}`(空object)都是合法的Observer。 -   - -* Observable: - 定义在某个时点(可以根据时钟,也可以根据事件),通过调用observer.callback来向observer推送数据。 - 比如,在Observable启动20 ms之后,调用observer.next('Hello');或者在用户点击鼠标的时候,调用observer.next(event); - 或者在链接服务器出错时,调用observer.error('can not reach server'),等等。 - * Observable.subscribe: - Observable定义好了以后,并不会自己运转起来,而是通过`Observable.subscribe(observer)`来启动,同时指定了observer。 - 这就像是在定义好了一个function以后,function自己不会运行,而是通过`function()`来启动。 -   - -* TestScheduler: - 一个虚拟时间机器,Observable可以挂靠其上。 - 我们定义的Observable在真实环境下可能要跑上一段时间才结束。而在TestScheduler里,就是一个同步的执行。 - 比如`Observable.interval(20).take(20)`,这个observable每隔20 ms推送一个递增数字,一共推20个,需要用时400 ms。 - 通过`Observable.interval(20, testScheduler).take(20)`(testScheduler是TestScheduler的一个instance), - 来设定Observable运行在虚拟时间机器上,在测试环境下,瞬间结束。 - * assertDeepEqual: - 在Spec里面要new一个TestScheduler,此时需要要以一个assertDeepEqual函数作为参数。后面代码部分详解。 -   - -* Marble Diagram: - Observable在不同时点向外推送数据,如果用句子来表达,可以是: - “在0 ms时,推100;在20 ms时推'a';40 ms,{x: 1};60 ms,[3,5],同时complete”等等。 - 这个过程也可以用Marble Diagram画出来,比如`'a-b-c-(d|)', {a: 100, b: 'a', c: {x: 1}, d: [3, 5]}`。 - * `'a-b-c-(d|)'`,这部分我们暂且叫它数据时间轴,它显示的是数据在什么时间被推送, - 一个字符占用10 frames(相当于10 ms),比如,c这个数据是在**第40 frame**时推送的。 - * `{a: 100, b: 'a', c: {x: 1}, d: [3, 5]}`,这部分是注明每个数据具体的值。 - * 另外,`-`代表啥都没发生;`|`代表complete;`()`代表同时,以`(`所在的时刻为准。 - 比如`(d|)`,是说`d`与`complete`同时发生在`(`所对应的时点,上面的数据时间轴里,`(`对应在**第60 frame**。 - - 其他详见[Writing Marble Tests][]。 - -## 测试环境搭建 -坦白一下,我还没弄明白RxJS开发时的测试环境是怎样搭建的,大家有兴趣可以研究一下[interval operator的spec][]的import部分。 -这里要用到的测试环境就是大家在[angular2-wepback-starter][]里看到的,jasmine + karma + webpack,以及其他相关的karma plugins。 -大家可以clone [angular2-wepback-starter][],也可以用我的轻量化的[rxjs-typescript-starter][]。 - -## 代码分析 -除了测试环境不同,还有一些[interval operator的spec][]用到的helper methods我也没找到。 -在粗看了[RxJS Testing源码][]之后(细看也看不懂),知道了TestScheduler有哪些method,就能大概改一改上面的spec,在我们的测试环境里跑起来。 -改过之后的spec如下,保存在index.spec.ts文件中: - - // index.spect.ts - import { Observable, TestScheduler } from 'rxjs'; - - describe('Observable.interval', () => { - it('should create an observable emitting periodically', () => { - const testScheduler = new TestScheduler((a, b) => expect(a).toEqual(b)); // added - const e1 = Observable.interval(20, testScheduler) - .take(6) // make it actually finite, so it can be rendered - .concat(Observable.never()); // but pretend it's infinite by not completing - const expected = '--a-b-c-d-e-f-'; - const values = {a: 0, b: 1, c: 2, d: 3, e: 4, f: 5, }; - testScheduler.expectObservable(e1).toBe(expected, values); // modified - testScheduler.flush(); // added - }); - }) - -逐条分析如下: -1. import TestScheduler -2. describe -> it -> -3. new一个TestScheduler,这里需要一个assertDeepEqual函数,TestScheduler.d.ts源码里是这样的: - `constructor(assertDeepEqual: (actual: any, expected: any) => boolean | void)` - 在网上搜了一下,我们可以用jasmine的expect().toEqual(), 就是`(a, b)=> expect(a).toEqual(b)`。 -4. 定义要被测试的Observable `e1`,挂上testScheduler,挂上testScheduler,挂上testScheduler。 - 至于这个一长串的Observable是个啥,我们稍后在测试输出里就能看到。 -5. 定义期望的Marble Diagram,有两部分,数据时间轴`expected`以及每个数据对应的数值`values`。 -6. 调用expectObserable().toBe(),这个是TestScheduler的method,写出来就是: - `testScheduler.expectObservable(e1).toBe(expected, values);`toBe就够了。 - 表面上看是`e1`被转换成了一个Marble Diagram,然后与*加载了values的expected*进行比较。 - 实际上是`e1`和`expected`都被转化成一个中间状态,然后比较。 -7. `testScheduler.flush();`这一步是启动虚拟时间机器。 - [Writing Marble Tests][]里有这么一句:*The TestScheduler will automatically flush at the end of your jasmine it block.* - 真的*红外遥感,自动冲冲*吗?大家先继续本文。 - -然后我们`npm test`(后面跑的就是`karma start`),看到`Executed 1 of 1 SUCCESS`。这有啥用? -我们改一下values吧,比如`f: 6`,保存,看到Executed 1 of 1 (1 FAILED) ERROR,以及一长串Expected [...] to equal [...]。 -第一个Array(我们的e1)的最后一项: (看不清?试试[js beautifier][]) -`Object({ frame: 120, notification: Notification({ kind: 'N', value: 5, exception: undefined, hasValue: true }) })` -意思就是在frame 120的时候,推送的数据是5。这就是上面第6.点中提到的中间状态。 -第二个Array(加载了values的expected)的最后一项: -`Object({ frame: 120, notification: Notification({ kind: 'N', value: 6, exception: undefined, hasValue: true }) })` -frame 120,推送6。看到区别了吧。 -这样,我们就大概知道了那个一长串的Observable是个啥了。 -然后我们把`testScheduler.flush();`删掉,保存,看到`Executed 1 of 1 SUCCESS`,此时f对应的还是6呢,怎么就SUCCESS了? -看来还是要*手动冲一下*。 - -## 结尾 - -现在,我们可以编写并运行RxJS的测试了。 -本文对`Observable.interval`的测试,可以说是RxJS中最简单的测试了。 -而在实际应用中,我们构建出来的Observable会变得很复杂,对其测试也会更复杂。 -大家可以通过研究TestScheduler的构造,并借助[RxJS Repo的Spec目录][]里spec,来进一步了解RxJS。 - - - -[Writing Marble Tests]: https://github.com/ReactiveX/rxjs/blob/master/doc/writing-marble-tests.md -[官方文档]: http://reactivex.io/rxjs/manual/overview.html -[interval operator的spec]: https://github.com/ReactiveX/rxjs/blob/master/spec/observables/interval-spec.ts -[angular2-wepback-starter]: https://github.com/AngularClass/angular2-webpack-starter -[rxjs-typescript-starter]: https://github.com/rxjs-space/rxjs-typescript-starter -[RxJS Testing源码]: https://github.com/ReactiveX/rxjs/tree/master/src/testing -[js beautifier]: http://jsbeautifier.org -[RxJS Repo的Spec目录]: https://github.com/ReactiveX/rxjs/tree/master/spec diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 3ce6882..951cba2 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -321,10 +321,10 @@ const items: Article[] = [ id: '一个简单的RxJS Test Spec', title: '一个简单的RxJS Test Spec', summary: '简要介绍如何编写并运行RxJS Unit Test Spec', - content: require('./a-simple-rxjs-test-spec/_index.md'), + content: require('./timliu/a-simple-rxjs-test-spec/_index.md'), first: true, tags: ['RxJS'], - authors: [], + authors: ['timliu'], }, ]; diff --git a/src/app/_shared/api/articles/timliu/a-simple-rxjs-test-spec/_index.md b/src/app/_shared/api/articles/timliu/a-simple-rxjs-test-spec/_index.md new file mode 100644 index 0000000..3a3c42e --- /dev/null +++ b/src/app/_shared/api/articles/timliu/a-simple-rxjs-test-spec/_index.md @@ -0,0 +1,138 @@ +# 一个简单的RxJS Test Spec + +## 写作原因: +Testing 可以帮助我们远离bug,除此以外,还能帮我们了解小到一段陌生的代码大到一个陌生的库是如何运转的。这一点同样适用于 RxJS。 +那么,一个 RxJS 的 Test Spec 该怎么写?Spec 写好了,该怎么运行呢?关于测试使用了 RxJS 的代码的过程,官方文档中暂时没有的完整的介绍。 +笔者通过各种尝试,摸索出来一套编写测试 spec 和建立测试环境的方法,在这里记录一二。难免错漏,仅供参考,并希望以此抛砖引玉。 + +## 读者指引 +本文使用 jasmine 测试框架,需要读者对 jasmine 的 spec 编写有一定了解。 + +## Testing 就是 Assertion +Testing 要做的事情就是 assertion,即比较**我们的代码生成的结果**与**我们期望的结果**。比如: +`expect(我们的代码生成的结果).toBe(我们期望的结果)`。 +具体到 RxJS,我们要测试的是 Observable,assertion 就是: +`expectObservable(我们的 observable).toBe(一个什么东西)` 。 + +下面以RxJS Repo 里的[interval operator的spec][]作为示例: + +```js +describe('Observable.interval', () => { + it('should create an observable emitting periodically', () => { + const e1 = Observable.interval(20, rxTestScheduler) + .take(6) // make it actually finite, so it can be rendered + .concat(Observable.never()); // but pretend it's infinite by not completing + const expected = '--a-b-c-d-e-f-'; + const values = {a: 0, b: 1, c: 2, d: 3, e: 4, f: 5, }; + expectObservable(e1).toBe(expected, values); + }); + // ... +}) +``` + +即使你不知道什么是 Observable,也不知道这个 Observable.interval 是做什么的,但通过上面的代码最后的 assertion,你大概能猜到: +expected 里面的字符会被 values 里面的对应的数值替换掉,同时我们期望 *e1* 与 *加载了values的expected* 等价。 + +接下来,我们先说相关概念,然后是简略的测试环境搭建,最后是分析上面这段代码。 + +大家也可以下先看一下官方的 [Writing Marble Tests][],然后再听我唠叨。 + +## 相关概念 +以下为粗略理解,大家也可以参考之前的文章《[白话 RxJS][]》,详情参见[官方文档][]。 +- Observer:一个Object,可以有3种callback,形如 `{next: nextFn, error: errorFn: complete: completeFn}`。 +- Observable:定义在某个时点(可以根据时钟,也可以根据事件),通过调用 observer.callback 来向 observer 推送数据,可以推送任意多次。 + 比如,在Observable启动20 ms之后,调用observer.next('Hello');或者在用户点击鼠标的时候,调用 observer.next(event);或者在链接服务器出错时,调用 observer.error('can not reach server'),等等。 +- Observable.prototype.subscribe :Observable 在定义好了以后,并不会自己运转起来,而是通过 Observable.prototype.subscribe 来启动。 + 比如,我们有一个 sampleObservable 以及一个 sampleObserver,要启动 sampleObservable,我们需要用 `sampleObservable.subscribe(sampleObserver)`。如此,sampleObservable 就开始运行了,即在定义好的时点,通过 sampleObserver.callback 推送数据。 +- TestScheduler:一个虚拟时间机器,Observable可以挂靠其上。我们定义的 Observable 在真实环境下,可能要跑上一段时间才结束。而在 TestScheduler 这个虚拟时间机器里,Observable 的运行仅仅是一个同步的执行。 + 比如 `Observable.interval(20).take(20)`,这个 observable 每隔20 ms推送一个递增数字,一共推20个,需要用时400 ms。通过 `Observable.interval(20, testScheduler).take(20)`(testScheduler是TestScheduler的一个实例), 来设定这个 observable 运行在虚拟时间机器上,在测试环境下,瞬间结束。 +- assertDeepEqual:在新建一个 TestScheduler 的实例的时候,需要传入一个 assertDeepEqual 函数,即 `const testScheduler = new TestScheduler(assertDeepEqual);`。根据 TestScheduler.d.ts 源码:assertDeepEqual 是这样一个函数: + `assertDeepEqual: (actual: any, expected: any) => boolean | void`。字面上看,这个函数会比较两个值,看是否相等,而且是 deeply equal,即如果对比的是Object,则需要迭代的对比 Object 上的每一个属性。在网上搜了一下,我们可以用 jasmine 的 expect().toEqual(), 就是 `(a, b) => expect(a).toEqual(b)`。 +- Marble Diagram:Observable 在不同时点向外推送数据,这个过程可以用文字表述,也可以用 Marble Diagram,对比着看就是这样: + - 文字表述:“在0 ms时,推送100;在20 ms时,推送 'a';40 ms时,推送 '{x: 1}';60 ms时,推送 '[3,5]',同时 调用 observer.complete()”等等。 + - Marble Diagram 表述:`'a-b-c-(d|)', {a: 100, b: 'a', c: {x: 1}, d: [3, 5]}`。 + + 对上述 Marble Diagram 具体说明如下: + 1. 'a-b-c-(d|)':这部分我们暂且叫它数据时间轴,它显示的是数据在什么时间被推送,一个字符占用 10 frames(相当于 10 ms),比如,c 这个数据是在*第40 frame*时推送的。 + 2. {a: 100, b: 'a', c: {x: 1}, d: [3, 5]}:这部分是注明每个数据具体的值。 + 3. 另外,'-' 代表啥都没发生;'|' 代表 complete;'()' 代表同时,以 '(' 所在的时刻为准。比如 '(d|)',是说 d 与 complete 同时发生在 '(' 所对应的时点,上面的数据时间轴里,'(' 对应在*第60 frame*。 + 4. 其他详见 [Writing Marble Tests][]。 + +## 测试环境搭建 +坦白一下,我还没弄明白 RxJS 源码 repo 的测试环境是怎样搭建的,大家有兴趣可以研究一下[源码 repo 上的的 package.json][]。 +(我们这里是 Angular 中文社区,所以)本文的测试环境就是 [angular2-wepback-starter][] 所使用的:jasmine + karma + webpack,以及其他相关的 karma plugins。 +大家可以 git clone angular2-wepback-starter,或者用我的轻量化的 [rxjs-typescript-starter][]。 + +## 代码分析 +在建立了测试环境以后,我们在 src 目录下新建一个 index.spec.ts 文件,并将开篇的 spec 拷入其中。可能是因为测试环境不同,这个 spec 没能在我们的环境下运行,所以还要对 spec 做一些修改。 +改过之后的spec如下: + +```js +// index.spect.ts +import { Observable, TestScheduler } from 'rxjs'; + +describe('Observable.interval', () => { + it('should create an observable emitting periodically', () => { + const testScheduler = new TestScheduler((a, b) => expect(a).toEqual(b)); // 增加这一行,新建一个 testScheduler + const e1 = Observable.interval(20, testScheduler) // 这里用我们的 testScheduler + .take(6) // make it actually finite, so it can be rendered + .concat(Observable.never()); // but pretend it's infinite by not completing + const expected = '--a-b-c-d-e-f-'; + const values = {a: 0, b: 1, c: 2, d: 3, e: 4, f: 5, }; + testScheduler.expectObservable(e1).toBe(expected, values); // 这里也是用我们的 testScheduler + testScheduler.flush(); // 增加这一行,用来启动 testScheduler 这个虚拟时间机器 + }); +}) +``` + +逐条分析如下: +1. import TestScheduler +2. describe -> it -> +3. 创建 TestScheduler 实例,命名这个实例为 testScheduler,这个过程在上面的“相关概念 / assertDeepEqual”一节有提到。 +4. 定义要被测试的 Observable 'e1`,挂上 testScheduler,挂上 testScheduler,挂上 testScheduler。 e1 构建使用了 interval、take、concat、never 等运算符,先不必清楚这个 e1 具体长什么样,稍后会在测试输出里看到。 +5. 定义期望的 Marble Diagram,有两部分,数据时间轴 'expected' 以及每个数据对应的数值 'values'。 +6. 调用 expectObserable().toBe(),这个是 TestScheduler的 method,写出来就是: + `testScheduler.expectObservable(e1).toBe(expected, values);`。 + 表面上看是 'e1' 被转换成了一个 Marble Diagram,然后与 *加载了 values 的 expected* 进行比较。实际上是 'e1' 和 'expected' 都被转化成一个中间状态,然后再进行比较。 +7. `testScheduler.flush();`这一步是启动虚拟时间机器。[Writing Marble Tests][]里有这么一句: + > The TestScheduler will automatically flush at the end of your jasmine 'it' block. + + 真的是*红外遥感,自动冲冲*吗?大家先继续本文。 + +然后我们 'npm test'(后面跑的就是 'karma start'),看到 'Executed 1 of 1 SUCCESS'。这有啥用?我们来让这个 spec fail掉,看看会有什么发现。 +改一下 values,比如 'f: 6',保存,看到 'Executed 1 of 1 (1 FAILED) ERROR',以及一长串 'Expected [...] to equal [...]'。 +第一个Array(我们的 'e1')的最后一项: (Array太长了看不清?试试[js beautifier][]) +`Object({ frame: 120, notification: Notification({ kind: 'N', value: 5, exception: undefined, hasValue: true }) })` +意思就是在frame 120的时候,推送的数据是5。这个 Object 就是上面第6点中提到的中间状态。 +第二个Array(加载了 'values' 的 'expected')的最后一项: +`Object({ frame: 120, notification: Notification({ kind: 'N', value: 6, exception: undefined, hasValue: true }) })` +frame 120,推送6。看到区别了吧。 +这样,根据第一个 Array,我们就知道了 e1 是一个什么样的 observable 了,而且可以通过更改 spec 去了解构建 e1 时候用到的运算符大概有什么功能了。 + +然后我们把 'testScheduler.flush();' 删掉,保存,看到 'Executed 1 of 1 SUCCESS',此时f对应的还是6呢,怎么会 SUCCESS 呢?看来还是要*手动冲一下*。 + +## 总结 +如果要测试应用了 RxJS 的代码,我们需要: +- 测试环境:jasmine + karma + webpack。 +- spec 编写: 新建 TestScheduler 实例,将被测试的 Observable 挂上 testScheduler,描述期望的 Marble Diagram,调用 expectObservable().toBe(),flush 一下。 + +本文只涉及了 RxJS 测试的皮毛。[RxJS Repo的Spec目录][]里,有详尽的 Unit Test Spec。要不要去 fail 几个? + +## 参考 +- [interval operator的spec][] +- [RxJS Testing源码][] +- [RxJS Repo的Spec目录][] +- [Writing Marble Tests][] +- [官方文档][] +- [白话 RxJS][] + +[Writing Marble Tests]: https://github.com/ReactiveX/rxjs/blob/master/doc/writing-marble-tests.md +[白话 RxJS]: https://wx.angular.cn/library/article/simple-rxjs +[源码 repo 上的的 package.json]: https://github.com/ReactiveX/rxjs/blob/master/package.json +[官方文档]: http://reactivex.io/rxjs/manual/overview.html +[interval operator的spec]: https://github.com/ReactiveX/rxjs/blob/master/spec/observables/interval-spec.ts +[angular2-wepback-starter]: https://github.com/AngularClass/angular2-webpack-starter +[rxjs-typescript-starter]: https://github.com/rxjs-space/rxjs-typescript-starter +[RxJS Testing源码]: https://github.com/ReactiveX/rxjs/tree/master/src/testing +[js beautifier]: http://jsbeautifier.org +[RxJS Repo的Spec目录]: https://github.com/ReactiveX/rxjs/tree/master/spec From f30223cbb245a500c90c027a0313aed6c69c5667 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Tue, 22 Nov 2016 20:33:11 -0800 Subject: [PATCH 090/177] more fixes --- .../timliu/simple-prototype-chain/_index.md | 144 +++++++++++------- 1 file changed, 89 insertions(+), 55 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md index 5d2f026..a1c5f42 100644 --- a/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md @@ -2,7 +2,7 @@ 初稿日期:2016-11-22 -> 本文记录笔者学习 JS 原型链的过程中的一些心得。了解原型链的教授们可以跳过本文,想看干货的同学们可以从第3节干货区开始。 +> 了解原型链的教授们或者使用 ES6 的朋友们可以跳过本文,想看干货的同学们可以从第3节干货区开始。 ## 写作原因/目的 @@ -12,46 +12,49 @@ 1. 技术进步了,我们在不了解 JS 底层(比如原型链,我的底线比较高)的情况下,就可以做出产品,不用自己造轮子。而技术进步至少体现在: - 现在有 ES6,应用 extends 关键字扩展一个 class,实际上就是在应用原型链,即使我们不知道什么是原型链; - 现在有强大的框架,比如在 Angular 里,我们有现成的 Directive、Component 等等,不需要知道 Component 是怎样继承了 Directive。 + 2. 这个原型链的技术文档真的是太...太...底层了,大家来体会一下: - > 根据 ECMAScript 标准,someObject.[[Prototype]] 符号是用于指派 someObject 的原型。这个等同于 JavaScript 的 \_\_proto__ 属性(现已弃用)。 + > 根据 ECMAScript 标准,someObject.[[Prototype]] 符号是用于指派 someObject 的原型。这个等同于 JS 的 \_\_proto__ 属性(现已弃用)。 It should not be confused with the func.prototype property of functions, which instead specifies the [[Prototype]] of all instances of the given function. 从 ECMAScript 6 开始, [[Prototype]] 可以用Object.getPrototypeOf()和Object.setPrototypeOf()访问器来访问。 - 上面这段摘自MDN的文档《[继承与原型链][]》,英文版文档比中文的多了一句,插播在这里,没有翻译。 - 这段里,形似 proto 的东西有三个: + 上面这段摘自MDN的文档《[继承与原型链][]》(英文版文档比中文的多了一句,插播在这里,没有翻译)。这段里,形似 proto 的东西有三个(我统称它们为“proto 什么的”): - someObject.[[Prototype]] 内部属性:大写的 Prototype 被“双重方括号”括起来,我在console里敲一个,SyntaxError?! - someObject.\_\_proto__ 属性:proto 的左右两边各有两个下划线(跟markdown没关系),“现已弃用”?那学它干啥?! - func.prototype 属性:func是啥?func.prototype又是啥?“not to be confused with ...”?我很 confuse ,好吗!?! - 真是够底层的,还是交给 Angular 们来对付这些 proto 吧,我要去做网站了。 + 真是够底层的,还是交给 Angular 们来对付这些“proto 什么的”吧,我要去做网站了。 -就这样,初学者可能每天都在使用原型链,却不想多看它一眼,至少我是这样的。不过呢,有这样一种场景,使得你不得不去了解原型链 -- 应聘时的笔试。当然,这只是开玩笑。了解原型链是学习 JS 不可或缺的一环,就像学习编程必须要明白什么是“面向对象”(我先去搜索引擎上看看)。即使我们不会自己来写library,了解原型链有助于我们理解其他library和框架的工作原理。 +就这样,初学者可能每天都在使用原型链,却不想多看它一眼,至少我是这样的。不过呢,有这样一种场景,使得你不得不去了解原型链 -- 应聘时的笔试。当然,这只是开玩笑。了解原型链是学习 JS 不可或缺的一环,有助于我们理解 JS 的工作原理。 本文尝试使用白话(即尽量不使用术语)来解释原型链。 ## 读者指引 -假设我们有 Foo 和 foo 两个对象,下面几个说法在本文中意思是一样的: -- foo 继承 Foo -- foo --> Foo -- foo 的 [[Prototype]] 指向 Foo -- foo.[[Prototype]] === Foo -- foo.\_\_proto__ === Foo -- Foo 是 foo 的原型 +- 如果您在生活中可以自由的使用 ES6 中的 class,而不需要维护什么历史遗留的“< ES6”项目,其实可以不用看本文。 +- 阅读本文需要读者了解 JS 中的赋值运算符('=')、相等运算符('\=\==')、不等运算符('!=='),以及 this 关键字等等。 +- 假设我们有 Foo 和 foo 两个对象,下面几个说法在本文中意思是一样的: + - foo 继承 Foo + - foo --> Foo + - foo 的 [[Prototype]] 指向 Foo + - foo.[[Prototype]] === Foo + - foo.\_\_proto__ === Foo + - Foo 是 foo 的原型 ## 干货区 -(看不明白没关系,后面的段落会一一解释,希望我能解释明白。) +为什么需要继承?因为省(我)事(懒)、省(我)资(很)源(懒)。比如:我们有一个 “太阳” 代码(包含构成、尺寸等等),还要设计 “北京的太阳” 代码,我们可以让 “北京的太阳” 继承 “太阳”,就是说不必重新设计 “构成、尺寸等等”,只要加上一个 “若隐若现” 就可以了。 +而 JS 是以原型链的方式实现继承的。本文主要内容如下:(看不明白没关系,后面的段落会一一解释,希望我能解释明白。) - someObject.[[Prototype]] 内部属性:我称它为“我没有找它指针”,这个指针是链式的,“我没有?找它;它也没有?找它的它...”。原型链由这个内部属性串起。 - someObject.\_\_proto__ 属性:这个是 [[Prototype]] 的访问器,可以认为 \_\_proto__ 和 [[Prototype]] 等效。 - func.prototype 属性:func是个构造函数,func的实例的 [[Prototype]] 指向这个 func.prototype,即 func.prototype 是 func 的实例的原型。 - 原型链的尽头是null。 -- 关于性能:原型链不要太长,没必要的情况下不要改变一个对象的 [[Prototype]]。 +- 关于性能:原型链不要太长;没必要的情况下不要改变一个对象的 [[Prototype]]。 -## [[Prototype]] 内部属性 与 \_\_proto__ 属性 -[[Prototype]] 是一个[内部属性][](详情参看链接),我们不能直接读取或设置一个内部属性,需要读取或设置内部属性的时候就要看有没有相关的访问器了。 -\_\_proto__ 属性就是 [[Prototype]] 的访问器,它既是getter,又是setter,同时负责读取和设置 [[Prototype]]。如果我们能过直接访问 [[Prototype]],那么会有以下代码: +## [[Prototype]] 与 \_\_proto__ +[[Prototype]] 是一个[内部属性][](详情参看链接),我们不能直接读取或设置一个内部属性,需要读取或设置内部属性的时候就要看有没有相应的访问器了。 +而 \_\_proto__ 属性正是 [[Prototype]] 的访问器,它既是getter,又是setter,同时负责读取和设置 [[Prototype]]。如果我们能过直接访问 [[Prototype]],那么会有以下代码: ```js someObject.[[Prototype]] === someObject.__proto__ // __proto__ 在这里是getter,读取 [[Prototype]] -// 下面两行等效 +// 下面两行赋值等效 someObject.[[Prototype]] = anotherObject; someObject.__proto__ = anotherObject; // __proto__ 在这里是setter,设置 [[Prototype]] ``` @@ -80,13 +83,14 @@ console.log(assertCombined); //true ``` someObject.[[Prototype]] 的作用就是:当我们在 someObject 上找不到某个属性的时候,就去其 [[Prototype]] 指向的对象上去找,如此往复。 比如,要访问 lurenJia.b,先在 lurenJia 上找,没到到,去 lurenJia.[[Prototype]] 指向的对象即 ObjA 上找,ObjA上也没有,就去 ObjA.[[Prototype]] 指向的对象(ObjB)上找,直到原型链的尽头(剧透:尽头 === null)。 -如果 lurenJia.[[Prototype]] 指向 ObjA,我们就可以说 lurenJia 继承了 ObjA,或者,ObjA 是 lurenJia 的原型。 +这时,原型链是:`lurenJia --> ObjA --> ObjB --> ...(我们还不知道的东西) --> null (剧透了的东西)`。 +另外,如果 lurenJia.[[Prototype]] 指向 ObjA,我们就可以说 lurenJia 继承了 ObjA,或者,ObjA 是 lurenJia 的原型。 -## func.prototype 属性 与 new 运算符 与 构造函数 +## func.prototype 在“例1”里,我们看到了原型链在行动,不过,好像还缺点什么。比如,我们需要一个 lurenYi,它和 lurenJia 很像,都是以 ObjA 为原型。 但是 lurenYi 有自己的 y 属性,不同于 lurenJia。我们要怎么做呢?看例子: -第n行 |例2 | |例3 +行 |例2 | |例3 -----|--------------------------|---|-------------------------- 1 |`var ObjA = {x: 1, a: 1};`||`var ObjA = {x: 1, a: 1};` |`// 略去若干行` @@ -101,7 +105,7 @@ someObject.[[Prototype]] 的作用就是:当我们在 someObject 上找不到 而后,设置 lurenYi.[[Prototype]] 指向 func.prototype(最终指向 ObjA);再调用 func,并以 lurenYi 为 this。 为什么要这样做?继续看例子: -第n行 |例3(重复) | |例4 +行 |例3(重复) | |例4 -----|------------------------------------- |---|-------------------------- 1 |`var ObjA = {x: 1, a: 1};` ||`var ObjA = {x: 1, a: 1};` |`// 略去若干行` @@ -117,9 +121,9 @@ someObject.[[Prototype]] 的作用就是:当我们在 someObject 上找不到 3. 调用构造函数,以新建的实例为 this。 new 运算符怎么这么牛?为什么new 可以设置实例的 [[Prototype]] 指向构造函数的 prototype 属性? -答:JavaScript就是这么设计的,构造函数的 prototype 属性就是为了配合 new 运算符而存在的。后面如果我们需要 lurenBing,可以`var lurenBing = new func(10);`,新建实例变得简单多了。 +答:JS就是这么设计的,人为设定构造函数的 prototype 属性就是为了配合 new 运算符而存在的。后面如果我们需要 lurenBing,可以`var lurenBing = new func(10);`,新建实例变得简单多了。 -所以呢,func.prototype 是一个人为设定的属性,new 一个 func 的实例的时候,自动设置实例的 [[Prototype]] 指向 func.prototype。我们可以说,func.prototype 是它的实例的原型,反过来说就是:实例继承了func.prototype。 +所以呢,func 是一个构造函数,func.prototype 是一个人为设定的属性,new 一个 func 的实例的时候,自动设置实例的 [[Prototype]] 指向 func.prototype。我们可以说,func.prototype 是 func 的实例的原型,反过来说就是:func 的实例继承了func.prototype。 原型链就是:`lurenYi --> func.prototype`,assertion 就是:`lurenYi.__proto__ === func.prototype`。 ===== 分隔线 ===== @@ -129,14 +133,14 @@ new 运算符怎么这么牛?为什么new 可以设置实例的 [[Prototype]] `var func = function(n) {this.y = n;}`。 2. 设置实例的 [[Prototype]] 指向构造函数的 prototype 属性,所以要求构造函数有 prototype 属性,如: `func.prototype = ObjA;`。 -另外,在生成一个构造函数的时候,JavaScript会自动给它分配一个 prototype 属性,这一点会在后面“原生构造函数”一节里说明。 -## 使用构造函数的情况下的原型链 -在使用构造函数的情况下,原型链是什么样的呢?一个构造函数又是如何继承另一个构造函数的呢(这个问题问的不妥,后面解释)? +其实,在生成一个构造函数的时候,JS会自动在其上配置 prototype 属性(当然,我们可以事后更改),这一点会在后面“原生构造函数”一节里说明。 +## 多重构造函数下的原型链 +(“多重构造函数”这个提法是笔者为开展下文而发明的,即原型链上有两个及以上构造函数的 prototype。大家往下看就知道了。) 假设我们有一个 Employee 构造函数,我们用 new 运算符生成一个实例 john,根据上一节,他们之间的原型链应该是`john --> Employee.prototype`。假设还有一个构造函数 Person,而且现在我们有两点需求: 1. 当请求 john.something 属性的时候,如果在 john 上和 Employee.prototype 上都找不到,还要去 Peroson.prototype 上找,即原型链是: - `john --> Employee.prototype --> Person.prototype`; + `john --> Employee.prototype --> Person.prototype`(我们可以说,这里用到了多重构造函数); 2. john 的初始化不仅受 Employee 影响,还受 Person 影响(暂且称这个过程为多重初始化)。 这个该怎么设置?看例子(改编自MDN文档《[Object.prototype][]》中的一个示例)(例5): @@ -145,7 +149,7 @@ new 运算符怎么这么牛?为什么new 可以设置实例的 [[Prototype]] var Person = function() { this.canTalk = true; }; // 这个是上级构造函数 -// JavaScript自动给 Person 加上了 prototype 属性(会在后面“原生构造函数”一节里说明) +// JS自动给 Person 加上了 prototype 属性(会在后面“原生构造函数”一节里说明) Person.prototype.greet = function() { if (this.canTalk) { @@ -170,14 +174,14 @@ john.greet(); // Hi, I am John. 这是上级构造函数prototype上的方法 ``` 对应前面的两点需求: -1. 如何实现原型链?设置:`Employee.prototype.__proto__ = Person.prototype;`。 +1. 如何实现多重构造函数的原型链?赋值:`Employee.prototype.__proto__ = Person.prototype;`。 2. 如何实现多重初始化?在 Employee 构造函数里调用:`Person.call(this);`。 这样我们就有了原型链 `john --> Employee.prototype --> Person.prototype`。 -Person.prototype 长什么样呢?见下一节。 +Person.prototype 由 JS 自动配置,它又是什么样的呢?我们继续。 -## 原生构造函数 与 func.prototype 出生时的样子 与 原型链的尽头 -[JavaScript的内建对象][],有很多自身就是构造函数,比如Object, Function, Array, String, Number,Boolean,RegExp等等。怎么知道一个内建对象是不是构造函数呢? +## 原生构造函数 +[JS的内建对象][],有很多自身就是构造函数,比如Object, Function, Array, String, Number,Boolean,RegExp等等。怎么知道一个内建对象是不是构造函数呢? 比如,Object,在console里敲入`Object`,看到`function Object() { [native code] }`,那么,Object 就是一个构造函数。 比如,Math,在console里敲入`Math`,看不到`function`字样,那么,Math 就不是一个构造函数。 那么多原生构造函数,具体都是做什么的?大家可以参看MDN的文档。这里简单提一下 Object 和 Function这两个构造函数。 @@ -190,7 +194,7 @@ Object 构造函数 var bar = {}; // Object 字面标记(Object literal) var bar = new Object(); // 新建 Object 实例 ``` -就是说,运行 Object 字面标记的时候,JavaScript在幕后调用了 Object 构造函数。眼见为实(例6): +就是说,运行 Object 字面标记的时候,JS在幕后调用了 Object 构造函数。眼见为实(例6): ```js var bar = {}; bar.__proto__ === Object.prototype; // true @@ -209,60 +213,90 @@ function Foo() {}; // 函数声明(function declaration) var Foo = function() {}; // 函数表达式(function expression) var Foo = new Function(); // 新建Function实例 ``` -即在运行函数声明和函数表达式的时候,JavaScript 都在幕后调用了 Function 构造函数。眼见为实(例7): +即在运行函数声明和函数表达式的时候,JS 都在幕后调用了 Function 构造函数。眼见为实(例7): ```js function Foo() {}; Foo.__proto__ === Function.prototype; // true ``` -前面提过,在生成构造函数的时候,JavaScript 会自动给它配置一个 prototype 属性。Foo.prototype长什么样呢? (例8): +前面提过,在生成构造函数的时候,JS 会自动给它配置一个 prototype 属性(Why? JS 就是这么设计的)。Foo.prototype长什么样呢? (例8): ```js function Foo() {}; -Foo.prototype; // 回车 +Foo.prototype; // 回车,然后看到返回下面的一个 Object // { // constructor: function Foo(), // __proto__: Object... // } ``` -Foo.prototype 在出生的时候,有两个属性: +回答上一节最后的问题(Person.prototype 什么样?这里是 Foo.prototype),Foo.prototype 在出生的时候,是一个 Object,有两个属性: 1. \_\_proto__:指向某个 Object,即 Foo.prototype 继承了某个 Object。 - 这个 Obejct 又是什么?想一下,Foo.prototype 是JavaScript自动设置的,会不会是通过 Object 构造函数设置的呢?验证: + 这个 Obejct 又是什么?想一下,Foo.prototype 是JS自动设置的,会不会是通过 Object 构造函数设置的呢?验证: `Foo.prototype.__proto__ === Object.prototype; // true`,果然是。所以,根据 Object 构造函数,我们在这里有一个原型链: `Foo.prototype --> Object.prototype --> null`。 2. constructor: 指向 Foo。让我们完整的说一下:构造函数的 prototype 属性的 constructor 属性 指向 构造函数本身。这有什么用? - 我们运行一下`new foo = Foo();`,如果我们想知道是哪个构造哈书创建的 foo,我们可以用`foo.constructor`,但是在 foo 上是没有 constructor 属性的,就要到 Foo.prototype 上找,找到了 Foo.prototype.constructor,指向 Foo,因为JavaScript 帮我们设置好了。除此以外,prototype.constructor 没啥用,除非真的想用。 + 我们运行一下`new foo = Foo();`,如果我们想知道是哪个构造函数创建的 foo,我们可以用`foo.constructor`,但是在 foo 上是没有 constructor 属性的,就要到 Foo.prototype 上找,找到了 Foo.prototype.constructor,并且指向 Foo本身,JS 帮我们设置好了。除此以外,prototype.constructor 没啥用,除非真的想用。大家也不用纠结于为什么“我的一个属性指向我自己”,JS 就是这么设计的。 -插播:`var Foo = () => {};`,运行这行(箭头函数)之后,Foo 不会成为一个构造函数,并且 JavaScript 不会自动配置 Foo.prototype,`Foo.prototype === undefined`。 +插播:`var Foo = () => {};`,运行这行(箭头函数)之后,Foo 不会成为一个构造函数,并且 JS 不会自动配置 Foo.prototype,`Foo.prototype === undefined`。 敲敲看:`var Foo = function() {return {}}; var foo = new Foo();`,Foo 里返回对象的时候,foo.\_\_proto__ 是什么?foo.constructor又是什么? ===== 分隔线 ===== 原型链的尽头 我来念一段经: -- JavaScript里的“东西”都是对象,对象 继承 构造函数的 prototype(`foo.__proto__ === Foo.prototype;`), -- 构造函数的 prototype 继承 Object.prototype (`Foo.prototype.__proto__ === Object.prototype;` ), -- Object.prototype 继承 null (`Object.prototype.__proto__ === null;`), -- null.[[Prototype]] 不存在(`null.__proto__; // throw`)。 +- JS里的对象都是实例,实例 继承 构造函数的 prototype,即 `foo.__proto__ === Foo.prototype;`, +- 构造函数的 prototype 继承 Object.prototype,即 `Foo.prototype.__proto__ === Object.prototype;`, +- Object.prototype 继承 null,即 `Object.prototype.__proto__ === null;`, +- null.[[Prototype]] 不存在,即 `null.__proto__; // Error`。 -所以,原型链的尽头是 null。万物皆 null,null 即万物。善哉善哉。 +所以,原型链总会是 `foo --> Foo.prototype --> Object.prototype --> null`,即原型链的的尽头是 null。万物皆 null,null 即万物。善哉善哉。 ## 几个相关方法、运算符 (详情参考MDN文档) - Object.getPrototypeOf(someObject):取代 \_\_proto__ 的 getter 功能(\_\_proto__ 已被弃用)。 - Object.setPrototypeOf(someObject):取代 \_\_proto__ 的 setter 功能(\_\_proto__ 已被弃用)。 - Object.create():`var targeObject = Object.create(sourceObject)`,这行相当于: `targetObject = {__proto__: sourceObject}`。 - “例5”的原型(《[Object.prototype][]》的示例)使用了 Object.create(),而且还有一行: `Employee.prototype.constructor = Employee;`。大家想想为什么要后面这行? + “例5”的原型(《[Object.prototype][]》的示例)使用了 Object.create(),而且还有一行: `Employee.prototype.constructor = Employee;`。大家有时间可以考略一下为什么要设置(其实是重新设置) Employee.prototype.constructor? - SomeType.isPrototypeOf(someObject):`Foo.prototype.isPrototypeOf(foo); // true`。 - someObject instanceof SomeType:`foo instanceof Foo; // true`。 ## 性能考量 -引用两段话: +原型链不要太长,因为: > The lookup time for properties that are high up on the prototype chain can have a negative impact on performance ... -摘自MDN之《[Inheritance and the prototype chain][]》 + +没必要的话,不要改变一个对象的原型,因为: > Changing the [[Prototype]] of an object is ... a very slow operation ... -摘自MDN之《[Object.prototype.\_\_proto__][]》 +## ES6 的 class +用ES6(或者TypeScript)的 class 重写“例5”,得到“例6”: + +```ts +class Person { + canTalk: boolean; + name: string; + constructor() { + this.canTalk = true; + } + greet() { + console.log('Hi, I am ' + this.name); + } +} + +class Employee extends Person { + title: string; + constructor(name, title) { + super(); + this.name = name; + this.title = title; + } +} +``` +'class'、'extends'、'super',这些其实只是语法糖(后面还是会被编译成类似“例5”的样子),但是真的很甜很好吃,“proto 什么的”还是洗洗睡吧。 +此时,您可能会有些许不满:“看了这么一大长篇,最后你告诉我‘proto 什么的’没必要?!” +这个没办法。我们赶上了这美好时代,有时候确实还是要去跟“proto 什么的”打交道。 + ## 总结 - 如果 A 是 B 的原型,那么原型链是 `B --> A`,assertion 是 `B.__proto__ === A`。 - 如果 Foo 是构造函数,foo 是它的一个实例,那么原型链是 `foo --> Foo.prototype`,assertion 是 `foo.__proto__ === Foo.prototype`。 @@ -273,11 +307,11 @@ Foo.prototype 在出生的时候,有两个属性: - [内部属性][] - [Object.prototype.\_\_proto__][] - [Object.prototype][] -- [JavaScript的内建对象][] +- [JS的内建对象][] -[继承与原型链]: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain -[Inheritance and the prototype chain]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain +[继承与原型链]: https://developer.mozilla.org/zh-CN/docs/Web/JS/Inheritance_and_the_prototype_chain +[Inheritance and the prototype chain]: https://developer.mozilla.org/en-US/docs/Web/JS/Inheritance_and_the_prototype_chain [内部属性]: http://stackoverflow.com/questions/17174786/what-is-the-significance-of-the-double-brackets-for-the-prototype-property-i -[Object.prototype.\_\_proto__]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto -[Object.prototype]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype -[JavaScript的内建对象]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects +[Object.prototype.\_\_proto__]: https://developer.mozilla.org/en-US/docs/Web/JS/Reference/Global_Objects/Object/proto +[Object.prototype]: https://developer.mozilla.org/en-US/docs/Web/JS/Reference/Global_Objects/Object/prototype +[JS的内建对象]: https://developer.mozilla.org/en-US/docs/Web/JS/Reference/Global_Objects From a6fe75d306eab43f3af482ba0b27dea7bcf9b3d5 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Tue, 22 Nov 2016 20:42:12 -0800 Subject: [PATCH 091/177] =?UTF-8?q?fixes=20=E5=8E=9F=E5=9E=8B=E9=93=BE?= =?UTF-8?q?=E7=9A=84=E5=B0=BD=E5=A4=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/articles/timliu/simple-prototype-chain/_index.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md index a1c5f42..a5ba666 100644 --- a/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md @@ -247,7 +247,8 @@ Foo.prototype; // 回车,然后看到返回下面的一个 Object - Object.prototype 继承 null,即 `Object.prototype.__proto__ === null;`, - null.[[Prototype]] 不存在,即 `null.__proto__; // Error`。 -所以,原型链总会是 `foo --> Foo.prototype --> Object.prototype --> null`,即原型链的的尽头是 null。万物皆 null,null 即万物。善哉善哉。 +所以,原型链总会是 `foo --> Foo.prototype --> Object.prototype --> null`,即原型链的的尽头是 null。(Foo.prototype 可能不是直接继承 Object.prototype,而是继承另外一个对象,而另外一个对象继承另外一个另外的对象,但最终都会找到 Object.prototype 头上。) +万物皆 null,null 即万物。善哉善哉。 ## 几个相关方法、运算符 (详情参考MDN文档) From b0c5770e4ce8fcea938496141ec002e04e367114 Mon Sep 17 00:00:00 2001 From: JohnnyTam Date: Tue, 22 Nov 2016 20:51:43 -0800 Subject: [PATCH 092/177] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20[=E5=A6=82?= =?UTF-8?q?=E4=BD=95=E4=BC=98=E9=9B=85=E5=8D=87=E7=BA=A7ng2=E5=B0=8F?= =?UTF-8?q?=E7=89=88=E6=9C=AC]=20MD=E6=A0=BC=E5=BC=8F=EF=BC=8C=E9=81=B5?= =?UTF-8?q?=E5=BE=AAGFM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git "a/src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" "b/src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" index c9bf99c..df830aa 100644 --- "a/src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" +++ "b/src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" @@ -22,7 +22,7 @@ package.json中,版本号如下: ### 符号`~` 举栗子: "@angular/core": "~2.0.1" -什么鬼: 只能安装 `2.0.1`, `2.0.2`, ... `2.0.9` 但是, **2.1.0就不可以了** +什么鬼: 只能安装 `2.0.1`, `2.0.2`, ... `2.0.xxx` 但是, **2.1.0不会安装** ### 符号 `>= <=` 更有者,可以使用如下形式: >= ... <= @@ -32,9 +32,9 @@ package.json中,版本号如下: ## 优雅升级常用npm命令 上述仅是package.json涉及内容的几小点,更多内容,参考npmjs官方文档 [Specifics of npm's package.json handling](https://docs.npmjs.com/files/package.json) 和 [The semantic versioner for npm](https://docs.npmjs.com/misc/semver) 接下来,开始我们的优雅之旅吧!以我自己的ng2入门项目[ng2-starter-webpack](https://github.com/tancolo/angular2/tree/master/ng2-starter-webpack)项目为例子说明,如何优雅升级ng2小版本。 -一句话总结升级步骤: ** 看版本,查依赖,修json,再重复。** +一句话总结升级步骤: **看版本,查依赖,修json,再重复** -**package.json 文件内容:** +**package.json 文件内容:** ``` "dependencies": { "@angular/common": "2.0.1", @@ -147,9 +147,9 @@ zone.js 0.6.25 0.6.25 0.6.26 ng2 $ npm view @angular/core@2.2.0 peerDependencies { rxjs: '5.0.0-beta.12', 'zone.js': '^0.6.21' } ``` -以查看 **@angular/core@2.2.0** 为例,它依赖 ** { rxjs: '5.0.0-beta.12', 'zone.js': '^0.6.21' } **, 也就是说升级**@angular/core** 到 ** 2.2.0 ** 没有必要升级rxjs, zone.js版本,即使他们有更新的版本。 +以查看 **@angular/core@2.2.0** 为例,它依赖 **{ rxjs: '5.0.0-beta.12', 'zone.js': '^0.6.21' }**, 也就是说升级**@angular/core** 到 **2.2.0** 没有必要升级`rxjs`, `zone.js`版本,即使他们有更新的版本。 -再看一个依赖包: ** angular-in-memory-web-api@0.1.1 ** +再看一个依赖包: **angular-in-memory-web-api@0.1.1** ``` $ npm view angular-in-memory-web-api@0.1.1 peerDependencies @@ -161,7 +161,7 @@ $ npm view angular-in-memory-web-api@0.1.1 peerDependencies 'zone.js': '^0.6.25' } ``` -以上说明,当升级ng2相关库为 2.2.0的时候,可以不用升级 ** angular-in-memory-web-api@0.1.1 ** +以上说明,当升级ng2相关库为 2.2.0的时候,可以不用升级 **angular-in-memory-web-api@0.1.1** 但是,修改完成 ng相关库为 2.2.0后,再次执行 npm install, 还是有错误 ``` @@ -197,17 +197,17 @@ npm ERR! peer dep missing: @angular/platform-browser@2.0.1, required by @angular 本次是angular/router的版本太低了,@3.0.1 要求ng相关库是2.0.1, 2.2.0无法使用,所以需要升级angular/router 为3.2.0 ### 修改,重复 -上述的** 看版本,查依赖,修json ** 可能会重复多次,完成后,测试的工作也不能少,至少主流程要走一遍,确保升级不会导致出现运行问题。 +上述的**看版本,查依赖,修json** 可能会重复多次,完成后,测试的工作也不能少,至少主流程要走一遍,确保升级不会导致问题。 ## 小结 -升级版本是个细致的活儿,需要科学的方法。否则容易出现问题,脑壳都会抓掉。再次总结下一般步骤吧! -#### step 1 看版本 +升级版本是个细致的活儿,需要科学的方法。否则容易出现问题,脑壳都会抓掉。再次总结下基本步骤吧! +### step 1 看版本 npm list --depth 0 npm outdated -#### step 2 查看依赖 +### step 2 查看依赖 npm view xxxpackage/xxx@x.x.x peerDependencies -#### step 3 修json -#### step 4 再重复 +### step 3 修json +### step 4 再重复 From 9f5e7fe6c4561f60c1cd8ac1a9e0a44ccca00c20 Mon Sep 17 00:00:00 2001 From: lhtin Date: Wed, 23 Nov 2016 13:35:01 +0800 Subject: [PATCH 093/177] =?UTF-8?q?add=20=E6=8A=95=E7=A8=BF=E6=B3=A8?= =?UTF-8?q?=E6=84=8F=E4=BA=8B=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/README.md b/README.md index b1d8a73..4ae98c0 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,38 @@ Angular中文社区热烈欢迎各位投稿。延续程序员的光荣传统, 最后,如果你想创建自己的专栏,请找到`src/app/_shared/api/columns`目录,编辑`index.ts`,添加你的专栏简介。当然,专栏是一种荣誉,专栏的文章有质量和数量的要求,如果你创建了专栏,我以后可能会追着你催稿哦,不过这都是小意思,对吧! +## 文章格式注意事项 + +为增加阅读体验,减少运营者的工作,请各位投稿时注意以下事项: + +1. 文章书写语言markdown,语法参考[这里](https://guides.github.com/features/mastering-markdown/) +2. pr之后尽量在github自己先view一下,保证格式是自己预期的 +3. markdown中`#`的使用:一个表示文章题目、两个表示一级标题、三个表示二级标题...依次类推。虽然有专门管理文章标题的元数据,建议还是在文章的文件中都添加文章题目 + + 示例: + ``` + # 文章题目 + + ## 前言 + + ## 内容 + + ### 内容1 + + ### 内容2 + + ## 总结 + ``` +4. 代码尽量添加编程语言标识,例如:` ```js `(表示代码由js写成) +5. 每段文字上下都空一行,首行不需要留空格 +6. 不要给标题添加序号 + + 示例(不好的): + ``` + ## 一、内容 + ### 1. 内容1 + ``` + ## 写文章参考方向 大方向:**只要是对用Angular 2做开发有用的,不一定局限在ng2** From d9b736a036d5de526e1d19e1d89d9a575bdfccf2 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Tue, 22 Nov 2016 22:54:10 -0800 Subject: [PATCH 094/177] fixes a quote mark typo --- .../api/articles/timliu/a-simple-rxjs-test-spec/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/_shared/api/articles/timliu/a-simple-rxjs-test-spec/_index.md b/src/app/_shared/api/articles/timliu/a-simple-rxjs-test-spec/_index.md index 3a3c42e..e6c18ab 100644 --- a/src/app/_shared/api/articles/timliu/a-simple-rxjs-test-spec/_index.md +++ b/src/app/_shared/api/articles/timliu/a-simple-rxjs-test-spec/_index.md @@ -89,7 +89,7 @@ describe('Observable.interval', () => { 1. import TestScheduler 2. describe -> it -> 3. 创建 TestScheduler 实例,命名这个实例为 testScheduler,这个过程在上面的“相关概念 / assertDeepEqual”一节有提到。 -4. 定义要被测试的 Observable 'e1`,挂上 testScheduler,挂上 testScheduler,挂上 testScheduler。 e1 构建使用了 interval、take、concat、never 等运算符,先不必清楚这个 e1 具体长什么样,稍后会在测试输出里看到。 +4. 定义要被测试的 Observable 'e1',挂上 testScheduler,挂上 testScheduler,挂上 testScheduler。 e1 构建使用了 interval、take、concat、never 等运算符,先不必清楚这个 e1 具体长什么样,稍后会在测试输出里看到。 5. 定义期望的 Marble Diagram,有两部分,数据时间轴 'expected' 以及每个数据对应的数值 'values'。 6. 调用 expectObserable().toBe(),这个是 TestScheduler的 method,写出来就是: `testScheduler.expectObservable(e1).toBe(expected, values);`。 From 5f6e20c157923cc88c1a04968282d5e318e2abd2 Mon Sep 17 00:00:00 2001 From: Zhicheng Wang Date: Wed, 23 Nov 2016 16:35:00 +0800 Subject: [PATCH 095/177] bugfix for build: replace node-uuid with uuid --- src/app/_shared/services/auth.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/_shared/services/auth.ts b/src/app/_shared/services/auth.ts index dbe3589..3049191 100644 --- a/src/app/_shared/services/auth.ts +++ b/src/app/_shared/services/auth.ts @@ -1,5 +1,5 @@ import {Injectable} from '@angular/core'; -import * as uuid from 'node-uuid'; +import * as uuid from 'uuid'; @Injectable() export class Auth { From 4f60e6c53bdc3e3940127d9fda77b62891248337 Mon Sep 17 00:00:00 2001 From: tancolo Date: Wed, 23 Nov 2016 18:17:39 -0800 Subject: [PATCH 096/177] =?UTF-8?q?=E9=81=B5=E5=BE=AAGFM=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E6=94=B9=E6=96=87=E7=AB=A0=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E7=9A=84=E9=94=99=E8=AF=AF=EF=BC=8C=E5=B7=B2=E7=BB=8F=E5=9C=A8?= =?UTF-8?q?github=E4=B8=8A=E9=A2=84=E8=A7=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git "a/src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" "b/src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" index df830aa..d4f0e6a 100644 --- "a/src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" +++ "b/src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" @@ -5,7 +5,7 @@ 这里的升级不是指ng1如何升级到ng2,仅以angular 2.0.1升级到当前2.2.0的时候需要注意的小细节。想了解 如何从ng1升级到ng2,请参考公众号之前文章[从ng1到ng2的平滑升级](./articles/260.从ng1到ng2的平滑升级[1]/_index.md) ## 目标 -1. package文件版本号前面的符号有什么鬼? +1. package.json文件中依赖包版本号前面的符号有什么鬼? 2. 如何从ng2.0.1 优雅升级到 ng2.2.0(当前最新) ## package依赖包版本号 @@ -13,21 +13,21 @@ ### 只有版本号 package.json中,版本号如下: -举栗子: "@angular/core": "2.0.1" -什么鬼: 安装指定版本 +- 举栗子: "@angular/core": "2.0.1" +- 什么鬼: 安装指定版本 ### 符号 `^` -举栗子: "@angular/core": "^2.0.1" -什么鬼: 安装该版本以及比该版本更新的版本,如: `2.0.1` , `2.0.2`, `2.1.0`, `2.7.0`, 但是,**3.x.x不会安装** +- 举栗子: "@angular/core": "^2.0.1" +- 什么鬼: 安装该版本以及比该版本更新的版本,如: `2.0.1` , `2.0.2`, `2.1.0`, `2.7.0`, 但是,**3.x.x不会安装** ### 符号`~` -举栗子: "@angular/core": "~2.0.1" -什么鬼: 只能安装 `2.0.1`, `2.0.2`, ... `2.0.xxx` 但是, **2.1.0不会安装** +- 举栗子: "@angular/core": "~2.0.1" +- 什么鬼: 只能安装 `2.0.1`, `2.0.2`, ... `2.0.xxx` 但是, **2.1.0不会安装** ### 符号 `>= <=` 更有者,可以使用如下形式: >= ... <= -"@angular/core": ">=2.0.1<=3.0.0" -什么鬼: 表示安装的版本是在 2.0.2到3.0.0之前的,上下边界也在内。 +- 举栗子: "@angular/core": ">=2.0.1<=3.0.0" +- 什么鬼: 表示安装的版本是在 2.0.2到3.0.0之前的,上下边界也在内。 ## 优雅升级常用npm命令 上述仅是package.json涉及内容的几小点,更多内容,参考npmjs官方文档 [Specifics of npm's package.json handling](https://docs.npmjs.com/files/package.json) 和 [The semantic versioner for npm](https://docs.npmjs.com/misc/semver) @@ -137,7 +137,7 @@ zone.js 0.6.25 0.6.25 0.6.26 ng2 ``` 一目了然,当前的version, 最新的version。 -不要猴急把package中的版本号都替换为最新的,要考虑依赖的问题。ng2的core依赖rxjs.js, zone.js, 把ng2升级到`2.2.0`,是否有必要把rxjs 或 zone.js升级为最新的版本呢? 也不一定。 +不要猴急把package中的版本号都替换为最新的,要考虑依赖的问题。ng2的core依赖rxjs.js, zone.js, 把ng2升级到`2.2.0`,是否有必要把`rxjs` 或 `zone.js`升级为最新的版本呢? 也不一定。 ### npm view xxxpackage/xxx@x.x.x peerDependencies @@ -202,12 +202,12 @@ npm ERR! peer dep missing: @angular/platform-browser@2.0.1, required by @angular ## 小结 升级版本是个细致的活儿,需要科学的方法。否则容易出现问题,脑壳都会抓掉。再次总结下基本步骤吧! ### step 1 看版本 -npm list --depth 0 -npm outdated +- **npm list --depth 0** +- **npm outdated** ### step 2 查看依赖 -npm view xxxpackage/xxx@x.x.x peerDependencies +- **npm view xxxpackage/xxx@x.x.x peerDependencies** -### step 3 修json -### step 4 再重复 +### step 3 修改package.json +### step 4 再重复 step 1,2,3 From 82dd924ff44cd78e4d370d0dc1d7bf975bd3f6e9 Mon Sep 17 00:00:00 2001 From: tancolo Date: Wed, 23 Nov 2016 18:19:55 -0800 Subject: [PATCH 097/177] =?UTF-8?q?=E4=BF=AE=E6=94=B9author=E4=B8=AD?= =?UTF-8?q?=E4=B8=AA=E4=BA=BA=E4=BB=8B=E7=BB=8D=E4=BB=A5=E5=8F=8A=E6=8F=8F?= =?UTF-8?q?=E8=BF=B0=E6=96=87=E4=BB=B6=E5=90=8D=E7=A7=B0=E6=9C=89=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/_shared/api/authors/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/_shared/api/authors/index.ts b/src/app/_shared/api/authors/index.ts index 42f61db..6ddb5bf 100644 --- a/src/app/_shared/api/authors/index.ts +++ b/src/app/_shared/api/authors/index.ts @@ -73,8 +73,8 @@ const items: Author[] = [ id: '木丁糖', name: '木丁糖', bio: '爱好前端开发的Android白面猿', - description: require('./木丁糖.md'), - avatar: require('./_images/270.木丁糖.jpg'), + description: require('./270.木丁糖.md'), + avatar: require('./_images/木丁糖.jpg'), columnist: false, homepage: 'http://www.jianshu.com/users/d614825bc8a1/latest_articles' }, From 1f9efbc703df6461ea7074d82f28551347674063 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Sun, 27 Nov 2016 06:35:49 -0800 Subject: [PATCH 098/177] with for loop example, which is to be deleted --- .../timliu/simple-immutable/_index.md | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 src/app/_shared/api/articles/timliu/simple-immutable/_index.md diff --git a/src/app/_shared/api/articles/timliu/simple-immutable/_index.md b/src/app/_shared/api/articles/timliu/simple-immutable/_index.md new file mode 100644 index 0000000..9aab760 --- /dev/null +++ b/src/app/_shared/api/articles/timliu/simple-immutable/_index.md @@ -0,0 +1,154 @@ +# 白话 JS 数值的可变与不可变 另 白话 Async 勘误 + +## 写作目的 +如果你是 JS 的初学者,同时你又在学习前端框架(包括 Angular),你可能会对后面这个描述感到有些不解:“以不可变数值(immutable value)作为程序状态(app state)的载体,会提升程序的性能”。什么是可变与不可变(后文以 mutability 代替 “可变与不可变”)?为什么数值的 mutability 会影响程序的性能?本文将尝试尽量不使用术语来回答这些问题。 + +## 读者指引 +需要读者接触过 Angular 的 @Input 和 ChangeDetectionStrategy。 + +## 什么是数值的可变与不可变 + +首先要明确的一点是:当提到 mutability 的时候,我们是在说数值,而不是变量。比如 `var text = 'abc';`,这里变量是 text,而 text 所对应的数值 'abc'。mutability 是针对数值 'abc' 而言的。 + +===== 分隔线 ===== + +先说什么是不可变(immutable)。 +在《JavaScript: The Definitive Guide, 4th Edition》,[关于 JS 的数据类型的章节][]有这么一句: +> ... because strings are immutable: there is no way to change the contents of a string value. + +作者此时并不是在说明 mutability,但他不经意间说出了不可变数值的特点,即:我们无法改变一个不可变数值的内容。为什么不可变?原因有两种:一,人为设定某类数值不可变;二,逻辑不通(数字 1 变成了数字 2,它还是数字 1 吗?)。 + +比如(例1): + +```js +var text = 'abc'; +text[1] = 'd'; +text[1] === 'b'; // true +``` +我们可以认为 string 数值(比如“例1”中变量 text 所对应的数值)是由单一字符构成的,但是我们不能修改 string 中的某个单一字符,因为:这是人为设定,JS 就是这么设计的。在其他的编程语言中,存在 mutable string(参见[Language-specific details][])。 +除 string 以外,JS 中的 number, boolean 等其他“原始值(primitive types)”也是不可变的,原因是逻辑不通 -- 数字 1 在变成数字 2 以后就不再是数字 1 了。 + +===== 分隔线 ===== + +对照不可变数值,可变(mutable)数值就是:其内容可以改变的数值。在 JS 里,可变数值包含 object(array、function等等是特种 object)、map、set等等。以 object 为例(例2): + +```js +var nameObj = {firstName: 'Doe', lastName: 'John'}; +nameObj.firstName = 'Foo'; +nameObj.firstName === 'Foo'; // true +``` +很明显,我们成功的修改了 nameObj 的 firstName 属性。所以说,object 是可变的。可是,这(object 是可变的)又何坑之有呢? + + +## 为什么可变数值是个坑 +“object 是可变的”,这一点并不是什么坑,坑的是“JS 中对可变数值的操作是以引用的方式(by reference)进行的”,内容变化了,引用却没变,一不留神,就变成了坑。以 object 类型数值为例(例3): + +```js +var valueObj = {a: 0}; +var valueArr = []; +for(var i = 0; i < 2; i++) { + var tempObj = valueObj; + tempObj.a++; + valueArr.push(tempObj); +} +var assert1 = valueArr[0] === valueObj; +var assert2 = valueArr[1] === valueObj; +var assert3 = valueArr[0] === valueArr[1]; +var assert4 = valueObj.a === 2; +var assert5 = valueObj !== {a: 2}; +var assertCombined = assert1 && assert2 && assert3; +console.log(assertCombined); // true +``` +我们在 `var tempObj = valueObj;` 这里拷贝了 valueObj,为什么最后“valueObj、value[0]、value[1]三者是等价的”?我们并没有直接操作 valueObj.a,为什么 `valueObj.a === 2`? + +在 JS 里,对数值的操作有两种:拷贝与对比(向函数传递参数可以被当成拷贝)。对 object 类型的数值的操作是以引用的方式进行的,即内容只有一份,拷贝和对比的对象是引用,与内容无关。我们来细看一下上面的代码: +- `var valueObj = {a: 0};`,这行有3个动作,1) 新建一个变量 valueObj,2) 新建一个 object 实例 {a: 0},3) 将“对 {a: 0} 的引用”**拷贝**到 valueObj; +- `var tempObj = valueObj;`,这行将 valueObj 上的“引用”**拷贝**到 tempObj; +- `tempObj.a++;`,这行改变了 tempObj.a 的值,此时,因为 valueObj 和 tempObj 有相同的引用,valueObj.a 也发生了变化; +- `valueArr[0] === valueObj;`,这行**对比** valueArr[0] 和 valueObj,对比的是二者的引用,他们都指向同一个 object,所以等价; +- `valueObj !== {a: 2};`,这行**对比** valueObj 与 {a: 2}(另一个 object 实例),尽管属性 a 数值相同,但两个引用不同,所以不等价。 + +知道了 object 数值的操作是以引用的方式进行,下面一个例子就不难理解了(例4): + +```js +var inputObj = {firstName: 'Doe', lastName: 'John'}; +var inputObj_beforeChange = inputObj; +inputObj.firstName = 'Foo'; +inputObj === inputObj_beforeChange; // true +``` +这段代码先将 inputObj 复制到 inputObj\_beforeChange,然后改变 inputObj,之后对比改变后的 inputObj 与 inputObj_beforeChange,结果是仍然等价。这里的坑就是:我们无法通过“拷贝初值并与对比结果”的方式来判断可变数值的内容是否发生过变化。 +你可能会问:不能判断内容是否变化又怎么样?我们来看一下 Angular 2 里的 ChangeDetectionStrategy。假设我们有下面这个 component: + +```ts +@Component({ + selector: 'item', + templateUrl: '

    {{ inputObj.firstName }}

    ', + // changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ItemComponent { + @Input() inputObj: {firstName: string, lastName: string}; + constructor() {} +} +``` +如果我们不设置 changeDetection 属性,即使用 ChangeDetectionStrategy.default,那么 Angular 会在下列情况检查 ItemComponent,以决定是否重新渲染: +- 任何 DOM 事件发生的时候; +- 任何 timer 到期的时候; +- 任何 Ajax 返回的时候; + +任何的意思是不论与这个 ItemComponent 有没有直接关系(即使是在其他 component 上发生了 dom 事件,也会来检查这个 ItemComponent)。为什么?因为任何上述事件都可能改变 inputObj 的内容。这样,因为 inputObj 的内容多数情况下不会改变,大多数对 ItemComponent 的检查是没有意义的。那么,我们试试 ChangeDetectionStrategy.onPush 吧,onPush 的意思是只有在 inputObj 发生变化的时候,才会检查 ItemComponent。我们在某个地方将 inputObj.firstName 改为 'Foo',你会发现 ItemComponent 并没有更新。因为 inputObj 包含的是对一个 object 的引用,内容变化了,引用却没变,Angular 认为 inputObj 没有变化,所以不检查,也就没有重新渲染。那该怎么办? + + +## 如何绕过“object 是可变的”这个坑 +上节介绍了“对可变数值的操作以引用方式进行”。那么,对不可变数值的操作又是怎样进行的呢?看例子(例5): +```js +var numA = 1; +var numB = numA; +numA === numB; // true +``` +number 类型的数值(以及其他不可变类型数据)的操作是以数值的方式进行的。`var numB = numA;`,这里是**拷贝** numA 的数值到 numB,即创建了一个新的数值 1,并分配给 numB;`numA === numB`,也是比较二者的数值。 + +仿照对不可变数值的操作,绕过“object 是可变的”这个坑的方法就是:在需要**拷贝** object 的时候,不是拷贝引用,而是手动创建新的 object,这样就有了一个新的引用,。例如(例6): +```js +var inputObj = {firstName: 'Doe', lastName: 'John'}; +var inputObj_beforeChange = Object.assign({}, inputObj); // 创建新的 object +inputObj.firstName = 'Foo'; +inputObj === inputObj_beforeChange; // false +``` + + + + + + + +## 参考 +- [关于 JS 的数据类型的章节][] +- [Language-specific details][] +- [By Value Versus by Reference][] + +## 《白话Javascript的Event Loop和Async》勘误 +《[白话Javascript的Event Loop和Async](https://wx.angular.cn/library/article/simple-javascript-event-loop-and-async)》里 +> 另外,Promise和Observable可以是sync也可以是async,主要看Promise.resolve和observer.next是谁触发的。 +Promise.then 是 async。 +```js +var o$ = Rx.Observable.create((observer) => {observer.next('o$ is sending out something')}); // 同步触发 observer.next +o$.subscribe(console.log); +console.log('after o$'); + +var p = new Promise((resolve, reject) => { + resolve('p is sending out something'); +}); +p.then(console.log); +console.log('after p'); +// 结果 +// 'o$ is sending out something' +// 'after o$' +// 'after p' +// 'p is sending out something' +``` + + + +[关于 JS 的数据类型的章节]: http://docstore.mik.ua/orelly/webprog/jscript/ch04_04.htm +[Language-specific details]: https://en.wikipedia.org/wiki/Immutable_object#Language-specific_details +[By Value Versus by Reference]: http://docstore.mik.ua/orelly/webprog/jscript/ch11_02.htm#jscript4-CHP-11-SECT-2 From 73e4d3aa9828903c45fa23d7fd40d58b46d3bab8 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Sun, 27 Nov 2016 17:40:42 -0800 Subject: [PATCH 099/177] [article] adds simple-mutability --- src/app/_shared/api/articles/index.ts | 9 + .../timliu/simple-immutable/_index.md | 154 --------------- .../timliu/simple-mutability/_index.md | 180 ++++++++++++++++++ 3 files changed, 189 insertions(+), 154 deletions(-) delete mode 100644 src/app/_shared/api/articles/timliu/simple-immutable/_index.md create mode 100644 src/app/_shared/api/articles/timliu/simple-mutability/_index.md diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 667f7bb..61525ba 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -335,6 +335,15 @@ const items: Article[] = [ tags: ['ng1', 'ng2', '平滑升级', 'es6', 'typescript'], authors: ['王開寧'], }, + { + id: 'simple-js-mutability', + title: '白话 JS 数值的可变与不可变', + summary: '简单介绍 JS 数值的可变与不可变的特点与影响。', + content: require('./timliu/simple-mutability/_index.md'), + first: true, + tags: ['mutability', 'immutable'], + authors: ['timliu'] + }, ]; @Injectable() diff --git a/src/app/_shared/api/articles/timliu/simple-immutable/_index.md b/src/app/_shared/api/articles/timliu/simple-immutable/_index.md deleted file mode 100644 index 9aab760..0000000 --- a/src/app/_shared/api/articles/timliu/simple-immutable/_index.md +++ /dev/null @@ -1,154 +0,0 @@ -# 白话 JS 数值的可变与不可变 另 白话 Async 勘误 - -## 写作目的 -如果你是 JS 的初学者,同时你又在学习前端框架(包括 Angular),你可能会对后面这个描述感到有些不解:“以不可变数值(immutable value)作为程序状态(app state)的载体,会提升程序的性能”。什么是可变与不可变(后文以 mutability 代替 “可变与不可变”)?为什么数值的 mutability 会影响程序的性能?本文将尝试尽量不使用术语来回答这些问题。 - -## 读者指引 -需要读者接触过 Angular 的 @Input 和 ChangeDetectionStrategy。 - -## 什么是数值的可变与不可变 - -首先要明确的一点是:当提到 mutability 的时候,我们是在说数值,而不是变量。比如 `var text = 'abc';`,这里变量是 text,而 text 所对应的数值 'abc'。mutability 是针对数值 'abc' 而言的。 - -===== 分隔线 ===== - -先说什么是不可变(immutable)。 -在《JavaScript: The Definitive Guide, 4th Edition》,[关于 JS 的数据类型的章节][]有这么一句: -> ... because strings are immutable: there is no way to change the contents of a string value. - -作者此时并不是在说明 mutability,但他不经意间说出了不可变数值的特点,即:我们无法改变一个不可变数值的内容。为什么不可变?原因有两种:一,人为设定某类数值不可变;二,逻辑不通(数字 1 变成了数字 2,它还是数字 1 吗?)。 - -比如(例1): - -```js -var text = 'abc'; -text[1] = 'd'; -text[1] === 'b'; // true -``` -我们可以认为 string 数值(比如“例1”中变量 text 所对应的数值)是由单一字符构成的,但是我们不能修改 string 中的某个单一字符,因为:这是人为设定,JS 就是这么设计的。在其他的编程语言中,存在 mutable string(参见[Language-specific details][])。 -除 string 以外,JS 中的 number, boolean 等其他“原始值(primitive types)”也是不可变的,原因是逻辑不通 -- 数字 1 在变成数字 2 以后就不再是数字 1 了。 - -===== 分隔线 ===== - -对照不可变数值,可变(mutable)数值就是:其内容可以改变的数值。在 JS 里,可变数值包含 object(array、function等等是特种 object)、map、set等等。以 object 为例(例2): - -```js -var nameObj = {firstName: 'Doe', lastName: 'John'}; -nameObj.firstName = 'Foo'; -nameObj.firstName === 'Foo'; // true -``` -很明显,我们成功的修改了 nameObj 的 firstName 属性。所以说,object 是可变的。可是,这(object 是可变的)又何坑之有呢? - - -## 为什么可变数值是个坑 -“object 是可变的”,这一点并不是什么坑,坑的是“JS 中对可变数值的操作是以引用的方式(by reference)进行的”,内容变化了,引用却没变,一不留神,就变成了坑。以 object 类型数值为例(例3): - -```js -var valueObj = {a: 0}; -var valueArr = []; -for(var i = 0; i < 2; i++) { - var tempObj = valueObj; - tempObj.a++; - valueArr.push(tempObj); -} -var assert1 = valueArr[0] === valueObj; -var assert2 = valueArr[1] === valueObj; -var assert3 = valueArr[0] === valueArr[1]; -var assert4 = valueObj.a === 2; -var assert5 = valueObj !== {a: 2}; -var assertCombined = assert1 && assert2 && assert3; -console.log(assertCombined); // true -``` -我们在 `var tempObj = valueObj;` 这里拷贝了 valueObj,为什么最后“valueObj、value[0]、value[1]三者是等价的”?我们并没有直接操作 valueObj.a,为什么 `valueObj.a === 2`? - -在 JS 里,对数值的操作有两种:拷贝与对比(向函数传递参数可以被当成拷贝)。对 object 类型的数值的操作是以引用的方式进行的,即内容只有一份,拷贝和对比的对象是引用,与内容无关。我们来细看一下上面的代码: -- `var valueObj = {a: 0};`,这行有3个动作,1) 新建一个变量 valueObj,2) 新建一个 object 实例 {a: 0},3) 将“对 {a: 0} 的引用”**拷贝**到 valueObj; -- `var tempObj = valueObj;`,这行将 valueObj 上的“引用”**拷贝**到 tempObj; -- `tempObj.a++;`,这行改变了 tempObj.a 的值,此时,因为 valueObj 和 tempObj 有相同的引用,valueObj.a 也发生了变化; -- `valueArr[0] === valueObj;`,这行**对比** valueArr[0] 和 valueObj,对比的是二者的引用,他们都指向同一个 object,所以等价; -- `valueObj !== {a: 2};`,这行**对比** valueObj 与 {a: 2}(另一个 object 实例),尽管属性 a 数值相同,但两个引用不同,所以不等价。 - -知道了 object 数值的操作是以引用的方式进行,下面一个例子就不难理解了(例4): - -```js -var inputObj = {firstName: 'Doe', lastName: 'John'}; -var inputObj_beforeChange = inputObj; -inputObj.firstName = 'Foo'; -inputObj === inputObj_beforeChange; // true -``` -这段代码先将 inputObj 复制到 inputObj\_beforeChange,然后改变 inputObj,之后对比改变后的 inputObj 与 inputObj_beforeChange,结果是仍然等价。这里的坑就是:我们无法通过“拷贝初值并与对比结果”的方式来判断可变数值的内容是否发生过变化。 -你可能会问:不能判断内容是否变化又怎么样?我们来看一下 Angular 2 里的 ChangeDetectionStrategy。假设我们有下面这个 component: - -```ts -@Component({ - selector: 'item', - templateUrl: '

    {{ inputObj.firstName }}

    ', - // changeDetection: ChangeDetectionStrategy.OnPush -}) -export class ItemComponent { - @Input() inputObj: {firstName: string, lastName: string}; - constructor() {} -} -``` -如果我们不设置 changeDetection 属性,即使用 ChangeDetectionStrategy.default,那么 Angular 会在下列情况检查 ItemComponent,以决定是否重新渲染: -- 任何 DOM 事件发生的时候; -- 任何 timer 到期的时候; -- 任何 Ajax 返回的时候; - -任何的意思是不论与这个 ItemComponent 有没有直接关系(即使是在其他 component 上发生了 dom 事件,也会来检查这个 ItemComponent)。为什么?因为任何上述事件都可能改变 inputObj 的内容。这样,因为 inputObj 的内容多数情况下不会改变,大多数对 ItemComponent 的检查是没有意义的。那么,我们试试 ChangeDetectionStrategy.onPush 吧,onPush 的意思是只有在 inputObj 发生变化的时候,才会检查 ItemComponent。我们在某个地方将 inputObj.firstName 改为 'Foo',你会发现 ItemComponent 并没有更新。因为 inputObj 包含的是对一个 object 的引用,内容变化了,引用却没变,Angular 认为 inputObj 没有变化,所以不检查,也就没有重新渲染。那该怎么办? - - -## 如何绕过“object 是可变的”这个坑 -上节介绍了“对可变数值的操作以引用方式进行”。那么,对不可变数值的操作又是怎样进行的呢?看例子(例5): -```js -var numA = 1; -var numB = numA; -numA === numB; // true -``` -number 类型的数值(以及其他不可变类型数据)的操作是以数值的方式进行的。`var numB = numA;`,这里是**拷贝** numA 的数值到 numB,即创建了一个新的数值 1,并分配给 numB;`numA === numB`,也是比较二者的数值。 - -仿照对不可变数值的操作,绕过“object 是可变的”这个坑的方法就是:在需要**拷贝** object 的时候,不是拷贝引用,而是手动创建新的 object,这样就有了一个新的引用,。例如(例6): -```js -var inputObj = {firstName: 'Doe', lastName: 'John'}; -var inputObj_beforeChange = Object.assign({}, inputObj); // 创建新的 object -inputObj.firstName = 'Foo'; -inputObj === inputObj_beforeChange; // false -``` - - - - - - - -## 参考 -- [关于 JS 的数据类型的章节][] -- [Language-specific details][] -- [By Value Versus by Reference][] - -## 《白话Javascript的Event Loop和Async》勘误 -《[白话Javascript的Event Loop和Async](https://wx.angular.cn/library/article/simple-javascript-event-loop-and-async)》里 -> 另外,Promise和Observable可以是sync也可以是async,主要看Promise.resolve和observer.next是谁触发的。 -Promise.then 是 async。 -```js -var o$ = Rx.Observable.create((observer) => {observer.next('o$ is sending out something')}); // 同步触发 observer.next -o$.subscribe(console.log); -console.log('after o$'); - -var p = new Promise((resolve, reject) => { - resolve('p is sending out something'); -}); -p.then(console.log); -console.log('after p'); -// 结果 -// 'o$ is sending out something' -// 'after o$' -// 'after p' -// 'p is sending out something' -``` - - - -[关于 JS 的数据类型的章节]: http://docstore.mik.ua/orelly/webprog/jscript/ch04_04.htm -[Language-specific details]: https://en.wikipedia.org/wiki/Immutable_object#Language-specific_details -[By Value Versus by Reference]: http://docstore.mik.ua/orelly/webprog/jscript/ch11_02.htm#jscript4-CHP-11-SECT-2 diff --git a/src/app/_shared/api/articles/timliu/simple-mutability/_index.md b/src/app/_shared/api/articles/timliu/simple-mutability/_index.md new file mode 100644 index 0000000..43705f4 --- /dev/null +++ b/src/app/_shared/api/articles/timliu/simple-mutability/_index.md @@ -0,0 +1,180 @@ +# 白话 JS 数值的可变与不可变 另 白话 Async 勘误 + +## 写作目的 +如果你是 JS 的初学者,同时你又在学习前端框架(包括 Angular),你可能会对后面这个描述感到有些不解:“以不可变数值(immutable value)作为程序状态(app state)的载体,会提升程序的性能”。什么是可变与不可变(后文以 mutability 代替 “可变与不可变”)?为什么数值的 mutability 会影响程序的性能?本文将尝试尽量不使用术语来回答这些问题。 + +## 读者指引 +需要读者大概了解下列知识点: +- Object.assign 方法。 +- Object 里的 getter 方法。 +- Angular 2 的 @Input 和 ChangeDetectionStrategy。 + +## 什么是数值的可变与不可变 + +首先要明确的一点是:当提到 mutability 的时候,我们是在说数值,而不是变量。比如 `var text = 'abc';`,这里变量是 text,而 text 所对应的数值是 'abc'。mutability 是针对数值 'abc' 而言的。 + +===== 分隔线 ===== + +先说什么是不可变(immutable)。 +在《JavaScript: The Definitive Guide, 4th Edition》,[关于 JS 的数据类型的章节][]有这么一句: +> ... because strings are immutable: there is no way to change the contents of a string value. + +作者此时并不是在说明 mutability,但他不经意间说出了不可变数值的特点,即:我们无法改变一个不可变数值的内容。为什么不可变?原因有两种:一,人为设定某类数值不可变;二,逻辑不通。 + +比如(例1): + +```js +var text = 'abc'; +text[1] = 'd'; +text[1] === 'b'; // true +``` +我们可以认为 string 数值(比如“例1”中变量 text 所对应的数值)是由单一字符构成的,但是我们不能修改 string 中的某个单一字符,因为:这是人为设定,JS 就是这么设计的。在其他的编程语言中,存在 mutable string(参见[Language-specific details][])。 +除 string 以外,JS 中的 number, boolean 等其他“原始值(primitive types)”也是不可变的,原因是逻辑不通 -- 数字 1 在变成数字 2 以后就不再是数字 1 了。 + +===== 分隔线 ===== + +对照不可变数值,可变(mutable)数值就是:其内容可以改变的数值。在 JS 里,可变数值包含 object(array、function等等是特种 object)、map、set等等。以 object 为例(例2): + +```js +var nameObj = {firstName: 'Doe', lastName: 'John'}; +nameObj.firstName = 'Foo'; +nameObj.firstName === 'Foo'; // true +``` +很明显,我们成功的修改了 nameObj 的 firstName 属性。所以说,object 是可变的。可是,这又何坑之有呢? + + +## 可变数值带来的是个什么坑 +“object 是可变的”,这一点并不是什么坑,坑的是“JS 中对可变数值的操作是以引用的方式(by reference)进行的”,内容变化了,引用却没变,一不留神,就变成了坑。以 object 类型数值为例(例3): + +```js +var inputObj = {firstName: 'Doe', lastName: 'John'}; +var inputObj_beforeChange = inputObj; +inputObj.firstName = 'Foo'; +inputObj === inputObj_beforeChange; // true +``` +- `var inputObj = {firstName: 'Doe', lastName: 'John'};`:这一行包含三个步骤,1)创建变量 inputObj,2)创建新的 object 实例,3)把“对 object 实例的引用”分配给 inputObj。 +- `var inputObj_beforeChange = inputObj;`:这里是拷贝 inputObj 所包含的引用,并分配给 inputObj_beforeChange。 +- `inputObj.firstName = 'Foo';`:改变 inputObj 引用的 object 的内容。 +- `inputObj === inputObj_beforeChange;`:对比两个引用,因为引用相同,此处为 true。 + +这里的坑就是:我们无法通过“拷贝初值并与结果对比”的方式来判断可变数值的内容是否发生过变化。 + +## 可变数值的坑的影响 +你可能会问:不能通过哇啦哇啦的方式来判断哇啦哇啦又怎么样?我们来看一下 Angular 2 里的 ChangeDetectionStrategy。假设我们在 AppComponent 下有一个这样的 ItemComponent: + +```ts +@Component({ + selector: 'item', + templateUrl: '

    {{ inputContent.firstName }}

    ', + // changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ItemComponent { + @Input() inputObj: {firstName: string, lastName: string}; + constructor() {} + get inputContent() { + console.log('detecting changes on template expression'); + return inputObj; + } +} +``` +如果我们不设置 changeDetection 属性,默认使用 ChangeDetectionStrategy.default,那么 Angular 会在下列情况对 ItemComponent 进行变更检查,以决定是否重新渲染: +- 任何注册了 listener 的 DOM 事件发生的时候; +- 任何 timer 事件发生的时候; +- 任何 Ajax 返回的时候; + +任何的意思是不论事件与 ItemComponent 有没有直接关系(即使是在其他 component 上发生了 dom 事件,也会来检查这个 ItemComponent)。为什么?因为任何上述事件都可能改变 inputObj 的内容。但是,因为 inputObj 的内容在多数情况下不会改变,大多数对 ItemComponent 的检查是没有意义的。 +落实到我们的 ItemComponent 上,每次变更检查都会调用 get inputContent,我们可以在 AppComponent 上添加一个按钮,注册一个 click listener,但不做任何事情,比如: +```html + + + +``` +```ts +// in app-component.ts +fakeObj: any = {firstName: 'John', lastName: 'Doe'}; +// in item-componet.ts +changeDetection: ChangeDetectionStrategy.default +``` +每次点按按钮,ItemComponent 上的 get inputContent 都会被调用,即使这个按钮是在 ItemComponent 之外。 +那么,我们试试 ChangeDetectionStrategy.onPush 吧,onPush 的意思是只有在 inputObj 发生变化(或者 ItemComponent 自身有事件发生)的时候,才会检查 ItemComponent。我们可以这样: +```html + + + +``` +```ts +// in item-componet.ts +changeDetection: ChangeDetectionStrategy.onPush +``` + +在点按 AppComponent 上的按钮时 inputObj.firstName 改为 'Foo',你会发现 ItemComponent 并没有更新。因为 Angular 判断一个 @Input 数值是否变化的方式就是“拷贝初值并与结果对比”,这个方式对 object 是无效的。踩到坑了,怎么办? + +## 如何绕过可变数值带来的坑 +承接上节的 Angular 例子,我们可以在需要改变一个 object 的属性的时候,创建一个新的 object: +```html + + + +``` +```ts +// in app-componet.ts +changeObj() { + this.fakeObj = Object.assign({}, this.fakeObj, {firstName: 'Foo'}) +} +``` + + +这样,就有了一个新的引用,Angular 就能通过“拷贝初值并与结果对比”来感知 inputObj 发生了变化。我们可以称这个过程为“强制不可变”,即不去改变一个可变数值,也不拷贝原来的引用,而是创建新数值,克隆原数值的内容,并在此基础上修改。但是 Object.assign 还是比较“肤浅”,如果一个 object 是多层级的,比如 {a: 1, b: {x: 2}},这里 b 包含的也是一个引用,一个 Object.assign 不能搞定,我们有几种选择: +- 在 app 中只使用包含一个层级的 object(这个不太现实)。 +- 使用循环多级克隆原数据的内容(可能会影响性能)。 +- 借助第三方库,如 ImmutableJS(又有一堆新的 api,但为了 app performance,翻滚翻滚)。 + +在 Angular 中使用“强制不可变”配合 ChangeDetectionStrategy.onPush 并不能完全杜绝无效检查,比如 inputObject 的内容没有变化,却创建了新的 inputObject,引用变了,就会检查一次。不过,这还是比 ChangeStrategy.default 强得多,可以大幅减少不必要的变更检查。所以就有了开篇提到的:“以不可变数值(immutable value)作为程序状态(app state)的载体,会提升程序的性能”。 + +题外话:使用 immutable value 并不是改善变更检查效率的唯一途径,还可以使用 observables。参见[Change Detection in Angular 2][]。 + +## 总结 +JS 中对可变数值的操作是以引用的方式进行的,内容变化了,引用却没变。“旧瓶装新酒”不一定总是我们想要的。 + +## 参考/推荐阅读 +- [关于 JS 的数据类型的章节][] +- [Language-specific details][] +- [By Value Versus by Reference][] +- [How does Angular 2 Change Detection Really Work ?][] +- [Change Detection in Angular 2][] + +## 《白话Javascript的Event Loop和Async》勘误 +《[白话Javascript的Event Loop和Async](https://wx.angular.cn/library/article/simple-javascript-event-loop-and-async)》里提到这样一句: +> Promise和Observable可以是sync也可以是async,主要看Promise.resolve和observer.next是谁触发的。 + +这里有重大错误。正确的说法应该是: +Observable 在创建的时候,不会自动运行,需要使用 subscribe 方法启动。而 Observable 的运行,可以是 sync 也可以是 async,主要看 observer.callback 是谁触发的。比如: +```js +var o$ = Rx.Observable.create((observer) => {observer.next('o$ is sending out something')}); +o$.subscribe(console.log); // subscribe 以后,同步触发 observer.next +console.log('after o$.subscribe'); +``` +在 console 里看到:先有 'o$ is sending out something',再有 'after o$.subscribe'。 + +Promise 在创建的时候,立即运行,运行的过程可以是 sync 也可以是 async,主要看 resolve 或 reject 是谁触发的。 +- (重点在这里)在Promise.prototype.then上注册的 callback 一定是被 async 执行的。比如: +```js +var p = new Promise((resolve, reject) => { + console.log('begin'); + resolve('p is sending out something'); // 这个 resolve 是 sync 的 +}); +// 在 console 上立即看到 'begin' +p.then(console.log); // 这个 console.log 会被添加到 task queue,而不是直接进入到 call stack +console.log('after p.then'); +``` +在 console 里看到:先有 'after p.then',再有 'p is sending out something'。 + +特此更正,并对读者致歉。 + +Happy coding! + +[关于 JS 的数据类型的章节]: http://docstore.mik.ua/orelly/webprog/jscript/ch04_04.htm +[Language-specific details]: https://en.wikipedia.org/wiki/Immutable_object#Language-specific_details +[By Value Versus by Reference]: http://docstore.mik.ua/orelly/webprog/jscript/ch11_02.htm#jscript4-CHP-11-SECT-2 +[How does Angular 2 Change Detection Really Work ?]: http://blog.angular-university.io/how-does-angular-2-change-detection-really-work/ +[Change Detection in Angular 2]: https://vsavkin.com/change-detection-in-angular-2-4f216b855d4c#.tdkm5385e From affc8820ec60a0667b64ecd9548bc90d1fc4df49 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Sun, 27 Nov 2016 18:02:15 -0800 Subject: [PATCH 100/177] correction: Promise.prototype.then adds callback to task queue --- .../_index.md | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-javascript-event-loop-and-async/_index.md b/src/app/_shared/api/articles/timliu/simple-javascript-event-loop-and-async/_index.md index fa5a7e3..232a86e 100644 --- a/src/app/_shared/api/articles/timliu/simple-javascript-event-loop-and-async/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-javascript-event-loop-and-async/_index.md @@ -60,13 +60,34 @@ Event loop包括`call stack + task queue + looper`(task queue和looper不是 - 而sync操作就是在call stack里逐步的运行任务。 常见的async api包括:timer(setTimeout, setInterval等等), eventListener(onreadystatechange、onclick等等)。 + +<错误> 另外,Promise和Observable可以是sync也可以是async,主要看Promise.resolve和observer.next是谁触发的。 + +<更正> +Observable 在创建的时候,不会自动运行,需要使用 subscribe 方法启动。而 Observable 的运行,可以是 sync 也可以是 async,主要看 observer.callback 是谁触发的。比如: ```js -var p1 = new Promise(function(resolve, reject){resolve(1)}); // 这个Promise是sync操作 -var o$ = Observable.create((observer) => {observer.next(1)}); -var o_ = o$.subscribe(console.log) // 这个Observable和Subscription都是sync操作 +var o$ = Rx.Observable.create((observer) => {observer.next('o$ is sending out something')}); +o$.subscribe(console.log); // subscribe 以后,同步触发 observer.next +console.log('after o$.subscribe'); ``` +在 console 里看到:先有 'o$ is sending out something',再有 'after o$.subscribe'。 + +Promise 在创建的时候,立即运行,运行的过程可以是 sync 也可以是 async,主要看 resolve 或 reject 是谁触发的。 +- (重点在这里)在Promise.prototype.then上注册的 callback 一定是被 async 执行的。比如: +```js +var p = new Promise((resolve, reject) => { + console.log('begin'); + resolve('p is sending out something'); // 这个 resolve 是 sync 的 +}); +// 在 console 上立即看到 'begin' +p.then(console.log); // 这个 console.log 会被添加到 task queue,而不是直接进入到 call stack +console.log('after p.then'); +``` +在 console 里看到:先有 'after p.then',再有 'p is sending out something'。 + + ## 总结 Async什么样?call stack里面看不到。 From 1e0919e3ced7415b252b3518d8ffd40b8866362c Mon Sep 17 00:00:00 2001 From: lhtin Date: Mon, 28 Nov 2016 13:43:51 +0800 Subject: [PATCH 101/177] merge authors/index.ts --- src/app/_shared/api/authors/index.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/app/_shared/api/authors/index.ts b/src/app/_shared/api/authors/index.ts index 0c3a915..45fe9c8 100644 --- a/src/app/_shared/api/authors/index.ts +++ b/src/app/_shared/api/authors/index.ts @@ -52,7 +52,6 @@ const items: Author[] = [ homepage: 'https://github.com/lhtin' }, { -<<<<<<< HEAD id: 'timliu', name: 'Tim刘', bio: '小白小白小白', @@ -70,8 +69,7 @@ const items: Author[] = [ columnist: false, homepage: 'https://twincle.github.io/' }, -<<<<<<< HEAD -======= + { id: 'dapao', name: '大炮', bio: '上天不要移開險峻,請賜予吾攀登之力', @@ -79,9 +77,7 @@ const items: Author[] = [ avatar: require(''), columnist: false, homepage: 'https://github.com/btcioner/About-ME' - } ->>>>>>> cf31106b8905551d1cb97e4a7f34ee70c533aa8a -======= + }, { id: '木丁糖', name: '木丁糖', @@ -91,8 +87,8 @@ const items: Author[] = [ columnist: false, homepage: 'http://www.jianshu.com/users/d614825bc8a1/latest_articles' }, ->>>>>>> 82dd924ff44cd78e4d370d0dc1d7bf975bd3f6e9 ]; + @Injectable() export class AuthorApi { // AuthorApi.query可以直接用来模拟从数据库里查找作者信息。 From 90cf0bda46c434cd22720795c75c372bf219134d Mon Sep 17 00:00:00 2001 From: JohnnyTam Date: Mon, 28 Nov 2016 15:07:35 +0800 Subject: [PATCH 102/177] =?UTF-8?q?[=E5=A6=82=E4=BD=95=E4=BC=98=E9=9B=85?= =?UTF-8?q?=E5=8D=87=E7=BA=A7ng2=E5=B0=8F=E7=89=88=E6=9C=AC]=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=20=E8=AF=AD=E4=B9=89=E5=8C=96=20=E5=8F=82=E8=80=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git "a/src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" "b/src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" index 40f87fc..96fcac7 100644 --- "a/src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" +++ "b/src/app/_shared/api/articles/280.\345\246\202\344\275\225\344\274\230\351\233\205\345\215\207\347\272\247ng2\345\260\217\347\211\210\346\234\254/_index.md" @@ -29,6 +29,18 @@ package.json中,版本号如下: - 举栗子: "@angular/core": ">=2.0.1<=3.0.0" - 什么鬼: 表示安装的版本是在 2.0.2到3.0.0之前的,上下边界也在内。 +### 符号`~`, `^`的由来 +看到上述符号`~`,`^`, 估计有小伙伴表示,这是什么鬼,npm为什么要使用这些符号。讲到这里,需要提及一个名词[语义化版本](http://semver.org/lang/zh-CN/), 简单的说就是一个规范,让大家快乐的升级。详细的需要参考npm官方的文档。 +[Specifics of npm's package.json handling](https://docs.npmjs.com/files/package.json) 和 [The semantic versioner for npm](https://docs.npmjs.com/misc/semver) +其中[tilde-ranges](https://docs.npmjs.com/misc/semver#tilde-ranges-123-12-1)以及[caret-ranges](https://docs.npmjs.com/misc/semver#caret-ranges-123-025-004)中给出了 `^`,`~`来由。 +引用如下: +> **Tilde Ranges ~1.2.3 ~1.2 ~1** + Allows patch-level changes if a minor version is specified on the comparator. Allows minor-level changes if not. + +> **Caret Ranges ^1.2.3 ^0.2.5 ^0.0.4** + Allows changes that do not modify the left-most non-zero digit in the [major, minor, patch] tuple. In other words, this allows patch and minor updates for versions 1.0.0 and above, patch updates for versions 0.X >=0.1.0, and no updates for versions 0.0.X. + + ## 优雅升级常用npm命令 上述仅是package.json涉及内容的几小点,更多内容,参考npmjs官方文档 [Specifics of npm's package.json handling](https://docs.npmjs.com/files/package.json) 和 [The semantic versioner for npm](https://docs.npmjs.com/misc/semver) 接下来,开始我们的优雅之旅吧!以我自己的ng2入门项目[ng2-starter-webpack](https://github.com/tancolo/angular2/tree/master/ng2-starter-webpack)项目为例子说明,如何优雅升级ng2小版本。 From 2b2036a98faefe4ecda8dee8f39e1133c7877fa3 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Mon, 28 Nov 2016 18:18:30 -0800 Subject: [PATCH 103/177] OnPush and Default --- .../api/articles/timliu/simple-mutability/_index.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-mutability/_index.md b/src/app/_shared/api/articles/timliu/simple-mutability/_index.md index 43705f4..a499b09 100644 --- a/src/app/_shared/api/articles/timliu/simple-mutability/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-mutability/_index.md @@ -77,7 +77,7 @@ export class ItemComponent { } } ``` -如果我们不设置 changeDetection 属性,默认使用 ChangeDetectionStrategy.default,那么 Angular 会在下列情况对 ItemComponent 进行变更检查,以决定是否重新渲染: +如果我们不设置 changeDetection 属性,默认使用 ChangeDetectionStrategy.Default,那么 Angular 会在下列情况对 ItemComponent 进行变更检查,以决定是否重新渲染: - 任何注册了 listener 的 DOM 事件发生的时候; - 任何 timer 事件发生的时候; - 任何 Ajax 返回的时候; @@ -93,10 +93,10 @@ export class ItemComponent { // in app-component.ts fakeObj: any = {firstName: 'John', lastName: 'Doe'}; // in item-componet.ts -changeDetection: ChangeDetectionStrategy.default +changeDetection: ChangeDetectionStrategy.Default ``` 每次点按按钮,ItemComponent 上的 get inputContent 都会被调用,即使这个按钮是在 ItemComponent 之外。 -那么,我们试试 ChangeDetectionStrategy.onPush 吧,onPush 的意思是只有在 inputObj 发生变化(或者 ItemComponent 自身有事件发生)的时候,才会检查 ItemComponent。我们可以这样: +那么,我们试试 ChangeDetectionStrategy.OnPush 吧,OnPush 的意思是只有在 inputObj 发生变化(或者 ItemComponent 自身有事件发生)的时候,才会检查 ItemComponent。我们可以这样: ```html @@ -104,7 +104,7 @@ changeDetection: ChangeDetectionStrategy.default ``` ```ts // in item-componet.ts -changeDetection: ChangeDetectionStrategy.onPush +changeDetection: ChangeDetectionStrategy.OnPush ``` 在点按 AppComponent 上的按钮时 inputObj.firstName 改为 'Foo',你会发现 ItemComponent 并没有更新。因为 Angular 判断一个 @Input 数值是否变化的方式就是“拷贝初值并与结果对比”,这个方式对 object 是无效的。踩到坑了,怎么办? @@ -129,7 +129,7 @@ changeObj() { - 使用循环多级克隆原数据的内容(可能会影响性能)。 - 借助第三方库,如 ImmutableJS(又有一堆新的 api,但为了 app performance,翻滚翻滚)。 -在 Angular 中使用“强制不可变”配合 ChangeDetectionStrategy.onPush 并不能完全杜绝无效检查,比如 inputObject 的内容没有变化,却创建了新的 inputObject,引用变了,就会检查一次。不过,这还是比 ChangeStrategy.default 强得多,可以大幅减少不必要的变更检查。所以就有了开篇提到的:“以不可变数值(immutable value)作为程序状态(app state)的载体,会提升程序的性能”。 +在 Angular 中使用“强制不可变”配合 ChangeDetectionStrategy.OnPush 并不能完全杜绝无效检查,比如 inputObject 的内容没有变化,却创建了新的 inputObject,引用变了,就会检查一次。不过,这还是比 ChangeStrategy.Default 强得多,可以大幅减少不必要的变更检查。所以就有了开篇提到的:“以不可变数值(immutable value)作为程序状态(app state)的载体,会提升程序的性能”。 题外话:使用 immutable value 并不是改善变更检查效率的唯一途径,还可以使用 observables。参见[Change Detection in Angular 2][]。 From a0eb416688d74aac1e160d0af255c3e135167920 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Mon, 28 Nov 2016 19:16:14 -0800 Subject: [PATCH 104/177] fixes based on trotyl's comments --- .../timliu/simple-prototype-chain/_index.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md index a5ba666..c568bd9 100644 --- a/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md @@ -44,7 +44,7 @@ 为什么需要继承?因为省(我)事(懒)、省(我)资(很)源(懒)。比如:我们有一个 “太阳” 代码(包含构成、尺寸等等),还要设计 “北京的太阳” 代码,我们可以让 “北京的太阳” 继承 “太阳”,就是说不必重新设计 “构成、尺寸等等”,只要加上一个 “若隐若现” 就可以了。 而 JS 是以原型链的方式实现继承的。本文主要内容如下:(看不明白没关系,后面的段落会一一解释,希望我能解释明白。) - someObject.[[Prototype]] 内部属性:我称它为“我没有找它指针”,这个指针是链式的,“我没有?找它;它也没有?找它的它...”。原型链由这个内部属性串起。 -- someObject.\_\_proto__ 属性:这个是 [[Prototype]] 的访问器,可以认为 \_\_proto__ 和 [[Prototype]] 等效。 +- someObject.\_\_proto__ 属性:这个是 [[Prototype]] 的访问器,可以认为 \_\_proto__ 和 [[Prototype]] 等效。(插播:MDN的中文文档《[继承与原型链][]》将“depreated”翻译成“已弃用”,这个说法有误导之嫌。\_\_proto__ 并非马上就不能用了,而是推荐大家使用 Object.getPrototypeOf 和 Object.setPrototypeOf。关于这两个方法,后面会简单介绍。) - func.prototype 属性:func是个构造函数,func的实例的 [[Prototype]] 指向这个 func.prototype,即 func.prototype 是 func 的实例的原型。 - 原型链的尽头是null。 - 关于性能:原型链不要太长;没必要的情况下不要改变一个对象的 [[Prototype]]。 @@ -182,8 +182,8 @@ Person.prototype 由 JS 自动配置,它又是什么样的呢?我们继续 ## 原生构造函数 [JS的内建对象][],有很多自身就是构造函数,比如Object, Function, Array, String, Number,Boolean,RegExp等等。怎么知道一个内建对象是不是构造函数呢? -比如,Object,在console里敲入`Object`,看到`function Object() { [native code] }`,那么,Object 就是一个构造函数。 -比如,Math,在console里敲入`Math`,看不到`function`字样,那么,Math 就不是一个构造函数。 +比如,Object,在console里敲入`new Object()`,没有报错,那么 Object 就是一个构造函数。 +比如,Math,在console里敲入`new Math()`,报错了,好吧,Math 就不是构造函数。 那么多原生构造函数,具体都是做什么的?大家可以参看MDN的文档。这里简单提一下 Object 和 Function这两个构造函数。 ===== 分隔线 ===== @@ -252,8 +252,8 @@ Foo.prototype; // 回车,然后看到返回下面的一个 Object ## 几个相关方法、运算符 (详情参考MDN文档) -- Object.getPrototypeOf(someObject):取代 \_\_proto__ 的 getter 功能(\_\_proto__ 已被弃用)。 -- Object.setPrototypeOf(someObject):取代 \_\_proto__ 的 setter 功能(\_\_proto__ 已被弃用)。 +- Object.getPrototypeOf(someObject):取代 \_\_proto__ 的 getter 功能(\_\_proto__ is deprecated)。 +- Object.setPrototypeOf(someObject):取代 \_\_proto__ 的 setter 功能(\_\_proto__ is deprecated)。 - Object.create():`var targeObject = Object.create(sourceObject)`,这行相当于: `targetObject = {__proto__: sourceObject}`。 “例5”的原型(《[Object.prototype][]》的示例)使用了 Object.create(),而且还有一行: `Employee.prototype.constructor = Employee;`。大家有时间可以考略一下为什么要设置(其实是重新设置) Employee.prototype.constructor? - SomeType.isPrototypeOf(someObject):`Foo.prototype.isPrototypeOf(foo); // true`。 @@ -310,9 +310,9 @@ class Employee extends Person { - [Object.prototype][] - [JS的内建对象][] -[继承与原型链]: https://developer.mozilla.org/zh-CN/docs/Web/JS/Inheritance_and_the_prototype_chain -[Inheritance and the prototype chain]: https://developer.mozilla.org/en-US/docs/Web/JS/Inheritance_and_the_prototype_chain +[继承与原型链]: https://developer.mozilla.org/zh-CN/docs/Web/javascript/Inheritance_and_the_prototype_chain +[Inheritance and the prototype chain]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain [内部属性]: http://stackoverflow.com/questions/17174786/what-is-the-significance-of-the-double-brackets-for-the-prototype-property-i -[Object.prototype.\_\_proto__]: https://developer.mozilla.org/en-US/docs/Web/JS/Reference/Global_Objects/Object/proto -[Object.prototype]: https://developer.mozilla.org/en-US/docs/Web/JS/Reference/Global_Objects/Object/prototype -[JS的内建对象]: https://developer.mozilla.org/en-US/docs/Web/JS/Reference/Global_Objects +[Object.prototype.\_\_proto__]: https://developer.mozilla.org/en-US/docs/Web/javascript/Reference/Global_Objects/Object/proto +[Object.prototype]: https://developer.mozilla.org/en-US/docs/Web/javascript/Reference/Global_Objects/Object/prototype +[JS的内建对象]: https://developer.mozilla.org/en-US/docs/Web/javascript/Reference/Global_Objects From 56f219df7881695bdc8d5ca5a3e637073acae799 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Mon, 28 Nov 2016 21:18:29 -0800 Subject: [PATCH 105/177] =?UTF-8?q?=E6=8F=90=E9=86=92=E5=8F=82=E8=80=83?= =?UTF-8?q?=E4=B8=AD=E6=96=87=E6=96=87=E6=A1=A3=E7=9A=84=E6=97=B6=E5=80=99?= =?UTF-8?q?=E5=AF=B9=E7=85=A7=E8=8B=B1=E6=96=87=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/articles/timliu/simple-prototype-chain/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md index c568bd9..02f7b46 100644 --- a/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md @@ -44,7 +44,7 @@ 为什么需要继承?因为省(我)事(懒)、省(我)资(很)源(懒)。比如:我们有一个 “太阳” 代码(包含构成、尺寸等等),还要设计 “北京的太阳” 代码,我们可以让 “北京的太阳” 继承 “太阳”,就是说不必重新设计 “构成、尺寸等等”,只要加上一个 “若隐若现” 就可以了。 而 JS 是以原型链的方式实现继承的。本文主要内容如下:(看不明白没关系,后面的段落会一一解释,希望我能解释明白。) - someObject.[[Prototype]] 内部属性:我称它为“我没有找它指针”,这个指针是链式的,“我没有?找它;它也没有?找它的它...”。原型链由这个内部属性串起。 -- someObject.\_\_proto__ 属性:这个是 [[Prototype]] 的访问器,可以认为 \_\_proto__ 和 [[Prototype]] 等效。(插播:MDN的中文文档《[继承与原型链][]》将“depreated”翻译成“已弃用”,这个说法有误导之嫌。\_\_proto__ 并非马上就不能用了,而是推荐大家使用 Object.getPrototypeOf 和 Object.setPrototypeOf。关于这两个方法,后面会简单介绍。) +- someObject.\_\_proto__ 属性:这个是 [[Prototype]] 的访问器,可以认为 \_\_proto__ 和 [[Prototype]] 等效。(插播:MDN的中文文档《[继承与原型链][]》将“depreated”翻译成“已弃用”,这个说法有误导之嫌。\_\_proto__ 并非不能用了,而是推荐大家使用 Object.getPrototypeOf 和 Object.setPrototypeOf。关于这两个方法,后面会简单介绍。另外,提醒一下,如果大家参考 MDN 的中文文档的话,一定要对照英文文档,因为 1) 翻译跟进不及时,2) 翻译可能有误。) - func.prototype 属性:func是个构造函数,func的实例的 [[Prototype]] 指向这个 func.prototype,即 func.prototype 是 func 的实例的原型。 - 原型链的尽头是null。 - 关于性能:原型链不要太长;没必要的情况下不要改变一个对象的 [[Prototype]]。 From 29f77944ca1d7f8ab91993757ce6f96344489660 Mon Sep 17 00:00:00 2001 From: rxjs-space Date: Mon, 28 Nov 2016 21:19:20 -0800 Subject: [PATCH 106/177] small fix --- .../api/articles/timliu/simple-prototype-chain/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md index 02f7b46..50d61c1 100644 --- a/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-prototype-chain/_index.md @@ -20,7 +20,7 @@ 上面这段摘自MDN的文档《[继承与原型链][]》(英文版文档比中文的多了一句,插播在这里,没有翻译)。这段里,形似 proto 的东西有三个(我统称它们为“proto 什么的”): - someObject.[[Prototype]] 内部属性:大写的 Prototype 被“双重方括号”括起来,我在console里敲一个,SyntaxError?! - - someObject.\_\_proto__ 属性:proto 的左右两边各有两个下划线(跟markdown没关系),“现已弃用”?那学它干啥?! + - someObject.\_\_proto__ 属性:proto 的左右两边各有两个下划线(跟markdown没关系),“现已弃用”(这里是翻译不准确,后面说明)?那学它干啥?! - func.prototype 属性:func是啥?func.prototype又是啥?“not to be confused with ...”?我很 confuse ,好吗!?! 真是够底层的,还是交给 Angular 们来对付这些“proto 什么的”吧,我要去做网站了。 From a9d7ecd2f148659ba92e05e937fecb239b7b8327 Mon Sep 17 00:00:00 2001 From: Trotyl Date: Wed, 30 Nov 2016 09:51:21 +0800 Subject: [PATCH 107/177] Fix some error and add more detail about input: event part. --- .../_index.md" | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git "a/src/app/_shared/api/articles/280.Angular2\344\270\255\347\232\204\351\200\232\344\277\241\346\226\271\345\274\217/_index.md" "b/src/app/_shared/api/articles/280.Angular2\344\270\255\347\232\204\351\200\232\344\277\241\346\226\271\345\274\217/_index.md" index 06d7ada..1e0622c 100644 --- "a/src/app/_shared/api/articles/280.Angular2\344\270\255\347\232\204\351\200\232\344\277\241\346\226\271\345\274\217/_index.md" +++ "b/src/app/_shared/api/articles/280.Angular2\344\270\255\347\232\204\351\200\232\344\277\241\346\226\271\345\274\217/_index.md" @@ -1,6 +1,6 @@ # Angular 2 中的通信方式 -软件工程中,随着应用规模的不断扩大,必然需要进行 Code Splitting。在 Web 开发中,组件化和模块化的观念已经被越来越多的人所熟知,从而编写出更高质量的代码。 +软件工程中,随着应用规模的不断扩大,必然需要进行 Logic Separation。在 Web 开发中,组件化和模块化的观念已经被越来越多的人所熟知,从而编写出更高质量的代码。 同时,随着实体职责的分离,我们也就会不可避免地需要进行实体间的相互通信,因为我们的应用仍然需要作为一个整体存在。因此,在本文中,将对 Angular 2 中的实体间通信方式进行简要介绍,以帮助读者编写更易于维护的代码。 @@ -103,7 +103,6 @@ class Child implements OnInit, OnDestroy { } this.propOneSubscription = value.subscribe(/* Some Logic */) - // Or use AsyncPipe in template } private propOneSubscription: Subscription @@ -118,7 +117,17 @@ class Child implements OnInit, OnDestroy { 当然,由于不像输出属性那样由 ng 自动管理,因此我们需要自行管理订阅,以免产生内存泄漏。 -这样,我们可以实现不需要对应数据的(父组件到子组件的)纯事件传递。 +不过,我们可以借助 [AsyncPipe](https://angular.io/docs/ts/latest/api/common/index/AsyncPipe-pipe.html),其中已经封装好了对 Observable 生命周期的管理,只需要在模版中指定即可。 + +```typescript +@Component({ + selector: 'child', + template: `

    {{ propOne | async }}

    ` +}) +class Child implements OnInit, OnDestroy { + @Input() propOne: Observable +} +``` 相比于直接的数据输入而言,事件流输入更有利于对组件内部状态的控制。 @@ -356,7 +365,7 @@ class DirectiveTwo { } 这样,通过某个共同的 Token,每个组件/指令都可以得到其他组件/指令给出的材料,而无需知晓其他组件/指令的具体存在。 -一个应用实例是 [FormControlName](https://angular.io/docs/ts/latest/api/forms/index/FormControlName-directive.html) 与 [Validator](https://angular.io/docs/ts/latest/api/forms/index/NG_VALIDATORS-let.html) 及 [AsyncValidator](https://angular.io/docs/ts/latest/api/forms/index/NG_ASYNC_VALIDATORS-let.html) 之间的交互,所有 Validator 指令都直接应用在 FromControl 所在的元素上,而 FormControl 无需知道每个 Validator 指令的具体形式(无论是内置的还是自定义的),只需要收集每个 Validator 指令所提供的验证函数即可。 +一个应用实例是 [FormControlName](https://angular.io/docs/ts/latest/api/forms/index/FormControlName-directive.html) 与 [Validator](https://angular.io/docs/ts/latest/api/forms/index/NG_VALIDATORS-let.html) 及 [AsyncValidator](https://angular.io/docs/ts/latest/api/forms/index/NG_ASYNC_VALIDATORS-let.html) 之间的交互,所有 Validator 指令都直接应用在 FormControl 所在的元素上,而 FormControl 无需知道每个 Validator 指令的具体形式(无论是内置的还是自定义的),只需要收集每个 Validator 指令所提供的验证函数即可。 当然,这并不是 `multi: true` 的唯一作用,比如我们还能通过 [APP_BOOTSTRAP_LISTENER](https://angular.io/docs/ts/latest/api/core/index/APP_BOOTSTRAP_LISTENER-let.html) 来监听应用的启动等等。 From aecef240ec2863d918b8e877019b72956ddbb1cd Mon Sep 17 00:00:00 2001 From: lhtin Date: Thu, 1 Dec 2016 14:14:43 +0800 Subject: [PATCH 108/177] fix: version error and require empty --- package.json | 22 +++++++++++----------- src/app/_shared/api/articles/index.ts | 20 ++++++++++---------- src/app/_shared/api/authors/index.ts | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index 33fff37..6c8f1de 100644 --- a/package.json +++ b/package.json @@ -52,15 +52,15 @@ }, "private": true, "dependencies": { - "@angular/common": "^2.0.0", - "@angular/compiler": "^2.0.0", - "@angular/core": "^2.0.0", - "@angular/forms": "^2.0.0", - "@angular/http": "^2.0.0", - "@angular/platform-browser": "^2.0.0", - "@angular/platform-browser-dynamic": "^2.0.0", - "@angular/platform-server": "^2.0.0", - "@angular/router": "^3.0.0", + "@angular/common": "^2.2.4", + "@angular/compiler": "^2.2.4", + "@angular/core": "^2.2.4", + "@angular/forms": "^2.2.4", + "@angular/http": "^2.2.4", + "@angular/platform-browser": "^2.2.4", + "@angular/platform-browser-dynamic": "^2.2.4", + "@angular/platform-server": "^2.2.4", + "@angular/router": "^3.2.4", "@angularclass/conventions-loader": "^1.0.2", "@angularclass/hmr": "~1.2.0", "@angularclass/hmr-loader": "~3.0.2", @@ -69,7 +69,7 @@ "core-js": "^2.4.1", "http-server": "^0.9.0", "ie-shim": "^0.1.0", - "rxjs": "5.0.0-beta.12", + "rxjs": "5.0.0-rc.4", "zone.js": "~0.6.17" }, "devDependencies": { @@ -147,7 +147,7 @@ "url-loader": "^0.5.7", "webpack": "2.1.0-beta.22", "webpack-dev-middleware": "^1.6.1", - "webpack-dev-server": "^2.1.0-beta.2", + "webpack-dev-server": "2.1.0-beta.10", "webpack-md5-hash": "^0.0.5", "webpack-merge": "^0.14.1" }, diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 5967d48..7cbe697 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -337,22 +337,22 @@ const items: Article[] = [ }, { id: '如何优雅升级ng2小版本', - title: '280.如何优雅升级ng2小版本', + title: '如何优雅升级ng2小版本', summary: '使用npm命令,搞定ng2小版本升级', content: require('./280.如何优雅升级ng2小版本/_index.md'), first: true, tags: ['ng2升级', 'npm 常用命令'], authors: ['木丁糖'], }, - { - id: '一个简单的RxJS Test Spec', - title: '一个简单的RxJS Test Spec', - summary: '简要介绍如何编写并运行RxJS Unit Test Spec', - content: require('./timliu/a-simple-rxjs-test-spec/_index.md'), - first: true, - tags: ['RxJS'], - authors: ['timliu'], - }, + // { + // id: '一个简单的RxJS Test Spec', + // title: '一个简单的RxJS Test Spec', + // summary: '简要介绍如何编写并运行RxJS Unit Test Spec', + // content: require('./timliu/a-simple-rxjs-test-spec/_index.md'), + // first: true, + // tags: ['RxJS'], + // authors: ['timliu'], + // }, { id: 'Angular2中的通信方式', title: 'Angular2中的通信方式', diff --git a/src/app/_shared/api/authors/index.ts b/src/app/_shared/api/authors/index.ts index 45fe9c8..669debe 100644 --- a/src/app/_shared/api/authors/index.ts +++ b/src/app/_shared/api/authors/index.ts @@ -74,7 +74,7 @@ const items: Author[] = [ name: '大炮', bio: '上天不要移開險峻,請賜予吾攀登之力', description: require('./67.大炮.md'), - avatar: require(''), + avatar: require('./_images/Tim刘.png'), columnist: false, homepage: 'https://github.com/btcioner/About-ME' }, From b60f52a13daf1fd8c9c306674b83934e2821c55f Mon Sep 17 00:00:00 2001 From: Trotyl Yu Date: Thu, 1 Dec 2016 14:17:59 +0800 Subject: [PATCH 109/177] Fix escaping of backtick --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4ae98c0..8c4dd80 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Angular中文社区热烈欢迎各位投稿。延续程序员的光荣传统, ## 总结 ``` -4. 代码尽量添加编程语言标识,例如:` ```js `(表示代码由js写成) +4. 代码尽量添加编程语言标识,例如:```` ```js ````(表示代码由js写成) 5. 每段文字上下都空一行,首行不需要留空格 6. 不要给标题添加序号 From 31f340f13c9c7950ba276217894d1e19b8b50797 Mon Sep 17 00:00:00 2001 From: twincle Date: Thu, 1 Dec 2016 16:54:15 +0800 Subject: [PATCH 110/177] =?UTF-8?q?+=20=E6=96=B0=E5=A2=9E=E6=96=87?= =?UTF-8?q?=E7=AB=A0=EF=BC=9A=E5=8D=95=E4=BE=8B=E6=A8=A1=E5=BC=8F=E4=B8=8E?= =?UTF-8?q?Angular?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 227 ++++++++++++++++++ src/app/_shared/api/articles/index.ts | 9 + 2 files changed, 236 insertions(+) create mode 100644 "src/app/_shared/api/articles/300.\345\215\225\344\276\213\346\250\241\345\274\217\344\270\216Angular/_index.md" diff --git "a/src/app/_shared/api/articles/300.\345\215\225\344\276\213\346\250\241\345\274\217\344\270\216Angular/_index.md" "b/src/app/_shared/api/articles/300.\345\215\225\344\276\213\346\250\241\345\274\217\344\270\216Angular/_index.md" new file mode 100644 index 0000000..b8e27b5 --- /dev/null +++ "b/src/app/_shared/api/articles/300.\345\215\225\344\276\213\346\250\241\345\274\217\344\270\216Angular/_index.md" @@ -0,0 +1,227 @@ +# 单例模式与Angular + +本文简单介绍单例模式的概念和作用,并结合Angular的依赖注入了解Angular中的单例模式用法。 + +本文力求用通俗易懂的语言描述,如有不严谨的地方还请多多指教。 + +## 没有单例模式的日子 + +通常我们定义一个类之后,会使用`new`关键字来创建一个类的实例,也就是对象。那么只要调用一次`new`关键字,就会生成一个全新的实例。 + +虽然每个实例都是由同一个类创建出来的,但是每个实例之间没有任何关联,修改、删除其中一个实例的属性,其他实例不会受到影响。 + +这里用一小段代码来直观的说明。 + +```typescript +// user.model.ts + +// 这里定义一个User类,其中name和age两个属性 +export default class User { + + name : string; + age : number; + + constructor (name : string, age : number) { + this.name = name; + this.age = age; + } + +} +``` + +```typescript +// main.ts + +import User from './user.model'; + +// 这里使用new关键字创建两个user实例 +const user1 = new User('Li Lei', 18); +const user2 = new User('Han Meimei', 17); + +console.log(user1.name); // Li Lei + +// 这里我修改user1的name属性,user2的name属性完全没有受到影响 +user1.name = 'Jim Green'; + +console.log(user1.name); // Jim Green +console.log(user2.name); // Han Meimei +``` + +这段代码看起来理所应当,完全没有可讨论的价值。也正是因为如此,我们才忽略了单例模式的作用和重要性。 + +## 单例模式的概念 + +顾名思义,单例模式就是某个类在**一定范围**内只有**一个实例**。 + +这句话该如何理解呢? + +在所谓的**一定范围**内,无论怎样获取类的实例,每次都只能得到**同样的实例**,无法获得与已有实例不同的新实例。从而确保了,在这个**一定范围**内,大家共用**同一个实例**,如果对这个实例进行修改,则会影响到所有使用该实例的代码。 + +不知大家是否已经感觉到,这样的说法,非常类似**全局变量**这样一个存在。 + +因此上面所谓的**一定范围**,**通常**就是指**全局范围**。 + +使用单例模式的类的基本逻辑是这样的: + +1. 没有公共的构造函数(`public constructor`),因此不能使用`new`关键字创建新实例; +2. 有一个专用于获取实例的静态方法,通常命名为`getInstance ()`(`static getInstance ()`); +3. 在这个方法中,判断当前是否已经有该类的实例。如果没有,则创建一个新实例(创建出来的实例就是唯一的实例);如果有,则返回该实例(确保没有新的实例被创建和返回)。 + +如果想了解实现单例模式的代码,可以参见本文最后一节。 + +## 单例模式的作用 + +### 存放全局变量 + +刚才从单例模式的概念和实现逻辑上,我们已经感觉出,单例模式很适合在全局变量上使用。 + +全局变量自然要在整个应用中的各处都保持一致,使用单例模式再合适不过。因此应用中的全局变量或全局方法,皆可以存放于使用单例模式的类中,确保全局一致。 + +### 节省内存开销 + +既然使用单例模式的类只存在一个实例,因此也就不会因为创建过多新实例而导致这些实例占用过多的内存。 + +单例模式的类实例永远只占用一个实例的内存开销。 + +试想如果有一个类,无论创建多少个新实例,实例之间都没有本质差别,这种情况下自然无需创建多个实例,只要有一个实例就足够。 + +在实际的应用中,service类多半即为这种情况。 + +因为service的功能被设计为处理业务逻辑,大多情况下service中只存放处理业务逻辑的方法,不存放具体的属性值,且处理业务逻辑的方法不会因为实例的不同而发生变化。 + +由此可见,即使大多情况下service类不使用单例模式也可正常运行,但使用单例模式无疑可以减少应用内存开销,提升运行效率。 + +### 业务需求确保全局唯一 + +某些情况下,如果业务要求全局必须只有唯一一个实例,这时就必须使用单例模式来实现。 + +例如在网站中缓存当前登录用户的对象,无论页面如何跳转,该登录用户必须最多只存在一个,如果用户登出并重新以另一用户身份登录,也不允许同时存放登出前和再次登录后两个不同的用户对象。且如果登录用户的属性发生了变化(例如用户修改了昵称),全局都要使用新属性值。 + +## Angular中的单例模式 + +如前所说,service类很适合使用单例模式实现。而Angular中的service正是使用单例模式的方式注入(依赖注入可参考[这篇文章](http://mp.weixin.qq.com/s/RXrjqwQj41rqlXZj2Z-w7w))到调用者中。 + +在Angular中,各类组件之间的相互依赖均使用依赖注入的方式相互调用,在设计良好的Angular项目中,几乎不会使用到`new`关键字来创建实例,所有的实例均交由Angular框架来帮你完成。 + +因此即使我们不了解单例模式的概念,也从没写过单例模式的实现代码,我们也从未在Angular中离开过单例模式的使用。 + +## Angular中单例模式的使用 + +在Angular中,单例模式使用`providers`来实现,我们先看一段代码。 + +```typescript +// app.module.ts + +import { BrowserModule } from '@angular/platform-browser'; + +import AppRootComponent from './app-root.component'; +import UserService from './user.service'; + +@NgModule({ + bootstrap: [ AppRootComponent ], + declarations: [ AppRootComponent ], + imports: [ BrowserModule ], + // 这里的providers就是使用单例模式注入service的用法 + providers: [ UserService ] +}) +export default class AppModule { +} +``` + +如上段代码所示,在`AppModule`中通过`@NgModule`装饰器中的`providers`属性供应了`UserService`,那么在**`AppModule`的范围内**,`UserService`即为单例模式,`AppModule`中无论在哪个组件中注入`UserService`,均为**同一实例**。 + +然而,`providers`属性不仅在`@NgModule`装饰器中存在,在`@Component`装饰器、`@Directive`装饰器中都有,我们该如何使用这些`providers`属性呢? + +## Angular中`prividers`的使用 + +在单例模式的概念中,我们反复强调过,单例模式是在**一定范围**内生效的,通常情况下,我们所谓的**一定范围**指的就是全局范围,但某些应用中我们需要在一个非全局范围的小范围内使用单例模式,超出这个范围的实例则使用新实例,而不是范围内已存在的单例。 + +Angular为我们提供了非常方便的限定单例模式适用范围的使用方法。 + +在Angular中,使用`providers`属性供应类单例,因此单例的适用范围即为`providers`属性所在的装饰器的范围。 + +也就是说,如果我们在`@NgModule`装饰器中使用`providers`属性供应某个类的单例,则在该module的范围内,所有组件注入的该类实例均为该单例;而在其他module中再注入该类实例,则为新的实例。`@NgModule`范围内的单例模式,非常类似于全局范围的单例模式,尤其是应用的根module中的单例。 + +同理,在`@Component`装饰器中使用`providers`属性供应某个类的单例,则在该component的范围内有效,其他component中再注入该类实例,则为新的实例。使用`@Directive`装饰器亦为如此。这种情况下即为小范围内的单例模式。 + +那么什么时候才会用到小范围内的单例模式呢? + +这种情况比较少见,Angular的官方文档也建议我们将service直接在`@NgModule`装饰器的`providers`属性中供应(官方文档:[https://angular.io/docs/ts/latest/cookbook/ngmodule-faq.html#!#q-component-or-module](https://angular.io/docs/ts/latest/cookbook/ngmodule-faq.html#!#q-component-or-module))。 + +因此,除非你很确定某个service必须仅限于某个组件中使用,否则建议直接将该service放置在module的`providers`属性中。 + +## 总结 + +说到这里,单例模式和Angular之间的关系已经说得差不多了,如果我们不了解单例模式和Angular之间的关系,则可能在某些情况下出现奇怪的错误。 + +例如我们在两个无关组件的`@Component`装饰器中提供了相同的全局变量service,则其中一个组件修改了全局变量,另一个组件则无法感知到,导致无法在页面中正常更新相关显示内容。 + +下面提供了一些扩展阅读内容,帮助你更好的理解本文的相关内容。 + +## 扩展阅读:AngularJS 1.x中的单例模式 + +AngularJS 1.x中的service(包括provider/factory/service/value/constant)同样也是单例模式,但相比Angular 2.x则有一些小小的缺陷。 + +最明显的就是,AngularJS 1.x中的单例模式永远是module范围内的,无法限制在某个controller或directive范围内。 + +因此,只要在某个module中注册了某个service,则在该module范围内均可用,且均唯一,无法在某个controller或directive范围内创建新的service实例。 + +## 扩展阅读:简单的单例模式实现 + +这里使用TypeScript来实现一个简单的单例模式类。 + +```typescript +// user.model.ts + +// 这里定义一个使用单例模式的User类 +// 其中name和age两个属性 +export default class User { + + // 这个私有静态属性,专门用来存放唯一的类实例 + private static instance : User; + + name : string; + age : number; + + // 这里将构造函数设为私有 + // 防止外部使用new关键字创建新的实例 + private constructor (name : string, age : number) { + this.name = name; + this.age = age; + } + + // 静态方法getInstance专门用来获取类实例 + // 如果用来存放唯一实例的私有静态属性instance不存在 + // 则创建一个唯一的新实例 + // 否则返回已存在的唯一实例 + static getInstance () : User { + if (User.instance === undefined) { + User.instance = new User('User Instance', 18); + } + + return User.instance; + } + +} +``` + +```typescript +// main.ts + +import User from './user.model'; + +// 这里使用getInstance方法获取User类的实例 +// 因此无论获取多少次,每次获取到的都是同样一个单例 +const user1 = User.getInstance(); +const user2 = User.getInstance(); + +console.log(user1.name); // User Instance +// 由于是同一个单例,因此user1和user2严格相等 +console.log(user1 === user2); // true + +// 这里我修改user1的name属性,user2的name属性同时也会发生变化 +user1.name = 'Jim Green'; + +console.log(user1.name); // Jim Green +console.log(user2.name); // Jim Green +``` diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 592d9f3..d45960b 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -273,6 +273,15 @@ const items: Article[] = [ tags: ['ng1', 'ng2', '平滑升级', 'es6', 'typescript'], authors: ['王開寧'], }, + { + id: '单例模式与Angular', + title: '单例模式与Angular', + summary: '简单介绍单例模式的概念和作用,并结合Angular的依赖注入了解Angular中的单例模式用法。', + content: require('./300.单例模式与Angular/_index.md'), + first: true, + tags: ['单例模式', 'Angular', '设计模式'], + authors: ['王開寧'], + }, ]; @Injectable() From c8df44743da5a83fcdc5b724628c75d3ec6e95ef Mon Sep 17 00:00:00 2001 From: twincle Date: Fri, 2 Dec 2016 17:49:12 +0800 Subject: [PATCH 111/177] =?UTF-8?q?*=20=E4=BF=AE=E5=A4=8D=E6=8B=BC?= =?UTF-8?q?=E5=86=99=E9=94=99=E8=AF=AF=20*=20=E5=AF=B9=E4=B8=8D=E4=B8=A5?= =?UTF-8?q?=E8=B0=A8=E4=B9=8B=E5=A4=84=E5=8A=A0=E4=BB=A5=E8=AF=B4=E6=98=8E?= =?UTF-8?q?=EF=BC=8C=E5=B9=B6=E6=8F=90=E4=BE=9B=E5=A4=96=E9=93=BE=E6=96=87?= =?UTF-8?q?=E7=AB=A0=E4=BD=9C=E4=B8=BA=E8=A1=A5=E5=85=85=E9=98=85=E8=AF=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git "a/src/app/_shared/api/articles/300.\345\215\225\344\276\213\346\250\241\345\274\217\344\270\216Angular/_index.md" "b/src/app/_shared/api/articles/300.\345\215\225\344\276\213\346\250\241\345\274\217\344\270\216Angular/_index.md" index b8e27b5..763557d 100644 --- "a/src/app/_shared/api/articles/300.\345\215\225\344\276\213\346\250\241\345\274\217\344\270\216Angular/_index.md" +++ "b/src/app/_shared/api/articles/300.\345\215\225\344\276\213\346\250\241\345\274\217\344\270\216Angular/_index.md" @@ -132,7 +132,7 @@ export default class AppModule { 然而,`providers`属性不仅在`@NgModule`装饰器中存在,在`@Component`装饰器、`@Directive`装饰器中都有,我们该如何使用这些`providers`属性呢? -## Angular中`prividers`的使用 +## Angular中`providers`的使用 在单例模式的概念中,我们反复强调过,单例模式是在**一定范围**内生效的,通常情况下,我们所谓的**一定范围**指的就是全局范围,但某些应用中我们需要在一个非全局范围的小范围内使用单例模式,超出这个范围的实例则使用新实例,而不是范围内已存在的单例。 @@ -150,9 +150,13 @@ Angular为我们提供了非常方便的限定单例模式适用范围的使用 因此,除非你很确定某个service必须仅限于某个组件中使用,否则建议直接将该service放置在module的`providers`属性中。 +除此之外,Angular中还有一些较为复杂的注入单例的情况:嵌套注入、懒加载注入、外部模块导入注入等,由于这些情况下的注入单例规则较为复杂,各位可查看这篇[专门讲述这些情况的文章](http://mp.weixin.qq.com/s/hDQsllMQwkJjBh5Mhuyt3A)。 + ## 总结 -说到这里,单例模式和Angular之间的关系已经说得差不多了,如果我们不了解单例模式和Angular之间的关系,则可能在某些情况下出现奇怪的错误。 +说到这里,单例模式和Angular之间的关系已经说得差不多了,本文对单例模式及其在Angular中的应用做了简单的探讨,希望能够抛砖引玉。 + +如果我们不了解单例模式和Angular之间的关系,则可能在某些情况下出现奇怪的错误。 例如我们在两个无关组件的`@Component`装饰器中提供了相同的全局变量service,则其中一个组件修改了全局变量,另一个组件则无法感知到,导致无法在页面中正常更新相关显示内容。 @@ -195,7 +199,8 @@ export default class User { // 则创建一个唯一的新实例 // 否则返回已存在的唯一实例 static getInstance () : User { - if (User.instance === undefined) { + if (typeof User.instance === 'undefined') { + // 如果不存在已有的instance,则初始化一个新的instance User.instance = new User('User Instance', 18); } From fec632bb30a3cafdaeff4c3f81d275c820d35178 Mon Sep 17 00:00:00 2001 From: Trotyl Date: Mon, 5 Dec 2016 15:50:10 +0800 Subject: [PATCH 112/177] Add article: Structural Directive in Angular 2. --- .../_index.md" | 362 ++++++++++++++++++ .../ng_probe.png" | Bin 0 -> 57374 bytes src/app/_shared/api/articles/index.ts | 9 + 3 files changed, 371 insertions(+) create mode 100644 "src/app/_shared/api/articles/290.Angular 2 \344\270\255\347\232\204 Structural Directive/_index.md" create mode 100644 "src/app/_shared/api/articles/290.Angular 2 \344\270\255\347\232\204 Structural Directive/ng_probe.png" diff --git "a/src/app/_shared/api/articles/290.Angular 2 \344\270\255\347\232\204 Structural Directive/_index.md" "b/src/app/_shared/api/articles/290.Angular 2 \344\270\255\347\232\204 Structural Directive/_index.md" new file mode 100644 index 0000000..af55c6e --- /dev/null +++ "b/src/app/_shared/api/articles/290.Angular 2 \344\270\255\347\232\204 Structural Directive/_index.md" @@ -0,0 +1,362 @@ +# Angular 2 中的 Structural Directive(结构型指令) + +原文发布于:https://zhuanlan.zhihu.com/p/22404947 + +友情提示: + ++ 这篇文章由于本身的内容取向,需要尽可能地保持严谨和全面,因此,可能对初学者并不十分友好。如果阅读本文的过程中觉得难度过大,可以考虑先把原文放入收藏夹中,过一段时间再来阅读; ++ 原文为双语版本,此处由于受众主要为中文用户所以仅摘录了中文部分,需要英文版本的读者可以进入上面的原文链接进行阅读。 + +Directive 一直是 Angular 中的一个重要组成部分,职能为扩展 HTML 语义。在 Angular 2 中,__Directive 被明确划分成三种类型:Component,Attribute Directive 以及 Structural Directive__(其中 Angular 1.x 也有这个划分,只是官方文档中没有明确提及)。其中,Structural Directive 虽然数量最少,却有着极高的重要性。 + +Angular 2 中,在 common 模块里内置了 3 个 Structural Directive:[NgIf](https://angular.io/docs/ts/latest/api/common/index/NgIf-directive.html),[NgFor](https://angular.io/docs/ts/latest/api/common/index/NgFor-directive.html) 和 [NgSwitch](https://angular.io/docs/ts/latest/api/common/index/NgSwitch-directive.html)。和 Angular 1.x 有很大不同的是,__Angular 2 提供了通用的星号 DSL(类似于 *prop="something")来实现自定义表达式语法__,而 Angular 1.x 只能自己靠正则匹配。其中,在 [Structural Directives](https://angular.io/docs/ts/latest/guide/structural-directives.html) 和 [Template Syntax](https://angular.io/docs/ts/latest/guide/template-syntax.html) 部分对这些 Directives 做了一些简单的介绍。但由于实在介绍的过于简单,既没有解释 DSL 的详细规则,也没有说明其运作原理。 + +本文中,将会解决这些,对 Structural Directive 的概念及原理进行介绍,同时剖析 NgFor 的实现方式以方便读者理解。 + + +## DSL 语法规则 + +为了解释语法规则,我们首先从 DSL 的翻译过程入手。__星号 DSL 会被翻译两次__,其中的第一次非常特别极其简单,也就是: + +```html +Content + + + +Content +``` + +接下来才是重要的部分,也就是第二次翻译,在第一次翻译后,才是 Angular 的解析器真正工作的开始(第一次翻译连正则都不用靠字符串拼接都能完成)。简单的说,__template 属性的值必须是一系列分号分隔的语句__,每个语句可以是: __1)赋值,2)冒号分隔的键值对__。类似于: + +```html + +``` + +由于第一次翻译的缘故,第一个语句必然是键值对,也就是星号 DSL 的第一项内容必然是表达式,后面的语句可以自己任意排列。但是,稍微有点常识的人都能够看出,__我们天天在用的 NgFor 显然就不满足这个规则,那么为什么会是这个规则呢__?我们的 NgFor 第一次翻译后明明是: + +```html + +``` + +这里并没有那些分隔符号的痕迹,不是么?是,也不是。事实上,和很多现代语言一样,当你不主动提供分隔符时,__Angular 的模版解析器会自动尝试添加分隔符__,也就是帮你断句。此外,由于这个 DSL 几乎完全没有任何的二义性,因此添加或不添加(或部分添加部分不添加)分隔符几乎永远都能得到相同的结果。因此,上面的代码完全等价于: + +```html + +``` + +这样看着和我们上面的规则接近了很多,但还是有些不同,也就是:1)第一个 key(也就是 ngFor)并没有对应任何的 value,2)赋值部分没有赋任何值。实际上,这里仅仅是一丢丢的简简单单的语法糖的语法糖,也就是规则的附加规则,即:__1)如果后一语句是赋值,则当前的键值对可以只有键没有值,2)如果赋值只有变量声明部分没有赋值部分,相当于赋上 $implicit 这个变量的值__。另外,不知道是 Bug 还是 Feature,第一条额外规则所述的情况中键值对和赋值之间不能手动加分号,当然,对于从星号 DSL 翻译过来的情况,第一个键值对和第一个赋值(如果是赋值的话)之间本来就不会有分号。因此,上面的代码又可以继续等价为: + +```html + +``` + +接着,现在开始就可以真的进行第二次翻译了。又一次简单的说,__1)对于键值对,第一个键值对的键会被当作基,添加到其后所有键值对的键之前,然后变成属性绑定(如果键值对没有值之后也就是一个没有值的属性);2)对于赋值,会被翻译成一个 `let-` 开头的字面值属性绑定__。至此,我们就能够很清晰的理解第二次翻译的结果了,也就是: + +```html + +``` + +友情提示,在 Angular 2 中,__有方括号(或 bind- 前缀)的属性和没有方括号(或 bind- 前缀)的属性都是属性绑定__。对于有方括号(或 bind- 前缀)的属性而言,例如 `[prop]="1 + 1"`,其数据绑定的内容是 `1 + 1` 的求值结果,也就是 2 这个数值(number);而对于没有方括号(或 bind- 前缀)的属性而言,例如 `prop="1 + 1"`,其数据绑定的内容是 `1 + 1` 这个字面值本身,也就是 "1 + 1" 这个字符串(如果有插值的话绑定的是插值后的结果)。一些文章或视频中为了和事件绑定押韵而把属性绑定说成是有方括号(或 bind- 前缀)的属性是不严谨的。 + +最后补充一点,__`$implicit` 其实只是语义上的表现__,并不直接存在于翻译结果中,所以直接的翻译结果是: + +```html + +``` + +综上,这就(应该)是星号 DSL 的规则了,因此我们现在也终于能理解 NgFor 的翻译过程了。 + +现在,如果我们愿意,我们可以用任何喜欢的方式来写 NgFor: + +```html + + + + + +``` + +## NgFor 的内部实现 + +从上一小节中我们知道,星号语法糖会被编译为普通的属性绑定。也就是说,__Structural Directive 在形式上并不会和 Attribute Directive 有任何不同__,只是它在内部所做的事情和 Attribute Directive 所做的事情的侧重点有些差异。 + +与其他 Directives 一样(对于 Entry Component 而言可能不是必须的),__NgFor 需要有一个 selector 来指定其应用的范围__。从上面的翻译结果我们知道,NgFor 需要作用在一个有 ngFor 属性和 ngForOf 属性的(template)元素上,因此对应的选择器就是 `[ngFor][ngForOf]`。在 CSS 中,属性选择器使用方括号的语法,并且多个选择器的组合仍然为选择器。于是我们得到 NgFor 的骨架: + +```typescript +@Directive({ + selector: '[ngFor][ngForOf]' +}) +class NgFor { + // 类名叫什么并不重要 +} +``` + +Angular 2 中,所有的 Directive(当然也包括 Component)都是 ES Class(当然实际上也可以用 Angular 2 的 ES5 API 来模拟 class 的方式),通过 Decorator 来实现额外的配置内容。 + +从上面我们已经知道,NgFor 会有两个 @Input() 属性(即属性绑定):ngForOf 和 ngForTrackBy。这里我们会发现一个问题,NgFor 的选择器和其属性绑定并不对应,这是正常的情况。对于选择器而言,我们需要应用在一个所有场景里都能满足的选择器上,而 trackBy 是可选的部分,所以并不会出现在 Directive 的 selector 中,否则我们不写 trackBy 的时候它就不是 NgFor 了;对于属性绑定而言,我们只需要有值的属性,ngFor 属性虽然始终存在但是并没有任何内容,所以每次去拿到一个 undefined 也没有任何意义,而输入属性需要考虑所有的可选内容,比如这里的 trackBy。(实际上可能还有另外的属性绑定,但此处不作深入讨论) + +所以现在我们可以增加属性绑定的声明: + +```typescript +@Directive({ + selector: '[ngFor][ngForOf]' +}) +class NgFor { + @Input() ngForOf: any + @Input() ngForTrackBy: TrackByFn +} + +// interface TrackByFn { (index: number, item: any): any } +``` + +这里我们增加一个 ngForOf 属性,为 any 类型(其实这里本应该是 Iterable 类型,即实现了 Symbol.iterator 属性的对象);另一个是 ngForTrackBy,是一个满足特定签名的函数类型(接收当前的 index 和集合中的当前 item 作为参数,返回任意值作为唯一性标识),这和我们在 Angular 1.x 中的用法稍有不同,我们无法继续使用内联表达式来作为标识,必须抽取成一个类方法。 + +有了参数,接下来我们就可以来进行操作了。这里我们需要做的事情很简单,__就是把 Template 变成一个 View,然后放进 ViewContainer 里__。 + +听上去可能有些陌生,Template 是什么呢?在 Component 中,我们会提供一个 template(或 templateUrl)属性,会自动进行 Template -> View 的转换,因为这里要做的操作非常简单,__一个 Component 有且只有一个 Template,并且也只会对应的一个 View__。而在 Structural Directive 中,就未必能有这么简单了,__比如这里我们需要根据循环项把同一个 Template 变成多个 View__。 + +我们知道 Angular 1.x 中有一个 $compile,其工作过程是: + +```text + compile + scope +template(raw/element) ---------> linkFn ---------> instance element +``` + +类似的,在 Angular 2 中,也有一个模版(Template)到视图(View)的过程: + +```text +For component template: + + compile +template(raw) ---------> view factory -----------> view + + +For template tag template: + + compile + context +template(raw) ---------> template(compiled) -----------> view +``` + +看到这里,读者可能会有若干的疑问: + ++ 为什么 Angular 2.0 中生成的结果是一个 View,这个抽象实体的存在目的是什么? ++ 为什么 Angular 2.0 中的 Template 在 Compile 之后还是 Template,那么 Template 到底指什么? ++ 为什么 Component 的 Template 就不需要 Context 就能实例化,而其他的 Template 就需要 Context 才能实例化呢? ++ Angular 2.0 中的 Context 和 Angular 1.x 中的 Scope 是什么关系?是不是像 Filter -> Pipe 那样的简单改名? + +接下来,我们就会对这些问题一一解答。 + +众所周知,__Angular 2.0 的一个重大改进就是能够跨平台,因此,不再像 Angular 1.x 中一样使用基于 DOM 的模版,也不能像服务器端模版那样直接使用基于字符串的模版。为此,必须引入一个中间抽象(但并没有使用 Virtual-DOM)__。所以,Angular 2.0 中不再是直接生成 DOM 元素的实例,而是一个更为高层的抽象视图的实例,这里叫做 View。 + +其实目前已有在 Web 平台中直接生成 DOM 元素的改进计划 [Perf: Direct Dom Rendering · Issue #11394 · angular/angular · GitHub](https://github.com/angular/angular/issues/11394),但这个属于性能上的透明优化,并不会影响到这里的概念解释。 + +另外,由于不是基于 DOM 的模版,__并不像 Angular 1.x 那样先将 Template 丢给浏览器渲染然后再对 DOM 对象进行操作,而是自行对原始字符串进行解析,然后根据分析结果直接操纵 DOM API 来按照需要构建元素,整个过程中都没有浏览器对 HTML 字符串的渲染行为发生__。当然,由于 Compiler 的功能过于强大,其本身的文件大小和工作时间都是不小的成本。 + +不过另一方面,由于 __Angular 2.0 中引入了一套通用的模版语法(对 HTML 的扩展),而不再像 Angular 1.x 中那样由每个 Directive 自行定义其 Compile 函数和自行正则匹配复杂表达式,因此,Angular 2.0 的模版编译并不需要发生在运行时,可以直接在编译时完成模版的编译__(类似于 jsx 的构建方式,但稍略复杂)。所以我们在运行时永远拿到的都是编译后的模版,而不会用到原始的字符串模版。 + +_一些 Demo 中可能会使用在运行时编译模版的方式,但这只是为了方便演示,实际生产环境为了性能基本并不会这么做。另外,一些极其特殊的项目可能也会需要对组件的动态模版来实时构建,这里会需要用到 Compiler API,但在一般项目中基本不会遇到,这里不做过多讨论。_ + +然后,我们还有一个新的实体叫 Context,但严格地说,它并不是一个实体。就像很多库中(比如 lodash)会有最后一个叫做 context 的参数一样,__仅仅是一个环境绑定,没有任何固定的类型也没有任何职能所在,除了作为 this 指针(变量)的指向__。或者说,这里的 Context 概念上就是一个纯粹的 ViewModel。反观 Scope,除了作为 ViewModel 外,还承担了 Watcher、Evaluator、ChangeDetector、Differ、EventEmitter、EventListener 的作用,严重破坏了单一职责的基本要求。所以,__Context 完全不是 Scope,但反过来,Scope 确实是 Context__。不过,由于 Context 本身只是一个抽象职责,所以很多时候并不是一个独立的实体。比如在组件模版中,Context 就是组件实例自身;而在 NgFor 的模版中,Context 就是一个 NgForRow 的实例。这也就是为什么 Component 的 Template(看似)不需要提供 Context。 + +在浏览器中,我们可以在控制台内使用: + +```javascript +ng.probe($0 /* a DOM element reference */) +``` + +得到的 [DebugElement](https://angular.io/docs/ts/latest/api/core/index/DebugElement-class.html) 来快速查看某个位置对应的 Context 信息。(如下图所示) + +![ng.probe demo](./ng_probe.png) + +回到正题,由于有依赖注入,我们这里可以很方便地获取我们所需的服务: + +```typescript +//... +class NgFor { + //... + constructor( + private _viewContainer: ViewContainerRef, + private _template: TemplateRef, + private _differs: IterableDiffers, + private _cdr: ChangeDetectorRef + ) { } + //... +} + +class NgForRow { + constructor(public $implicit: any, public index: number, public count: number) { } + + get first(): boolean { return this.index === 0; } + get last(): boolean { return this.index === this.count - 1; } + get even(): boolean { return this.index % 2 === 0; } + get odd(): boolean { return !this.even; } +} +``` + +首先解释下这里用到的 TypeScript 语法。TypeScript 中,通过在构造函数的参数前加上 public/private 修饰符,可以将其自动绑定为实例的属性。即: + +```typescript +class SomeClass { + constructor(private name: Type) { } +} +``` + +等价于: + +```typescript +class SomeClass { + private name: Type + constructor(name: Type) { this.name = name } +} +``` + +另外,这里还用到了泛型,这也是面向对象语言中很常用的特性。其中,TemplateRef 是一个开类型,可接受一个类型参数;这里的 NgForRow 其实就是这里的 Context 的类型,在这里作为 TemplateRef 的类型参数,之后即可通过 TemplateRef 这样得到对应的闭类型。在类型定义中,我们可以充分利用泛型语法,来构造通用的 API: + +```typescript +function identity(self: T): T { return self } +const sth = identity(5) +``` + +例如上面的示例中,我们定义了一个没什么用的函数,永远返回参数本身。但通过泛型,我们可以让返回值的类型永远等同于参数的类型,而不需要对所有的类型都定义一个函数,或者使用 any 造成无法进行类型检查。 + +此外,class、getter/setter 等都是 JavaScript 的基本概念,这里不多介绍。 + +这里我们需要 4 个依赖,分别是 [ViewContainer](https://angular.io/docs/ts/latest/api/core/index/ViewContainerRef-class.html)、[Template](https://angular.io/docs/ts/latest/api/core/index/TemplateRef-class.html)、[Differ](https://angular.io/docs/ts/latest/api/core/index/IterableDiffer-interface.html) 和 [ChangeDetector](https://angular.io/docs/ts/latest/api/core/index/ChangeDetectorRef-class.html),其中,ViewContainer、Template 和 ChangeDetector 是直接通过 Ref 的方式获得,而 Differ 是通过 Factory 的方式来主动创建的。 + +__Angular 2.0 默认采用了脏检测作为变化检测的策略__。脏检测是一种广泛使用的变化检测方式,通过事后比较的方式来寻找变化部分,Angular 1.x、Angular 2.0 和 React 等主流库/框架都使用了脏检测的方式来检测变化。(虽然 React 自己很少这么说) + +因此,为了能够检测变化,我们需要回答两个问题:什么时候进行检测?怎样进行检测?Angular 1.x 采用了较为落后的方式,在每一次可能引起变化的事件中都进行全量的比较。而在 Angular 2.0 和 React 中采用了一定的优化方案,基于组件化和单项数据流的特性,我们可以很大程度上缩小需要检测的范围,提高性能。 + +而在 Angular 2.0 中,__我们可以通过 ChangeDetectorRef 类型来实现对 ChangeDetection 的过程的控制__,虽然在一般的程序中可能不大会用得到。实际上,这里的 ChangeDetectorRef 仅仅是一个 Role,并不是真的有这个 ChangeDetectorRef 类型单独的实例,由于 TypeScript 中 interface 是运行时不可见的而 class 又是 structural 的,这么做并没有什么实现上的问题。由于 Angular 2.0 的应用是一个组件树,我们可以动态调整当前组件子树的状态,从其类型签名就可以了解: + +```typescript +class ChangeDetectorRef { + markForCheck() : void + detach() : void + detectChanges() : void + checkNoChanges() : void + reattach() : void +} +``` + +另外还有一个 Differ 类型,相比之下,Differ 并不是 Angular 2.0 的什么重要组成部分,只是一系列工具库,用来对不同类型的对象进行比较得出变化情况。实际上,如果我们愿意的话,我们也可以完全不使用脏检测,自行定义别的检测方式,不过鉴于 Angular 2.0 本身的优化情况,使用脏检测并没有什么性能问题。 + +对于 IterableDiffer(同样适用于其他的 Differ 类型),这里涉及到了几个类型分别是:[IterableDiffer](https://angular.io/docs/ts/latest/api/core/index/IterableDiffer-interface.html)、[IterableDiffers](https://angular.io/docs/ts/latest/api/core/index/IterableDiffers-class.html)、[IterableDifferFactory](https://angular.io/docs/ts/latest/api/core/index/IterableDifferFactory-interface.html) 和 [DefaultIterableDiffer](https://angular.io/docs/ts/latest/api/core/index/DefaultIterableDiffer-class.html)。其中 IterableDiffer 是一个接口,DefaultIterableDiffer 是 IterableDiffer 的一个实现类,IterableDifferFactory 是 IterableDiffer 对应工厂类型的接口,IterableDiffers 是 IterableDiffer 的工具类。当然,事实上也是有 DefaultIterableDifferFactory 这个类型的,只是并没有归入文档中,因此不做介绍。其中,IterableDifferFactory 有一个 supports 方法,用来确定是否支持某个具体的 Iterable 对象(有很多类型都实现了 Iterable,比如常见的数组,不常见的生成器函数的返回值等)。为此,IterableDiffers 也提供了一个 find 方法,用来自动查找可用于这个对象的 IterableDifferFactory,类似于: + +```typescript +this._differ = this._differs.find(value).create(this._cdr, this.ngForTrackBy) +``` + +当然,作为工厂类型,有一个 create 方法是无序过多介绍的,其接受两个参数,分别是 ChangeDetectorRef 和 TrackBy 函数,之后返回一个 IterableDiffer 实例。当然,因为这里的 find 是可能会失败的,因为可能支持某个对象实例的 Differ 并不存在。换句话说,__我们也可以提供自定义的 IterableDifferFactory 来扩展 NgFor 能够支持的类型范围__(通过 IterableDiffers.extend ),这也是单一职责或者说低耦合性带来的一个巨大便利。 + +Angular 2.0 也和其他组件化的实现一样,__具有生命周期(Life-Cycle Hook)这个概念__。这里我们需要用到两个 Hooks:OnChanges 和 DoCheck。 + +OnChanges 正如其名,就在每次发生变化时调用。然而,我们干的事情并不是每次变化都起作用,而是只需要第一次执行就能完成: + +```typescript +//... +class NgFor implements OnChanges { + //... + + private _differ: IterableDiffer = null; + + ngOnChanges(changes: SimpleChanges): void { + if ('ngForOf' in changes) { + const value = changes['ngForOf'].currentValue; + if (!this._differ && value) { + try { + this._differ = this._differs.find(value).create(this._cdr, this.ngForTrackBy); + } catch (e) { throw new Error(`...`); } + } + } + } +} +``` + +这里又接触到了一个新的类型,SimpleChanges,就是一个简单的当字典用的对象,每个 key 是属性名称(实际上是 input 的名称),value 是一个 SimpleChange 类型的对象。那么 SimpleChange 又是什么呢?看一看结构就很清楚了: + +```typescript +class SimpleChange { + constructor(previousValue: any, currentValue: any) + previousValue : any + currentValue : any + isFirstChange() : boolean +} +``` + +这个我们在熟悉不过了,和 Scope.$watch 的回调参数非常相似,这里我们可以得到每个变化了的属性的旧值和新值,以及一个能确定是否为首次变化的函数。 + +不过上面并不是重点,只是为了让我们能够继续读代码。仔细进行分支检查我们可以发现,真正的内容只可能会被执行一次,__而且所谓的真正的内容唯一的作用就是初始化 Differ,之后的变动也不会造成任何影响__。那么,为什么一定要这么做呢?而不是在 OnInit 的时候就把 Differ 给初始化好呢? + +这里就有一个逻辑问题,上面我们已经知道,具体使用的 Differ 是需要根据对应 Iterable 的实际类型来确定的,而 ngForOf 却不一定是在组件初始化时就已经存在的(比如使用 async 这个 Pipe),所以在组件初始化的时候我们还未必能确定 ngForOf 这个 Iterable 的类型,因此也就无法获取对应类型的 IterableDiffer。(不过话说真的有必要搞得这么复杂么?)所以说,虽然这里是 OnChanges 这个接口,但只是进行初始化这个操作,理解了这点,我们就能够继续往下了。 + +当然,我们也能够发现这里用到了两个假设: + ++ ngForOf 的类型是不会发生变化的。即不会现在循环一个 Array,过一会又变成一个 Set,当然实现上可能并不会发生问题,但原理上并不应当出现这种情况; ++ ngForTrackBy 始终不会发生变化。即不能在初始化以后修改 ngForTrackBy 的绑定,正常情况下也当然不会这么做。 + +除了 OnChanges 这个接口外,我们还实现了另一个接口:DoChecks。并且这里是真真正正的来 DoCheck,并不像上面的 OnChanges 那样挂羊头卖狗肉,而是真正的实现了检测变化的功能: + +```typescript +//... +class NgFor implements OnChanges, OnChanges { + //... + + ngDoCheck() { + if (this._differ) { + const changes = this._differ.diff(this.ngForOf); + if (changes) this._applyChanges(changes); + } + } +} +``` + +这里的功能很简单,如果有 Differ 的情况下(上面说到由于 ngForOf 指不定什么时候才有因此 Differ 也是指不定什么时候才有的),会调用 Differ 的 diff 方法来检测变化,如果有变化则进行后续操作。这里略有一点 Tricky,甚至可以说可能有潜在错误隐患,直接假定了当前的 Differ 就是 DefaultIterableDiffer(实际上上面也说道用户可以提供另外的 DifferFactory),从而可以写出下面的变化应用代码: + +```typescript +private _applyChanges(changes: DefaultIterableDiffer) { + const insertTuples: RecordViewTuple[] = []; + changes.forEachOperation( + (item: CollectionChangeRecord, adjustedPreviousIndex: number, currentIndex: number) => { + if (item.previousIndex == null) { + const view = this._viewContainer.createEmbeddedView( + this._template, new NgForRow(null, null, null), currentIndex); + const tuple = new RecordViewTuple(item, view); + insertTuples.push(tuple); + } else if (currentIndex == null) { + this._viewContainer.remove(adjustedPreviousIndex); + } else { + const view = this._viewContainer.get(adjustedPreviousIndex); + this._viewContainer.move(view, currentIndex); + const tuple = new RecordViewTuple(item, >view); + insertTuples.push(tuple); + } + }); + + //... +} +``` + +这里用到了 DefaultIterableDiffer 的一个重要特性,其 diff 方法中,如果没有变化内容,则返回 null,如果有变化内容,则返回其自身,因此这里的 changes 参数仍然是一个 DefaultIterableDiffer。之后的代码就很简单,对于每一个元素变化,如果是新增的元素,就在自己的 ViewContainer 中为其新建一个 View,其中,Template 就是拿到的 TemplateRef,Context 为新建的一个 NgForRow 类型的实例,Index 为当前 Iterable 元素的 Index,并将其单独添加到一个数组中以供某后续操作(其实就是设一下 $implicit 的值);如果是被删除的元素,则直接将其 View 从 ViewContainer 中删除即可;如果是内容有变化的元素(可能是顺序变化也可能是元素本身变化),则将其 View 在 ViewContainer 的位置也进行对应调整,也同样将其加入到某待后续操作的数组中。 + +```typescript +private _applyChanges(changes: DefaultIterableDiffer) { + //... + for (let i = 0; i < insertTuples.length; i++) { + this._perViewChange(insertTuples[i].view, insertTuples[i].record); + } + //... +} + +private _perViewChange(view: EmbeddedViewRef, record: CollectionChangeRecord) { + view.context.$implicit = record.item; +} +``` + +紧接着就是刚刚我们提到的某后续操作,真的就只是设置一下 Context 的 $implicit 属性。如果不记得这个是什么了的,可以往上翻翻看,其实就是 `let item of items` 中 `item` 的值。 + +至此,我们可以知道,NgFor 没有使用 DOM 操作,仍然保持着 Angular 2 的平台无关性。同时,也并没有使用什么黑魔法,只是用到了一些平常不太会用到的 API。所以,NgFor 并没有任何的实现上的特殊性,我们完全可以自行实现一个 NgFor 或者类似功能的 Structural Directive。 diff --git "a/src/app/_shared/api/articles/290.Angular 2 \344\270\255\347\232\204 Structural Directive/ng_probe.png" "b/src/app/_shared/api/articles/290.Angular 2 \344\270\255\347\232\204 Structural Directive/ng_probe.png" new file mode 100644 index 0000000000000000000000000000000000000000..bb92f44ef5cb3587f2c20ce6717c7464b84d728b GIT binary patch literal 57374 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
    JYm#@)VWvDBPZX4QE#w? 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

    JYm#@)VWvDBPZX4QE#w? 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 QC Date: Mon, 5 Dec 2016 15:52:58 +0800 Subject: [PATCH 117/177] Make original link a real link. --- .../_index.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/src/app/_shared/api/articles/290.Angular 2 \344\270\255\347\232\204 Structural Directive/_index.md" "b/src/app/_shared/api/articles/290.Angular 2 \344\270\255\347\232\204 Structural Directive/_index.md" index af55c6e..3d6bb50 100644 --- "a/src/app/_shared/api/articles/290.Angular 2 \344\270\255\347\232\204 Structural Directive/_index.md" +++ "b/src/app/_shared/api/articles/290.Angular 2 \344\270\255\347\232\204 Structural Directive/_index.md" @@ -1,6 +1,6 @@ # Angular 2 中的 Structural Directive(结构型指令) -原文发布于:https://zhuanlan.zhihu.com/p/22404947 +原文发布于:[https://zhuanlan.zhihu.com/p/22404947](https://zhuanlan.zhihu.com/p/22404947) 友情提示: From 84d9a8ba75af595aa0dbef0020946d0b202cc8fd Mon Sep 17 00:00:00 2001 From: Trotyl Date: Tue, 6 Dec 2016 14:26:12 +0800 Subject: [PATCH 118/177] Add column info. --- src/app/_shared/api/articles/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 2ce1639..022e5fd 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -350,6 +350,7 @@ const items: Article[] = [ summary: 'Angular 2 中,我们难免需要进行组件间的相互通信,但是这些通信方式你真的都知道吗?', content: require('./280.Angular2中的通信方式/_index.md'), first: true, + column: 'trotyl', tags: ['ng2'], authors: ['trotyl'], }, @@ -368,6 +369,7 @@ const items: Article[] = [ summary: 'Angular 2 中,*NgFor 这种神奇的写法及其功能是如何实现的呢?本文将深入探寻 Structural Directive 的本质', content: require('./290.Angular 2 中的 Structural Directive/_index.md'), first: false, + column: 'trotyl', tags: ['ng2', 'Structural Directive'], authors: ['trotyl'], }, From 67dbcfa86af0bea8b9a8461a43b0e79c34cb5dd5 Mon Sep 17 00:00:00 2001 From: Trotyl Date: Tue, 13 Dec 2016 17:51:31 +0800 Subject: [PATCH 119/177] Update shrinkwrap. --- npm-shrinkwrap.json | 6923 ++++++++++++++++++++++++++++++++++++++++++- package.json | 2 +- 2 files changed, 6769 insertions(+), 156 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 21528a0..791e220 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,230 +1,6843 @@ { - "name": "angular2-webpack-starter", - "version": "5.0.5", + "name": "user-ui", + "version": "0.0.0", "dependencies": { "@angular/common": { - "version": "2.0.0-rc.6", - "from": "@angular/common@2.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-2.0.0-rc.6.tgz" + "version": "2.3.0", + "from": "@angular/common@>=2.2.4 <3.0.0", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-2.3.0.tgz" }, "@angular/compiler": { - "version": "2.0.0-rc.6", - "from": "@angular/compiler@2.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-2.0.0-rc.6.tgz" + "version": "2.3.0", + "from": "@angular/compiler@>=2.2.4 <3.0.0", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-2.3.0.tgz" }, "@angular/core": { - "version": "2.0.0-rc.6", - "from": "@angular/core@2.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-2.0.0-rc.6.tgz" + "version": "2.3.0", + "from": "@angular/core@>=2.2.4 <3.0.0", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-2.3.0.tgz" }, "@angular/forms": { - "version": "2.0.0-rc.6", - "from": "@angular/forms@>=2.0.0-rc.6 <3.0.0", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-2.0.0-rc.6.tgz" + "version": "2.3.0", + "from": "@angular/forms@>=2.2.4 <3.0.0", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-2.3.0.tgz" }, "@angular/http": { - "version": "2.0.0-rc.6", - "from": "@angular/http@2.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@angular/http/-/http-2.0.0-rc.6.tgz" + "version": "2.3.0", + "from": "@angular/http@>=2.2.4 <3.0.0", + "resolved": "https://registry.npmjs.org/@angular/http/-/http-2.3.0.tgz" }, "@angular/platform-browser": { - "version": "2.0.0-rc.6", - "from": "@angular/platform-browser@2.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-2.0.0-rc.6.tgz" + "version": "2.3.0", + "from": "@angular/platform-browser@>=2.2.4 <3.0.0", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-2.3.0.tgz" }, "@angular/platform-browser-dynamic": { - "version": "2.0.0-rc.6", - "from": "@angular/platform-browser-dynamic@2.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-2.0.0-rc.6.tgz" + "version": "2.3.0", + "from": "@angular/platform-browser-dynamic@>=2.2.4 <3.0.0", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-2.3.0.tgz" }, "@angular/platform-server": { - "version": "2.0.0-rc.6", - "from": "@angular/platform-server@2.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-2.0.0-rc.6.tgz" + "version": "2.3.0", + "from": "@angular/platform-server@>=2.2.4 <3.0.0", + "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-2.3.0.tgz", + "dependencies": { + "parse5": { + "version": "2.2.3", + "from": "parse5@>=2.2.1 <3.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-2.2.3.tgz" + } + } + }, + "@angular/router": { + "version": "3.3.0", + "from": "@angular/router@>=3.2.4 <4.0.0", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-3.3.0.tgz" + }, + "@angularclass/conventions-loader": { + "version": "1.0.13", + "from": "@angularclass/conventions-loader@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/@angularclass/conventions-loader/-/conventions-loader-1.0.13.tgz" + }, + "@angularclass/hmr": { + "version": "1.2.2", + "from": "@angularclass/hmr@>=1.2.0 <1.3.0", + "resolved": "https://registry.npmjs.org/@angularclass/hmr/-/hmr-1.2.2.tgz" + }, + "@angularclass/hmr-loader": { + "version": "3.0.2", + "from": "@angularclass/hmr-loader@>=3.0.2 <3.1.0", + "resolved": "https://registry.npmjs.org/@angularclass/hmr-loader/-/hmr-loader-3.0.2.tgz" + }, + "@types/hammerjs": { + "version": "2.0.33", + "from": "@types/hammerjs@>=2.0.33 <3.0.0", + "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.33.tgz", + "dev": true + }, + "@types/jasmine": { + "version": "2.5.38", + "from": "@types/jasmine@>=2.2.34 <3.0.0", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.5.38.tgz", + "dev": true + }, + "@types/node": { + "version": "6.0.51", + "from": "@types/node@>=6.0.38 <7.0.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.51.tgz", + "dev": true + }, + "@types/protractor": { + "version": "1.5.20", + "from": "@types/protractor@>=1.5.20 <2.0.0", + "resolved": "https://registry.npmjs.org/@types/protractor/-/protractor-1.5.20.tgz", + "dev": true + }, + "@types/selenium-webdriver": { + "version": "2.44.29", + "from": "@types/selenium-webdriver@2.44.29", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-2.44.29.tgz", + "dev": true + }, + "@types/source-map": { + "version": "0.1.29", + "from": "@types/source-map@>=0.1.27 <0.2.0", + "resolved": "https://registry.npmjs.org/@types/source-map/-/source-map-0.1.29.tgz", + "dev": true + }, + "@types/uglify-js": { + "version": "2.6.28", + "from": "@types/uglify-js@>=2.0.27 <3.0.0", + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-2.6.28.tgz", + "dev": true + }, + "@types/webpack": { + "version": "1.12.36", + "from": "@types/webpack@>=1.12.34 <2.0.0", + "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-1.12.36.tgz", + "dev": true + }, + "abbrev": { + "version": "1.0.9", + "from": "abbrev@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "dev": true + }, + "accepts": { + "version": "1.1.4", + "from": "accepts@1.1.4", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.1.4.tgz", + "dev": true, + "dependencies": { + "mime-db": { + "version": "1.12.0", + "from": "mime-db@>=1.12.0 <1.13.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.12.0.tgz", + "dev": true + }, + "mime-types": { + "version": "2.0.14", + "from": "mime-types@>=2.0.4 <2.1.0", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.0.14.tgz", + "dev": true + } + } + }, + "acorn": { + "version": "2.7.0", + "from": "acorn@>=2.1.0 <3.0.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz", + "dev": true + }, + "acorn-globals": { + "version": "1.0.9", + "from": "acorn-globals@>=1.0.3 <2.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz", + "dev": true + }, + "adm-zip": { + "version": "0.4.7", + "from": "adm-zip@0.4.7", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz", + "dev": true + }, + "after": { + "version": "0.8.1", + "from": "after@0.8.1", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.1.tgz", + "dev": true + }, + "agent-base": { + "version": "2.0.1", + "from": "agent-base@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.0.1.tgz", + "dev": true, + "dependencies": { + "semver": { + "version": "5.0.3", + "from": "semver@>=5.0.1 <5.1.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", + "dev": true + } + } + }, + "align-text": { + "version": "0.1.4", + "from": "align-text@>=0.1.3 <0.2.0", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "dev": true + }, + "alphanum-sort": { + "version": "1.0.2", + "from": "alphanum-sort@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "dev": true + }, + "amdefine": { + "version": "1.0.1", + "from": "amdefine@>=0.0.4", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "dev": true + }, + "angular2-router-loader": { + "version": "0.3.4", + "from": "angular2-router-loader@>=0.3.2 <0.4.0", + "resolved": "https://registry.npmjs.org/angular2-router-loader/-/angular2-router-loader-0.3.4.tgz", + "dev": true + }, + "angular2-template-loader": { + "version": "0.5.0", + "from": "angular2-template-loader@>=0.5.0 <0.6.0", + "resolved": "https://registry.npmjs.org/angular2-template-loader/-/angular2-template-loader-0.5.0.tgz", + "dev": true + }, + "ansi-regex": { + "version": "2.0.0", + "from": "ansi-regex@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "from": "ansi-styles@>=2.2.1 <3.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "dev": true + }, + "any-promise": { + "version": "1.3.0", + "from": "any-promise@>=1.3.0 <2.0.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "dev": true + }, + "anymatch": { + "version": "1.3.0", + "from": "anymatch@>=1.3.0 <2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz", + "dev": true + }, + "aproba": { + "version": "1.0.4", + "from": "aproba@>=1.0.3 <2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.0.4.tgz", + "dev": true + }, + "are-we-there-yet": { + "version": "1.1.2", + "from": "are-we-there-yet@>=1.1.2 <1.2.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz", + "dev": true + }, + "argparse": { + "version": "1.0.9", + "from": "argparse@>=1.0.7 <2.0.0", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "dev": true + }, + "argv": { + "version": "0.0.2", + "from": "argv@>=0.0.2", + "resolved": "https://registry.npmjs.org/argv/-/argv-0.0.2.tgz", + "dev": true + }, + "arr-diff": { + "version": "2.0.0", + "from": "arr-diff@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "dev": true + }, + "arr-flatten": { + "version": "1.0.1", + "from": "arr-flatten@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.0.1.tgz", + "dev": true + }, + "array-differ": { + "version": "1.0.0", + "from": "array-differ@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", + "dev": true + }, + "array-find-index": { + "version": "1.0.2", + "from": "array-find-index@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "dev": true + }, + "array-flatten": { + "version": "1.1.1", + "from": "array-flatten@1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "dev": true + }, + "array-index": { + "version": "1.0.0", + "from": "array-index@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/array-index/-/array-index-1.0.0.tgz", + "dev": true + }, + "array-slice": { + "version": "0.2.3", + "from": "array-slice@>=0.2.3 <0.3.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "from": "array-union@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "dev": true + }, + "array-uniq": { + "version": "1.0.3", + "from": "array-uniq@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "dev": true + }, + "array-unique": { + "version": "0.2.1", + "from": "array-unique@>=0.2.1 <0.3.0", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "dev": true + }, + "arraybuffer.slice": { + "version": "0.0.6", + "from": "arraybuffer.slice@0.0.6", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "from": "arrify@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "dev": true + }, + "asap": { + "version": "1.0.0", + "from": "asap@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/asap/-/asap-1.0.0.tgz", + "dev": true + }, + "asn1": { + "version": "0.2.3", + "from": "asn1@>=0.2.3 <0.3.0", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "dev": true + }, + "asn1.js": { + "version": "4.9.0", + "from": "asn1.js@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.0.tgz", + "dev": true + }, + "assert": { + "version": "1.4.1", + "from": "assert@>=1.1.1 <2.0.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", + "dev": true + }, + "assert-plus": { + "version": "0.2.0", + "from": "assert-plus@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "dev": true + }, + "assets-webpack-plugin": { + "version": "3.5.0", + "from": "assets-webpack-plugin@>=3.4.0 <4.0.0", + "resolved": "https://registry.npmjs.org/assets-webpack-plugin/-/assets-webpack-plugin-3.5.0.tgz" + }, + "ast-types": { + "version": "0.9.2", + "from": "ast-types@0.9.2", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.9.2.tgz", + "dev": true + }, + "async": { + "version": "0.9.0", + "from": "async@0.9.0", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.0.tgz" + }, + "async-each": { + "version": "1.0.1", + "from": "async-each@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", + "dev": true + }, + "async-foreach": { + "version": "0.1.3", + "from": "async-foreach@>=0.1.3 <0.2.0", + "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "from": "asynckit@>=0.4.0 <0.5.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "dev": true + }, + "autoprefixer": { + "version": "6.5.4", + "from": "autoprefixer@>=6.3.1 <7.0.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.5.4.tgz", + "dev": true + }, + "awesome-typescript-loader": { + "version": "2.2.4", + "from": "awesome-typescript-loader@>=2.2.1 <3.0.0", + "resolved": "https://registry.npmjs.org/awesome-typescript-loader/-/awesome-typescript-loader-2.2.4.tgz", + "dev": true, + "dependencies": { + "colors": { + "version": "1.1.2", + "from": "colors@>=1.1.2 <2.0.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "dev": true + } + } + }, + "aws-sign2": { + "version": "0.6.0", + "from": "aws-sign2@>=0.6.0 <0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "dev": true + }, + "aws4": { + "version": "1.5.0", + "from": "aws4@>=1.2.1 <2.0.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.5.0.tgz", + "dev": true + }, + "babel-code-frame": { + "version": "6.20.0", + "from": "babel-code-frame@>=6.11.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.20.0.tgz", + "dev": true + }, + "backo2": { + "version": "1.0.2", + "from": "backo2@1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "dev": true + }, + "balanced-match": { + "version": "0.4.2", + "from": "balanced-match@>=0.4.1 <0.5.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "dev": true + }, + "base64-arraybuffer": { + "version": "0.1.2", + "from": "base64-arraybuffer@0.1.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.2.tgz", + "dev": true + }, + "base64-js": { + "version": "1.2.0", + "from": "base64-js@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.0.tgz", + "dev": true + }, + "base64id": { + "version": "0.1.0", + "from": "base64id@0.1.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-0.1.0.tgz", + "dev": true + }, + "batch": { + "version": "0.5.3", + "from": "batch@0.5.3", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.5.3.tgz", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.0", + "from": "bcrypt-pbkdf@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz", + "dev": true, + "optional": true + }, + "beeper": { + "version": "1.1.1", + "from": "beeper@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", + "dev": true + }, + "benchmark": { + "version": "1.0.0", + "from": "benchmark@1.0.0", + "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-1.0.0.tgz", + "dev": true + }, + "better-assert": { + "version": "1.0.2", + "from": "better-assert@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "dev": true + }, + "big.js": { + "version": "3.1.3", + "from": "big.js@>=3.1.3 <4.0.0", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.1.3.tgz" + }, + "binary-extensions": { + "version": "1.8.0", + "from": "binary-extensions@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.8.0.tgz", + "dev": true + }, + "bl": { + "version": "1.0.3", + "from": "bl@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.0.3.tgz", + "dev": true, + "dependencies": { + "readable-stream": { + "version": "2.0.6", + "from": "readable-stream@>=2.0.5 <2.1.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "dev": true + } + } + }, + "blob": { + "version": "0.0.4", + "from": "blob@0.0.4", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "dev": true + }, + "block-stream": { + "version": "0.0.9", + "from": "block-stream@*", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "dev": true + }, + "bluebird": { + "version": "2.11.0", + "from": "bluebird@>=2.10.2 <3.0.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", + "dev": true + }, + "bn.js": { + "version": "4.11.6", + "from": "bn.js@>=4.1.1 <5.0.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "dev": true + }, + "body-parser": { + "version": "1.15.2", + "from": "body-parser@>=1.12.4 <2.0.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.15.2.tgz", + "dev": true, + "dependencies": { + "qs": { + "version": "6.2.0", + "from": "qs@6.2.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.0.tgz", + "dev": true + } + } + }, + "boolbase": { + "version": "1.0.0", + "from": "boolbase@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "dev": true + }, + "boom": { + "version": "2.10.1", + "from": "boom@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "dev": true + }, + "bootstrap": { + "version": "4.0.0-alpha.5", + "from": "bootstrap@>=4.0.0-alpha.3 <5.0.0", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.0.0-alpha.5.tgz" + }, + "brace-expansion": { + "version": "1.1.6", + "from": "brace-expansion@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.6.tgz", + "dev": true + }, + "braces": { + "version": "1.8.5", + "from": "braces@>=1.8.2 <2.0.0", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "dev": true + }, + "brorand": { + "version": "1.0.6", + "from": "brorand@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.0.6.tgz", + "dev": true + }, + "browserify-aes": { + "version": "1.0.6", + "from": "browserify-aes@>=1.0.4 <2.0.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.0.6.tgz", + "dev": true + }, + "browserify-cipher": { + "version": "1.0.0", + "from": "browserify-cipher@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.0.tgz", + "dev": true + }, + "browserify-des": { + "version": "1.0.0", + "from": "browserify-des@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.0.tgz", + "dev": true + }, + "browserify-rsa": { + "version": "4.0.1", + "from": "browserify-rsa@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "dev": true + }, + "browserify-sign": { + "version": "4.0.0", + "from": "browserify-sign@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.0.tgz", + "dev": true + }, + "browserify-zlib": { + "version": "0.1.4", + "from": "browserify-zlib@>=0.1.4 <0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", + "dev": true + }, + "browserslist": { + "version": "1.4.0", + "from": "browserslist@>=1.4.0 <1.5.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.4.0.tgz", + "dev": true + }, + "buffer": { + "version": "4.9.1", + "from": "buffer@>=4.3.0 <5.0.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "dev": true + }, + "buffer-shims": { + "version": "1.0.0", + "from": "buffer-shims@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "from": "buffer-xor@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "from": "builtin-modules@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "dev": true + }, + "builtin-status-codes": { + "version": "2.0.0", + "from": "builtin-status-codes@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-2.0.0.tgz", + "dev": true + }, + "bytes": { + "version": "2.4.0", + "from": "bytes@2.4.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", + "dev": true + }, + "callsite": { + "version": "1.0.0", + "from": "callsite@1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "dev": true + }, + "camel-case": { + "version": "3.0.0", + "from": "camel-case@>=3.0.0 <3.1.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "dev": true + }, + "camelcase": { + "version": "1.2.1", + "from": "camelcase@>=1.2.1 <2.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz" + }, + "camelcase-keys": { + "version": "2.1.0", + "from": "camelcase-keys@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "dev": true, + "dependencies": { + "camelcase": { + "version": "2.1.1", + "from": "camelcase@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "dev": true + } + } + }, + "caniuse-db": { + "version": "1.0.30000597", + "from": "caniuse-db@>=1.0.30000597 <2.0.0", + "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000597.tgz", + "dev": true + }, + "caseless": { + "version": "0.11.0", + "from": "caseless@>=0.11.0 <0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", + "dev": true + }, + "center-align": { + "version": "0.1.3", + "from": "center-align@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "from": "chalk@>=1.1.1 <2.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "dev": true + }, + "character-parser": { + "version": "1.2.1", + "from": "character-parser@1.2.1", + "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-1.2.1.tgz", + "dev": true + }, + "charenc": { + "version": "0.0.1", + "from": "charenc@>=0.0.1 <0.1.0", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.1.tgz", + "dev": true + }, + "chokidar": { + "version": "1.6.1", + "from": "chokidar@>=1.4.1 <2.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.6.1.tgz", + "dev": true + }, + "cipher-base": { + "version": "1.0.3", + "from": "cipher-base@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.3.tgz", + "dev": true + }, + "clap": { + "version": "1.1.2", + "from": "clap@>=1.0.9 <2.0.0", + "resolved": "https://registry.npmjs.org/clap/-/clap-1.1.2.tgz", + "dev": true + }, + "clean-css": { + "version": "3.4.22", + "from": "clean-css@>=3.4.0 <3.5.0", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.22.tgz", + "dev": true, + "dependencies": { + "commander": { + "version": "2.8.1", + "from": "commander@>=2.8.0 <2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "dev": true + }, + "source-map": { + "version": "0.4.4", + "from": "source-map@>=0.4.0 <0.5.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "dev": true + } + } + }, + "cliui": { + "version": "2.1.0", + "from": "cliui@>=2.1.0 <3.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "dev": true, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "from": "wordwrap@0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "dev": true + } + } + }, + "clone": { + "version": "1.0.2", + "from": "clone@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz", + "dev": true + }, + "clone-stats": { + "version": "0.0.1", + "from": "clone-stats@>=0.0.1 <0.0.2", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", + "dev": true + }, + "coa": { + "version": "1.0.1", + "from": "coa@>=1.0.1 <1.1.0", + "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.1.tgz", + "dev": true + }, + "code-point-at": { + "version": "1.1.0", + "from": "code-point-at@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "dev": true + }, + "codecov": { + "version": "1.0.1", + "from": "codecov@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/codecov/-/codecov-1.0.1.tgz", + "dev": true + }, + "codelyzer": { + "version": "0.0.28", + "from": "codelyzer@>=0.0.28 <0.1.0", + "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-0.0.28.tgz", + "dev": true + }, + "collections": { + "version": "0.2.2", + "from": "collections@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/collections/-/collections-0.2.2.tgz", + "dev": true + }, + "color": { + "version": "0.11.4", + "from": "color@>=0.11.0 <0.12.0", + "resolved": "https://registry.npmjs.org/color/-/color-0.11.4.tgz", + "dev": true + }, + "color-convert": { + "version": "1.8.2", + "from": "color-convert@>=1.3.0 <2.0.0", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.8.2.tgz", + "dev": true + }, + "color-name": { + "version": "1.1.1", + "from": "color-name@>=1.1.1 <2.0.0", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", + "dev": true + }, + "color-string": { + "version": "0.3.0", + "from": "color-string@>=0.3.0 <0.4.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz", + "dev": true + }, + "colormin": { + "version": "1.1.2", + "from": "colormin@>=1.0.5 <2.0.0", + "resolved": "https://registry.npmjs.org/colormin/-/colormin-1.1.2.tgz", + "dev": true + }, + "colors": { + "version": "1.0.3", + "from": "colors@1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz" + }, + "combine-lists": { + "version": "1.0.1", + "from": "combine-lists@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/combine-lists/-/combine-lists-1.0.1.tgz", + "dev": true + }, + "combined-stream": { + "version": "1.0.5", + "from": "combined-stream@>=1.0.5 <1.1.0", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "dev": true + }, + "commander": { + "version": "2.9.0", + "from": "commander@>=2.9.0 <3.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "dev": true + }, + "component-bind": { + "version": "1.0.0", + "from": "component-bind@1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "dev": true + }, + "component-emitter": { + "version": "1.1.2", + "from": "component-emitter@1.1.2", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz", + "dev": true + }, + "component-inherit": { + "version": "0.0.3", + "from": "component-inherit@0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "dev": true + }, + "compressible": { + "version": "2.0.9", + "from": "compressible@>=2.0.8 <2.1.0", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.9.tgz", + "dev": true + }, + "compression": { + "version": "1.6.2", + "from": "compression@>=1.5.2 <2.0.0", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.6.2.tgz", + "dev": true, + "dependencies": { + "accepts": { + "version": "1.3.3", + "from": "accepts@>=1.3.3 <1.4.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", + "dev": true + }, + "bytes": { + "version": "2.3.0", + "from": "bytes@2.3.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.3.0.tgz", + "dev": true + }, + "negotiator": { + "version": "0.6.1", + "from": "negotiator@0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "dev": true + } + } + }, + "concat-map": { + "version": "0.0.1", + "from": "concat-map@0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "dev": true + }, + "concat-stream": { + "version": "1.5.0", + "from": "concat-stream@1.5.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz", + "dev": true, + "dependencies": { + "readable-stream": { + "version": "2.0.6", + "from": "readable-stream@>=2.0.0 <2.1.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "dev": true + } + } + }, + "connect": { + "version": "3.5.0", + "from": "connect@>=3.3.5 <4.0.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.5.0.tgz", + "dev": true + }, + "connect-history-api-fallback": { + "version": "1.3.0", + "from": "connect-history-api-fallback@>=1.3.0 <2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.3.0.tgz", + "dev": true + }, + "console-browserify": { + "version": "1.1.0", + "from": "console-browserify@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "from": "console-control-strings@>=1.1.0 <1.2.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "dev": true + }, + "constantinople": { + "version": "3.0.2", + "from": "constantinople@>=3.0.1 <3.1.0", + "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-3.0.2.tgz", + "dev": true + }, + "constants-browserify": { + "version": "1.0.0", + "from": "constants-browserify@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "dev": true + }, + "content-disposition": { + "version": "0.5.1", + "from": "content-disposition@0.5.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.1.tgz", + "dev": true + }, + "content-type": { + "version": "1.0.2", + "from": "content-type@>=1.0.2 <1.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz", + "dev": true + }, + "cookie": { + "version": "0.3.1", + "from": "cookie@0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "from": "cookie-signature@1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "dev": true + }, + "copy-webpack-plugin": { + "version": "3.0.1", + "from": "copy-webpack-plugin@>=3.0.1 <4.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-3.0.1.tgz", + "dev": true + }, + "core-js": { + "version": "2.4.1", + "from": "core-js@>=2.4.1 <3.0.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz" + }, + "core-util-is": { + "version": "1.0.2", + "from": "core-util-is@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "dev": true + }, + "corser": { + "version": "2.0.1", + "from": "corser@>=2.0.0 <2.1.0", + "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz" + }, + "create-ecdh": { + "version": "4.0.0", + "from": "create-ecdh@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz", + "dev": true + }, + "create-hash": { + "version": "1.1.2", + "from": "create-hash@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.2.tgz", + "dev": true + }, + "create-hmac": { + "version": "1.1.4", + "from": "create-hmac@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.4.tgz", + "dev": true + }, + "cross-spawn": { + "version": "3.0.1", + "from": "cross-spawn@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", + "dev": true, + "dependencies": { + "lru-cache": { + "version": "4.0.2", + "from": "lru-cache@>=4.0.1 <5.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz", + "dev": true + } + } + }, + "crypt": { + "version": "0.0.1", + "from": "crypt@>=0.0.1 <0.1.0", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.1.tgz", + "dev": true + }, + "cryptiles": { + "version": "2.0.5", + "from": "cryptiles@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "dev": true + }, + "crypto-browserify": { + "version": "3.11.0", + "from": "crypto-browserify@>=3.11.0 <4.0.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.11.0.tgz", + "dev": true + }, + "css": { + "version": "1.0.8", + "from": "css@>=1.0.8 <1.1.0", + "resolved": "https://registry.npmjs.org/css/-/css-1.0.8.tgz", + "dev": true + }, + "css-color-names": { + "version": "0.0.4", + "from": "css-color-names@0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "dev": true + }, + "css-loader": { + "version": "0.25.0", + "from": "css-loader@>=0.25.0 <0.26.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.25.0.tgz", + "dev": true + }, + "css-parse": { + "version": "1.0.4", + "from": "css-parse@1.0.4", + "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.0.4.tgz", + "dev": true + }, + "css-select": { + "version": "1.2.0", + "from": "css-select@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "dev": true + }, + "css-selector-tokenizer": { + "version": "0.6.0", + "from": "css-selector-tokenizer@>=0.6.0 <0.7.0", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.6.0.tgz", + "dev": true + }, + "css-stringify": { + "version": "1.0.5", + "from": "css-stringify@1.0.5", + "resolved": "https://registry.npmjs.org/css-stringify/-/css-stringify-1.0.5.tgz", + "dev": true + }, + "css-to-string-loader": { + "version": "0.1.2", + "from": "css-to-string-loader@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/css-to-string-loader/-/css-to-string-loader-0.1.2.tgz", + "dev": true + }, + "css-what": { + "version": "2.1.0", + "from": "css-what@>=2.1.0 <2.2.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz", + "dev": true + }, + "cssesc": { + "version": "0.1.0", + "from": "cssesc@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz", + "dev": true + }, + "cssnano": { + "version": "3.9.1", + "from": "cssnano@>=2.6.1 <4.0.0", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-3.9.1.tgz", + "dev": true + }, + "csso": { + "version": "2.2.1", + "from": "csso@>=2.2.1 <2.3.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-2.2.1.tgz", + "dev": true + }, + "currently-unhandled": { + "version": "0.4.1", + "from": "currently-unhandled@>=0.4.1 <0.5.0", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "dev": true + }, + "custom-event": { + "version": "1.0.1", + "from": "custom-event@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "dev": true + }, + "d": { + "version": "0.1.1", + "from": "d@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/d/-/d-0.1.1.tgz", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "from": "dashdash@>=1.12.0 <2.0.0", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "dev": true, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "from": "assert-plus@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "dev": true + } + } + }, + "date-now": { + "version": "0.1.4", + "from": "date-now@>=0.1.4 <0.2.0", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "dev": true + }, + "dateformat": { + "version": "1.0.12", + "from": "dateformat@>=1.0.6 <2.0.0", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", + "dev": true + }, + "debug": { + "version": "2.2.0", + "from": "debug@>=2.2.0 <2.3.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "dev": true + }, + "decamelize": { + "version": "1.2.0", + "from": "decamelize@>=1.1.2 <2.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "from": "deep-is@>=0.1.3 <0.2.0", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "dev": true + }, + "defined": { + "version": "1.0.0", + "from": "defined@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "from": "delayed-stream@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "from": "delegates@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "dev": true + }, + "depd": { + "version": "1.1.0", + "from": "depd@>=1.1.0 <1.2.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz", + "dev": true + }, + "des.js": { + "version": "1.0.0", + "from": "des.js@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", + "dev": true + }, + "destroy": { + "version": "1.0.4", + "from": "destroy@>=1.0.4 <1.1.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "dev": true + }, + "di": { + "version": "0.0.1", + "from": "di@>=0.0.1 <0.0.2", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "dev": true + }, + "diff": { + "version": "3.1.0", + "from": "diff@>=3.1.0 <4.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.1.0.tgz", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.2", + "from": "diffie-hellman@>=5.0.0 <6.0.0", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz", + "dev": true + }, + "dom-converter": { + "version": "0.1.4", + "from": "dom-converter@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.1.4.tgz", + "dev": true, + "dependencies": { + "utila": { + "version": "0.3.3", + "from": "utila@>=0.3.0 <0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.3.3.tgz", + "dev": true + } + } + }, + "dom-serialize": { + "version": "2.2.1", + "from": "dom-serialize@>=2.2.0 <3.0.0", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "dev": true + }, + "dom-serializer": { + "version": "0.1.0", + "from": "dom-serializer@>=0.0.0 <1.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", + "dev": true, + "dependencies": { + "domelementtype": { + "version": "1.1.3", + "from": "domelementtype@>=1.1.1 <1.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "dev": true + } + } + }, + "domain-browser": { + "version": "1.1.7", + "from": "domain-browser@>=1.1.1 <2.0.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz", + "dev": true + }, + "domelementtype": { + "version": "1.3.0", + "from": "domelementtype@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", + "dev": true + }, + "domhandler": { + "version": "2.1.0", + "from": "domhandler@>=2.1.0 <2.2.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.1.0.tgz", + "dev": true + }, + "domutils": { + "version": "1.5.1", + "from": "domutils@1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "dev": true + }, + "duplexer2": { + "version": "0.0.2", + "from": "duplexer2@0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "dev": true, + "dependencies": { + "isarray": { + "version": "0.0.1", + "from": "isarray@0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "from": "readable-stream@>=1.1.9 <1.2.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "dev": true + } + } + }, + "ecc-jsbn": { + "version": "0.1.1", + "from": "ecc-jsbn@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "dev": true, + "optional": true + }, + "ecstatic": { + "version": "1.4.1", + "from": "ecstatic@>=1.4.0 <2.0.0", + "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-1.4.1.tgz", + "dependencies": { + "minimist": { + "version": "1.2.0", + "from": "minimist@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz" + } + } + }, + "ee-first": { + "version": "1.1.1", + "from": "ee-first@1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "dev": true + }, + "elliptic": { + "version": "6.3.2", + "from": "elliptic@>=6.0.0 <7.0.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.3.2.tgz", + "dev": true + }, + "emojis-list": { + "version": "2.1.0", + "from": "emojis-list@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz" + }, + "encodeurl": { + "version": "1.0.1", + "from": "encodeurl@>=1.0.1 <1.1.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz", + "dev": true + }, + "engine.io": { + "version": "1.6.10", + "from": "engine.io@1.6.10", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.6.10.tgz", + "dev": true + }, + "engine.io-client": { + "version": "1.6.9", + "from": "engine.io-client@1.6.9", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.6.9.tgz", + "dev": true + }, + "engine.io-parser": { + "version": "1.2.4", + "from": "engine.io-parser@1.2.4", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.2.4.tgz", + "dev": true, + "dependencies": { + "has-binary": { + "version": "0.1.6", + "from": "has-binary@0.1.6", + "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.6.tgz", + "dev": true + }, + "isarray": { + "version": "0.0.1", + "from": "isarray@0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "dev": true + } + } + }, + "enhanced-resolve": { + "version": "2.3.0", + "from": "enhanced-resolve@>=2.2.2 <3.0.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-2.3.0.tgz", + "dev": true, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "from": "graceful-fs@>=4.1.2 <5.0.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "dev": true + } + } + }, + "ent": { + "version": "2.2.0", + "from": "ent@>=2.2.0 <2.3.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "dev": true + }, + "entities": { + "version": "1.1.1", + "from": "entities@>=1.1.1 <1.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "dev": true + }, + "errno": { + "version": "0.1.4", + "from": "errno@>=0.1.3 <0.2.0", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz", + "dev": true + }, + "error-ex": { + "version": "1.3.0", + "from": "error-ex@>=1.2.0 <2.0.0", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.0.tgz", + "dev": true + }, + "es5-ext": { + "version": "0.10.12", + "from": "es5-ext@>=0.10.11 <0.11.0", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.12.tgz", + "dev": true + }, + "es6-iterator": { + "version": "2.0.0", + "from": "es6-iterator@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.0.tgz", + "dev": true + }, + "es6-promise": { + "version": "4.0.5", + "from": "es6-promise@>=4.0.3 <4.1.0", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.0.5.tgz", + "dev": true + }, + "es6-symbol": { + "version": "3.1.0", + "from": "es6-symbol@>=3.0.2 <4.0.0", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.0.tgz", + "dev": true + }, + "es6-templates": { + "version": "0.2.3", + "from": "es6-templates@>=0.2.2 <0.3.0", + "resolved": "https://registry.npmjs.org/es6-templates/-/es6-templates-0.2.3.tgz", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "from": "escape-html@>=1.0.3 <1.1.0", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "from": "escape-string-regexp@>=1.0.3 <2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + }, + "escodegen": { + "version": "1.8.1", + "from": "escodegen@>=1.8.0 <1.9.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "dev": true, + "dependencies": { + "source-map": { + "version": "0.2.0", + "from": "source-map@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "dev": true, + "optional": true + } + } + }, + "esprima": { + "version": "2.7.3", + "from": "esprima@>=2.6.0 <3.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "dev": true + }, + "estraverse": { + "version": "1.9.3", + "from": "estraverse@>=1.9.1 <2.0.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "from": "esutils@>=2.0.2 <3.0.0", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "dev": true + }, + "etag": { + "version": "1.7.0", + "from": "etag@>=1.7.0 <1.8.0", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.7.0.tgz", + "dev": true + }, + "eventemitter3": { + "version": "1.2.0", + "from": "eventemitter3@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz" + }, + "events": { + "version": "1.1.1", + "from": "events@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "dev": true + }, + "eventsource": { + "version": "0.1.6", + "from": "eventsource@>=0.1.6 <0.2.0", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-0.1.6.tgz", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.0", + "from": "evp_bytestokey@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz", + "dev": true + }, + "execSync": { + "version": "1.0.2", + "from": "execSync@1.0.2", + "resolved": "https://registry.npmjs.org/execSync/-/execSync-1.0.2.tgz", + "dev": true + }, + "exit": { + "version": "0.1.2", + "from": "exit@>=0.1.2 <0.2.0", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "dev": true + }, + "expand-braces": { + "version": "0.1.2", + "from": "expand-braces@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz", + "dev": true, + "dependencies": { + "braces": { + "version": "0.1.5", + "from": "braces@>=0.1.2 <0.2.0", + "resolved": "https://registry.npmjs.org/braces/-/braces-0.1.5.tgz", + "dev": true + }, + "expand-range": { + "version": "0.1.1", + "from": "expand-range@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz", + "dev": true + }, + "is-number": { + "version": "0.1.1", + "from": "is-number@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-0.1.1.tgz", + "dev": true + }, + "repeat-string": { + "version": "0.2.2", + "from": "repeat-string@>=0.2.2 <0.3.0", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-0.2.2.tgz", + "dev": true + } + } + }, + "expand-brackets": { + "version": "0.1.5", + "from": "expand-brackets@>=0.1.4 <0.2.0", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "dev": true + }, + "expand-range": { + "version": "1.8.2", + "from": "expand-range@>=1.8.1 <2.0.0", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "dev": true + }, + "exports-loader": { + "version": "0.6.3", + "from": "exports-loader@>=0.6.3 <0.7.0", + "resolved": "https://registry.npmjs.org/exports-loader/-/exports-loader-0.6.3.tgz", + "dev": true, + "dependencies": { + "source-map": { + "version": "0.1.43", + "from": "source-map@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "dev": true + } + } + }, + "expose-loader": { + "version": "0.7.1", + "from": "expose-loader@>=0.7.1 <0.8.0", + "resolved": "https://registry.npmjs.org/expose-loader/-/expose-loader-0.7.1.tgz", + "dev": true + }, + "express": { + "version": "4.14.0", + "from": "express@>=4.13.3 <5.0.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.14.0.tgz", + "dev": true, + "dependencies": { + "accepts": { + "version": "1.3.3", + "from": "accepts@>=1.3.3 <1.4.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", + "dev": true + }, + "negotiator": { + "version": "0.6.1", + "from": "negotiator@0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "dev": true + }, + "qs": { + "version": "6.2.0", + "from": "qs@6.2.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.0.tgz", + "dev": true + } + } + }, + "extend": { + "version": "3.0.0", + "from": "extend@>=3.0.0 <3.1.0", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz", + "dev": true + }, + "extglob": { + "version": "0.3.2", + "from": "extglob@>=0.3.1 <0.4.0", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "dev": true + }, + "extract-text-webpack-plugin": { + "version": "2.0.0-beta.4", + "from": "extract-text-webpack-plugin@>=2.0.0-beta.4 <3.0.0", + "resolved": "https://registry.npmjs.org/extract-text-webpack-plugin/-/extract-text-webpack-plugin-2.0.0-beta.4.tgz", + "dev": true, + "dependencies": { + "async": { + "version": "1.5.2", + "from": "async@>=1.5.0 <2.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "dev": true + } + } + }, + "extract-zip": { + "version": "1.5.0", + "from": "extract-zip@>=1.5.0 <1.6.0", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.5.0.tgz", + "dev": true, + "dependencies": { + "debug": { + "version": "0.7.4", + "from": "debug@0.7.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", + "dev": true + }, + "mkdirp": { + "version": "0.5.0", + "from": "mkdirp@0.5.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", + "dev": true + } + } + }, + "extsprintf": { + "version": "1.0.2", + "from": "extsprintf@1.0.2", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", + "dev": true + }, + "fancy-log": { + "version": "1.2.0", + "from": "fancy-log@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.2.0.tgz", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.5", + "from": "fast-levenshtein@>=2.0.4 <2.1.0", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.5.tgz", + "dev": true + }, + "fastparse": { + "version": "1.1.1", + "from": "fastparse@>=1.1.1 <2.0.0", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz", + "dev": true + }, + "faye-websocket": { + "version": "0.10.0", + "from": "faye-websocket@>=0.10.0 <0.11.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "dev": true + }, + "fd-slicer": { + "version": "1.0.1", + "from": "fd-slicer@>=1.0.1 <1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", + "dev": true + }, + "file-loader": { + "version": "0.9.0", + "from": "file-loader@>=0.9.0 <0.10.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-0.9.0.tgz", + "dev": true + }, + "filename-regex": { + "version": "2.0.0", + "from": "filename-regex@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.0.tgz", + "dev": true + }, + "fill-range": { + "version": "2.2.3", + "from": "fill-range@>=2.1.0 <3.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", + "dev": true + }, + "finalhandler": { + "version": "0.5.0", + "from": "finalhandler@0.5.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.5.0.tgz", + "dev": true + }, + "find-up": { + "version": "1.1.2", + "from": "find-up@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "dev": true + }, + "findup-sync": { + "version": "0.3.0", + "from": "findup-sync@>=0.3.0 <0.4.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", + "dev": true, + "dependencies": { + "glob": { + "version": "5.0.15", + "from": "glob@>=5.0.0 <5.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "dev": true + } + } + }, + "flatten": { + "version": "1.0.2", + "from": "flatten@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", + "dev": true + }, + "for-in": { + "version": "0.1.6", + "from": "for-in@>=0.1.5 <0.2.0", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.6.tgz", + "dev": true + }, + "for-own": { + "version": "0.1.4", + "from": "for-own@>=0.1.4 <0.2.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.4.tgz", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "from": "forever-agent@>=0.6.1 <0.7.0", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "dev": true + }, + "form-data": { + "version": "2.1.2", + "from": "form-data@>=2.1.1 <2.2.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.2.tgz", + "dev": true + }, + "forwarded": { + "version": "0.1.0", + "from": "forwarded@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz", + "dev": true + }, + "fresh": { + "version": "0.3.0", + "from": "fresh@0.3.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz", + "dev": true + }, + "fs-access": { + "version": "1.0.1", + "from": "fs-access@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", + "dev": true + }, + "fs-extra": { + "version": "0.26.7", + "from": "fs-extra@>=0.26.4 <0.27.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz", + "dev": true, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "from": "graceful-fs@>=4.1.2 <5.0.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "dev": true + } + } + }, + "fs.realpath": { + "version": "1.0.0", + "from": "fs.realpath@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "dev": true + }, + "fsevents": { + "version": "1.0.15", + "from": "fsevents@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.0.15.tgz", + "dev": true, + "optional": true, + "dependencies": { + "abbrev": { + "version": "1.0.9", + "from": "abbrev@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.0.0", + "from": "ansi-regex@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "from": "ansi-styles@>=2.2.1 <3.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.0.4", + "from": "aproba@>=1.0.3 <2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.0.4.tgz", + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.2", + "from": "are-we-there-yet@>=1.1.2 <1.2.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz", + "dev": true, + "optional": true + }, + "asn1": { + "version": "0.2.3", + "from": "asn1@>=0.2.3 <0.3.0", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "dev": true, + "optional": true + }, + "assert-plus": { + "version": "0.2.0", + "from": "assert-plus@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "dev": true, + "optional": true + }, + "async": { + "version": "1.5.2", + "from": "async@>=1.5.2 <2.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "dev": true, + "optional": true + }, + "aws-sign2": { + "version": "0.6.0", + "from": "aws-sign2@>=0.6.0 <0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "dev": true, + "optional": true + }, + "aws4": { + "version": "1.4.1", + "from": "aws4@>=1.2.1 <2.0.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.4.1.tgz", + "dev": true, + "optional": true + }, + "balanced-match": { + "version": "0.4.2", + "from": "balanced-match@>=0.4.1 <0.5.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "dev": true + }, + "bl": { + "version": "1.1.2", + "from": "bl@>=1.1.2 <1.2.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz", + "dev": true, + "optional": true, + "dependencies": { + "readable-stream": { + "version": "2.0.6", + "from": "readable-stream@>=2.0.5 <2.1.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "dev": true, + "optional": true + } + } + }, + "block-stream": { + "version": "0.0.9", + "from": "block-stream@*", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "dev": true + }, + "boom": { + "version": "2.10.1", + "from": "boom@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "dev": true + }, + "brace-expansion": { + "version": "1.1.5", + "from": "brace-expansion@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.5.tgz", + "dev": true + }, + "buffer-shims": { + "version": "1.0.0", + "from": "buffer-shims@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", + "dev": true + }, + "caseless": { + "version": "0.11.0", + "from": "caseless@>=0.11.0 <0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", + "dev": true, + "optional": true + }, + "chalk": { + "version": "1.1.3", + "from": "chalk@>=1.1.1 <2.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.0.0", + "from": "code-point-at@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.0.0.tgz", + "dev": true + }, + "combined-stream": { + "version": "1.0.5", + "from": "combined-stream@>=1.0.5 <1.1.0", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "dev": true + }, + "commander": { + "version": "2.9.0", + "from": "commander@>=2.9.0 <3.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "from": "concat-map@0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "from": "console-control-strings@>=1.1.0 <1.2.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "from": "core-util-is@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "dev": true + }, + "cryptiles": { + "version": "2.0.5", + "from": "cryptiles@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "dev": true, + "optional": true + }, + "dashdash": { + "version": "1.14.0", + "from": "dashdash@>=1.12.0 <2.0.0", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.0.tgz", + "dev": true, + "optional": true, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "from": "assert-plus@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "dev": true, + "optional": true + } + } + }, + "debug": { + "version": "2.2.0", + "from": "debug@>=2.2.0 <2.3.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "dev": true, + "optional": true + }, + "deep-extend": { + "version": "0.4.1", + "from": "deep-extend@>=0.4.0 <0.5.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.1.tgz", + "dev": true, + "optional": true + }, + "delayed-stream": { + "version": "1.0.0", + "from": "delayed-stream@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "from": "delegates@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "dev": true, + "optional": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "from": "ecc-jsbn@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "dev": true, + "optional": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "from": "escape-string-regexp@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "dev": true, + "optional": true + }, + "extend": { + "version": "3.0.0", + "from": "extend@>=3.0.0 <3.1.0", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz", + "dev": true, + "optional": true + }, + "extsprintf": { + "version": "1.0.2", + "from": "extsprintf@1.0.2", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "from": "forever-agent@>=0.6.1 <0.7.0", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "dev": true, + "optional": true + }, + "form-data": { + "version": "1.0.0-rc4", + "from": "form-data@>=1.0.0-rc4 <1.1.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.0-rc4.tgz", + "dev": true, + "optional": true + }, + "fs.realpath": { + "version": "1.0.0", + "from": "fs.realpath@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "dev": true + }, + "fstream": { + "version": "1.0.10", + "from": "fstream@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.10.tgz", + "dev": true + }, + "fstream-ignore": { + "version": "1.0.5", + "from": "fstream-ignore@>=1.0.5 <1.1.0", + "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz", + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.6.0", + "from": "gauge@>=2.6.0 <2.7.0", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.6.0.tgz", + "dev": true, + "optional": true + }, + "generate-function": { + "version": "2.0.0", + "from": "generate-function@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", + "dev": true, + "optional": true + }, + "generate-object-property": { + "version": "1.2.0", + "from": "generate-object-property@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "dev": true, + "optional": true + }, + "getpass": { + "version": "0.1.6", + "from": "getpass@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz", + "dev": true, + "optional": true, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "from": "assert-plus@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "dev": true, + "optional": true + } + } + }, + "glob": { + "version": "7.0.5", + "from": "glob@>=7.0.5 <8.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.5.tgz", + "dev": true + }, + "graceful-fs": { + "version": "4.1.4", + "from": "graceful-fs@>=4.1.2 <5.0.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.4.tgz", + "dev": true + }, + "graceful-readlink": { + "version": "1.0.1", + "from": "graceful-readlink@>=1.0.0", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "dev": true, + "optional": true + }, + "har-validator": { + "version": "2.0.6", + "from": "har-validator@>=2.0.6 <2.1.0", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", + "dev": true, + "optional": true + }, + "has-ansi": { + "version": "2.0.0", + "from": "has-ansi@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "dev": true, + "optional": true + }, + "has-color": { + "version": "0.1.7", + "from": "has-color@>=0.1.7 <0.2.0", + "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", + "dev": true, + "optional": true + }, + "has-unicode": { + "version": "2.0.1", + "from": "has-unicode@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "dev": true, + "optional": true + }, + "hawk": { + "version": "3.1.3", + "from": "hawk@>=3.1.3 <3.2.0", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "dev": true, + "optional": true + }, + "hoek": { + "version": "2.16.3", + "from": "hoek@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "dev": true + }, + "http-signature": { + "version": "1.1.1", + "from": "http-signature@>=1.1.0 <1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "dev": true, + "optional": true + }, + "inflight": { + "version": "1.0.5", + "from": "inflight@>=1.0.4 <2.0.0", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz", + "dev": true + }, + "inherits": { + "version": "2.0.1", + "from": "inherits@>=2.0.1 <2.1.0", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "dev": true + }, + "ini": { + "version": "1.3.4", + "from": "ini@>=1.3.0 <1.4.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "from": "is-fullwidth-code-point@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "dev": true + }, + "is-my-json-valid": { + "version": "2.13.1", + "from": "is-my-json-valid@>=2.12.4 <3.0.0", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.13.1.tgz", + "dev": true, + "optional": true + }, + "is-property": { + "version": "1.0.2", + "from": "is-property@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "dev": true, + "optional": true + }, + "is-typedarray": { + "version": "1.0.0", + "from": "is-typedarray@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "dev": true, + "optional": true + }, + "isarray": { + "version": "1.0.0", + "from": "isarray@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "from": "isstream@>=0.1.2 <0.2.0", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "dev": true, + "optional": true + }, + "jodid25519": { + "version": "1.0.2", + "from": "jodid25519@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz", + "dev": true, + "optional": true + }, + "jsbn": { + "version": "0.1.0", + "from": "jsbn@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz", + "dev": true, + "optional": true + }, + "json-schema": { + "version": "0.2.2", + "from": "json-schema@0.2.2", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.2.tgz", + "dev": true, + "optional": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "from": "json-stringify-safe@>=5.0.1 <5.1.0", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "dev": true, + "optional": true + }, + "jsonpointer": { + "version": "2.0.0", + "from": "jsonpointer@2.0.0", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz", + "dev": true, + "optional": true + }, + "jsprim": { + "version": "1.3.0", + "from": "jsprim@>=1.2.2 <2.0.0", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.3.0.tgz", + "dev": true, + "optional": true + }, + "mime-db": { + "version": "1.23.0", + "from": "mime-db@>=1.23.0 <1.24.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.23.0.tgz", + "dev": true + }, + "mime-types": { + "version": "2.1.11", + "from": "mime-types@>=2.1.7 <2.2.0", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.11.tgz", + "dev": true + }, + "minimatch": { + "version": "3.0.2", + "from": "minimatch@>=3.0.2 <4.0.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.2.tgz", + "dev": true + }, + "minimist": { + "version": "0.0.8", + "from": "minimist@0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "from": "mkdirp@>=0.5.0 <0.6.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "dev": true + }, + "ms": { + "version": "0.7.1", + "from": "ms@0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "dev": true, + "optional": true + }, + "node-pre-gyp": { + "version": "0.6.29", + "from": "node-pre-gyp@>=0.6.29 <0.7.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.6.29.tgz", + "dev": true, + "optional": true + }, + "node-uuid": { + "version": "1.4.7", + "from": "node-uuid@>=1.4.7 <1.5.0", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz", + "dev": true, + "optional": true + }, + "nopt": { + "version": "3.0.6", + "from": "nopt@>=3.0.1 <3.1.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "dev": true, + "optional": true + }, + "npmlog": { + "version": "3.1.2", + "from": "npmlog@>=3.1.2 <3.2.0", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-3.1.2.tgz", + "dev": true, + "optional": true + }, + "number-is-nan": { + "version": "1.0.0", + "from": "number-is-nan@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz", + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "from": "oauth-sign@>=0.8.1 <0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.0", + "from": "object-assign@>=4.1.0 <5.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", + "dev": true, + "optional": true + }, + "once": { + "version": "1.3.3", + "from": "once@>=1.3.0 <2.0.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.0", + "from": "path-is-absolute@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "from": "pinkie@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "dev": true, + "optional": true + }, + "pinkie-promise": { + "version": "2.0.1", + "from": "pinkie-promise@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "1.0.7", + "from": "process-nextick-args@>=1.0.6 <1.1.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "dev": true + }, + "qs": { + "version": "6.2.0", + "from": "qs@>=6.2.0 <6.3.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.0.tgz", + "dev": true, + "optional": true + }, + "rc": { + "version": "1.1.6", + "from": "rc@>=1.1.0 <1.2.0", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.1.6.tgz", + "dev": true, + "optional": true, + "dependencies": { + "minimist": { + "version": "1.2.0", + "from": "minimist@>=1.2.0 <2.0.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.1.4", + "from": "readable-stream@>=2.0.0 <3.0.0||>=1.1.13 <2.0.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.4.tgz", + "dev": true + }, + "request": { + "version": "2.73.0", + "from": "request@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.73.0.tgz", + "dev": true, + "optional": true + }, + "rimraf": { + "version": "2.5.3", + "from": "rimraf@>=2.5.0 <2.6.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.3.tgz", + "dev": true + }, + "semver": { + "version": "5.2.0", + "from": "semver@>=5.2.0 <5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.2.0.tgz", + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "from": "set-blocking@>=2.0.0 <2.1.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.0", + "from": "signal-exit@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.0.tgz", + "dev": true, + "optional": true + }, + "sntp": { + "version": "1.0.9", + "from": "sntp@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "dev": true, + "optional": true + }, + "sshpk": { + "version": "1.8.3", + "from": "sshpk@>=1.7.0 <2.0.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.8.3.tgz", + "dev": true, + "optional": true, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "from": "assert-plus@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "dev": true, + "optional": true + } + } + }, + "string_decoder": { + "version": "0.10.31", + "from": "string_decoder@>=0.10.0 <0.11.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "dev": true + }, + "string-width": { + "version": "1.0.1", + "from": "string-width@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.1.tgz", + "dev": true + }, + "stringstream": { + "version": "0.0.5", + "from": "stringstream@>=0.0.4 <0.1.0", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "dev": true, + "optional": true + }, + "strip-ansi": { + "version": "3.0.1", + "from": "strip-ansi@>=3.0.1 <4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "dev": true + }, + "strip-json-comments": { + "version": "1.0.4", + "from": "strip-json-comments@>=1.0.4 <1.1.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "dev": true, + "optional": true + }, + "supports-color": { + "version": "2.0.0", + "from": "supports-color@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "dev": true, + "optional": true + }, + "tar": { + "version": "2.2.1", + "from": "tar@>=2.2.0 <2.3.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "dev": true + }, + "tar-pack": { + "version": "3.1.4", + "from": "tar-pack@>=3.1.0 <3.2.0", + "resolved": "https://registry.npmjs.org/tar-pack/-/tar-pack-3.1.4.tgz", + "dev": true, + "optional": true + }, + "tough-cookie": { + "version": "2.2.2", + "from": "tough-cookie@>=2.2.0 <2.3.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.2.tgz", + "dev": true, + "optional": true + }, + "tunnel-agent": { + "version": "0.4.3", + "from": "tunnel-agent@>=0.4.1 <0.5.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "dev": true, + "optional": true + }, + "tweetnacl": { + "version": "0.13.3", + "from": "tweetnacl@>=0.13.0 <0.14.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.13.3.tgz", + "dev": true, + "optional": true + }, + "uid-number": { + "version": "0.0.6", + "from": "uid-number@>=0.0.6 <0.1.0", + "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", + "dev": true, + "optional": true + }, + "util-deprecate": { + "version": "1.0.2", + "from": "util-deprecate@>=1.0.1 <1.1.0", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "dev": true + }, + "verror": { + "version": "1.3.6", + "from": "verror@1.3.6", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.0", + "from": "wide-align@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.0.tgz", + "dev": true, + "optional": true + }, + "wrappy": { + "version": "1.0.2", + "from": "wrappy@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "dev": true + }, + "xtend": { + "version": "4.0.1", + "from": "xtend@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "dev": true, + "optional": true + } + } + }, + "fstream": { + "version": "1.0.10", + "from": "fstream@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.10.tgz", + "dev": true, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "from": "graceful-fs@>=4.1.2 <5.0.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "dev": true + } + } + }, + "function-bind": { + "version": "1.1.0", + "from": "function-bind@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.0.tgz", + "dev": true + }, + "gauge": { + "version": "2.6.0", + "from": "gauge@>=2.6.0 <2.7.0", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.6.0.tgz", + "dev": true + }, + "gaze": { + "version": "1.1.2", + "from": "gaze@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.2.tgz", + "dev": true + }, + "generate-function": { + "version": "2.0.0", + "from": "generate-function@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", + "dev": true + }, + "generate-object-property": { + "version": "1.2.0", + "from": "generate-object-property@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "dev": true + }, + "get-caller-file": { + "version": "1.0.2", + "from": "get-caller-file@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", + "dev": true + }, + "get-stdin": { + "version": "4.0.1", + "from": "get-stdin@>=4.0.1 <5.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "dev": true + }, + "getpass": { + "version": "0.1.6", + "from": "getpass@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz", + "dev": true, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "from": "assert-plus@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "dev": true + } + } + }, + "gh-pages": { + "version": "0.11.0", + "from": "gh-pages@>=0.11.0 <0.12.0", + "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-0.11.0.tgz", + "dev": true, + "dependencies": { + "async": { + "version": "1.5.2", + "from": "async@1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "dev": true + }, + "graceful-fs": { + "version": "4.1.2", + "from": "graceful-fs@4.1.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.2.tgz", + "dev": true + } + } + }, + "glob": { + "version": "6.0.4", + "from": "glob@>=6.0.4 <7.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "dev": true + }, + "glob-base": { + "version": "0.3.0", + "from": "glob-base@>=0.3.0 <0.4.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "dev": true + }, + "glob-parent": { + "version": "2.0.0", + "from": "glob-parent@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "dev": true + }, + "globby": { + "version": "4.1.0", + "from": "globby@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-4.1.0.tgz", + "dev": true + }, + "globule": { + "version": "1.1.0", + "from": "globule@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.1.0.tgz", + "dev": true, + "dependencies": { + "glob": { + "version": "7.1.1", + "from": "glob@>=7.1.1 <7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "dev": true + }, + "lodash": { + "version": "4.16.6", + "from": "lodash@>=4.16.4 <4.17.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.6.tgz", + "dev": true + } + } + }, + "glogg": { + "version": "1.0.0", + "from": "glogg@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.0.tgz", + "dev": true + }, + "graceful-fs": { + "version": "1.2.3", + "from": "graceful-fs@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", + "dev": true, + "optional": true + }, + "graceful-readlink": { + "version": "1.0.1", + "from": "graceful-readlink@>=1.0.0", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "dev": true + }, + "gulp-util": { + "version": "3.0.7", + "from": "gulp-util@3.0.7", + "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.7.tgz", + "dev": true, + "dependencies": { + "minimist": { + "version": "1.2.0", + "from": "minimist@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "dev": true + }, + "object-assign": { + "version": "3.0.0", + "from": "object-assign@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", + "dev": true + } + } + }, + "gulplog": { + "version": "1.0.0", + "from": "gulplog@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", + "dev": true + }, + "handle-thing": { + "version": "1.2.5", + "from": "handle-thing@>=1.2.4 <2.0.0", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-1.2.5.tgz", + "dev": true + }, + "handlebars": { + "version": "4.0.6", + "from": "handlebars@>=4.0.1 <5.0.0", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.6.tgz", + "dev": true, + "dependencies": { + "async": { + "version": "1.5.2", + "from": "async@>=1.4.0 <2.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "dev": true + }, + "source-map": { + "version": "0.4.4", + "from": "source-map@>=0.4.4 <0.5.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "dev": true + } + } + }, + "har-validator": { + "version": "2.0.6", + "from": "har-validator@>=2.0.6 <2.1.0", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", + "dev": true + }, + "has": { + "version": "1.0.1", + "from": "has@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", + "dev": true + }, + "has-ansi": { + "version": "2.0.0", + "from": "has-ansi@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "dev": true + }, + "has-binary": { + "version": "0.1.7", + "from": "has-binary@0.1.7", + "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz", + "dev": true, + "dependencies": { + "isarray": { + "version": "0.0.1", + "from": "isarray@0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "dev": true + } + } + }, + "has-color": { + "version": "0.1.7", + "from": "has-color@>=0.1.7 <0.2.0", + "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", + "dev": true + }, + "has-cors": { + "version": "1.1.0", + "from": "has-cors@1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "dev": true + }, + "has-flag": { + "version": "1.0.0", + "from": "has-flag@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "dev": true + }, + "has-gulplog": { + "version": "0.1.0", + "from": "has-gulplog@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "from": "has-unicode@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "dev": true + }, + "hash.js": { + "version": "1.0.3", + "from": "hash.js@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.0.3.tgz", + "dev": true + }, + "hasha": { + "version": "2.2.0", + "from": "hasha@>=2.2.0 <2.3.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz", + "dev": true + }, + "hawk": { + "version": "3.1.3", + "from": "hawk@>=3.1.3 <3.2.0", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "dev": true + }, + "he": { + "version": "0.5.0", + "from": "he@>=0.5.0 <0.6.0", + "resolved": "https://registry.npmjs.org/he/-/he-0.5.0.tgz" + }, + "highlight.js": { + "version": "9.8.0", + "from": "highlight.js@>=9.7.0 <10.0.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.8.0.tgz", + "dev": true + }, + "hoek": { + "version": "2.16.3", + "from": "hoek@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "dev": true + }, + "hosted-git-info": { + "version": "2.1.5", + "from": "hosted-git-info@>=2.1.4 <3.0.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.5.tgz", + "dev": true + }, + "hpack.js": { + "version": "2.1.6", + "from": "hpack.js@>=2.1.6 <3.0.0", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "dev": true + }, + "html-comment-regex": { + "version": "1.1.1", + "from": "html-comment-regex@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.1.tgz", + "dev": true + }, + "html-loader": { + "version": "0.4.4", + "from": "html-loader@>=0.4.4 <0.5.0", + "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-0.4.4.tgz", + "dev": true + }, + "html-minifier": { + "version": "3.2.3", + "from": "html-minifier@>=3.0.1 <4.0.0", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.2.3.tgz", + "dev": true, + "dependencies": { + "he": { + "version": "1.1.0", + "from": "he@>=1.1.0 <1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.0.tgz", + "dev": true + } + } + }, + "html-webpack-plugin": { + "version": "2.24.1", + "from": "html-webpack-plugin@>=2.21.0 <3.0.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-2.24.1.tgz", + "dev": true, + "dependencies": { + "bluebird": { + "version": "3.4.6", + "from": "bluebird@>=3.4.6 <4.0.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.6.tgz", + "dev": true + } + } + }, + "htmlparser2": { + "version": "3.3.0", + "from": "htmlparser2@>=3.3.0 <3.4.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.3.0.tgz", + "dev": true, + "dependencies": { + "domutils": { + "version": "1.1.6", + "from": "domutils@>=1.1.0 <1.2.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.1.6.tgz", + "dev": true + }, + "isarray": { + "version": "0.0.1", + "from": "isarray@0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "dev": true + }, + "readable-stream": { + "version": "1.0.34", + "from": "readable-stream@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "dev": true + } + } + }, + "http-deceiver": { + "version": "1.2.7", + "from": "http-deceiver@>=1.2.4 <2.0.0", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "dev": true + }, + "http-errors": { + "version": "1.5.1", + "from": "http-errors@>=1.5.0 <1.6.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.5.1.tgz", + "dev": true + }, + "http-proxy": { + "version": "1.16.2", + "from": "http-proxy@>=1.8.1 <2.0.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz" + }, + "http-proxy-middleware": { + "version": "0.17.3", + "from": "http-proxy-middleware@>=0.17.1 <0.18.0", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.17.3.tgz", + "dev": true, + "dependencies": { + "is-extglob": { + "version": "2.1.1", + "from": "is-extglob@>=2.1.0 <3.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "dev": true + }, + "is-glob": { + "version": "3.1.0", + "from": "is-glob@>=3.1.0 <4.0.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "dev": true + } + } + }, + "http-server": { + "version": "0.9.0", + "from": "http-server@>=0.9.0 <0.10.0", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.9.0.tgz" + }, + "http-signature": { + "version": "1.1.1", + "from": "http-signature@>=1.1.0 <1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "dev": true + }, + "https-browserify": { + "version": "0.0.1", + "from": "https-browserify@0.0.1", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz", + "dev": true + }, + "https-proxy-agent": { + "version": "1.0.0", + "from": "https-proxy-agent@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", + "dev": true + }, + "iconv-lite": { + "version": "0.4.13", + "from": "iconv-lite@0.4.13", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", + "dev": true + }, + "icss-replace-symbols": { + "version": "1.0.2", + "from": "icss-replace-symbols@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.0.2.tgz", + "dev": true + }, + "ie-shim": { + "version": "0.1.0", + "from": "ie-shim@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/ie-shim/-/ie-shim-0.1.0.tgz" + }, + "ieee754": { + "version": "1.1.8", + "from": "ieee754@>=1.1.4 <2.0.0", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", + "dev": true + }, + "imports-loader": { + "version": "0.6.5", + "from": "imports-loader@>=0.6.5 <0.7.0", + "resolved": "https://registry.npmjs.org/imports-loader/-/imports-loader-0.6.5.tgz", + "dev": true, + "dependencies": { + "source-map": { + "version": "0.1.43", + "from": "source-map@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "dev": true + } + } + }, + "in-publish": { + "version": "2.0.0", + "from": "in-publish@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", + "dev": true + }, + "indent-string": { + "version": "2.1.0", + "from": "indent-string@>=2.1.0 <3.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "dev": true + }, + "indexes-of": { + "version": "1.0.1", + "from": "indexes-of@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "dev": true + }, + "indexof": { + "version": "0.0.1", + "from": "indexof@0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "from": "inflight@>=1.0.4 <2.0.0", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "dev": true + }, + "inherits": { + "version": "2.0.3", + "from": "inherits@>=2.0.1 <2.1.0", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "dev": true + }, + "interpret": { + "version": "1.0.1", + "from": "interpret@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.1.tgz", + "dev": true + }, + "invert-kv": { + "version": "1.0.0", + "from": "invert-kv@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "dev": true + }, + "ipaddr.js": { + "version": "1.1.1", + "from": "ipaddr.js@1.1.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.1.1.tgz", + "dev": true + }, + "is-absolute-url": { + "version": "2.1.0", + "from": "is-absolute-url@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "from": "is-arrayish@>=0.2.1 <0.3.0", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "from": "is-binary-path@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "dev": true + }, + "is-buffer": { + "version": "1.1.4", + "from": "is-buffer@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.4.tgz", + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "from": "is-builtin-module@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "dev": true + }, + "is-dotfile": { + "version": "1.0.2", + "from": "is-dotfile@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.2.tgz", + "dev": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "from": "is-equal-shallow@>=0.1.3 <0.2.0", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "dev": true + }, + "is-extendable": { + "version": "0.1.1", + "from": "is-extendable@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "dev": true + }, + "is-extglob": { + "version": "1.0.0", + "from": "is-extglob@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "from": "is-finite@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "from": "is-fullwidth-code-point@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "from": "is-glob@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "dev": true + }, + "is-my-json-valid": { + "version": "2.15.0", + "from": "is-my-json-valid@>=2.12.4 <3.0.0", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz", + "dev": true + }, + "is-number": { + "version": "2.1.0", + "from": "is-number@>=2.1.0 <3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "dev": true + }, + "is-plain-obj": { + "version": "1.1.0", + "from": "is-plain-obj@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "dev": true + }, + "is-posix-bracket": { + "version": "0.1.1", + "from": "is-posix-bracket@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "from": "is-primitive@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "dev": true + }, + "is-promise": { + "version": "2.1.0", + "from": "is-promise@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "dev": true + }, + "is-property": { + "version": "1.0.2", + "from": "is-property@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "from": "is-stream@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "dev": true + }, + "is-svg": { + "version": "2.1.0", + "from": "is-svg@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "from": "is-typedarray@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "from": "is-utf8@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "from": "isarray@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "dev": true + }, + "isbinaryfile": { + "version": "3.0.1", + "from": "isbinaryfile@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.1.tgz", + "dev": true + }, + "isexe": { + "version": "1.1.2", + "from": "isexe@>=1.1.1 <2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-1.1.2.tgz", + "dev": true + }, + "isobject": { + "version": "2.1.0", + "from": "isobject@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "from": "isstream@>=0.1.2 <0.2.0", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "dev": true + }, + "istanbul": { + "version": "0.4.5", + "from": "istanbul@>=0.0.0 <1.0.0", + "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", + "dev": true, + "dependencies": { + "async": { + "version": "1.5.2", + "from": "async@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "dev": true + }, + "glob": { + "version": "5.0.15", + "from": "glob@>=5.0.15 <6.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "dev": true + }, + "supports-color": { + "version": "3.1.2", + "from": "supports-color@>=3.1.0 <4.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "dev": true + }, + "wordwrap": { + "version": "1.0.0", + "from": "wordwrap@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "dev": true + } + } + }, + "istanbul-instrumenter-loader": { + "version": "0.2.0", + "from": "istanbul-instrumenter-loader@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/istanbul-instrumenter-loader/-/istanbul-instrumenter-loader-0.2.0.tgz", + "dev": true + }, + "jade": { + "version": "1.11.0", + "from": "jade@>=1.7.0 <2.0.0", + "resolved": "https://registry.npmjs.org/jade/-/jade-1.11.0.tgz", + "dev": true, + "dependencies": { + "commander": { + "version": "2.6.0", + "from": "commander@>=2.6.0 <2.7.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.6.0.tgz", + "dev": true + } + } + }, + "jade-html-loader": { + "version": "0.0.3", + "from": "jade-html-loader@>=0.0.3 <0.0.4", + "resolved": "https://registry.npmjs.org/jade-html-loader/-/jade-html-loader-0.0.3.tgz", + "dev": true + }, + "jasmine": { + "version": "2.4.1", + "from": "jasmine@2.4.1", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.4.1.tgz", + "dev": true, + "dependencies": { + "glob": { + "version": "3.2.11", + "from": "glob@>=3.2.11 <4.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", + "dev": true + }, + "minimatch": { + "version": "0.3.0", + "from": "minimatch@>=0.3.0 <0.4.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", + "dev": true + } + } + }, + "jasmine-core": { + "version": "2.4.1", + "from": "jasmine-core@2.4.1", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.4.1.tgz", + "dev": true + }, + "jasmine-spec-reporter": { + "version": "2.5.0", + "from": "jasmine-spec-reporter@2.5.0", + "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-2.5.0.tgz", + "dev": true, + "dependencies": { + "colors": { + "version": "1.1.2", + "from": "colors@1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "dev": true + } + } + }, + "jasminewd2": { + "version": "0.0.9", + "from": "jasminewd2@0.0.9", + "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-0.0.9.tgz", + "dev": true + }, + "jodid25519": { + "version": "1.0.2", + "from": "jodid25519@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz", + "dev": true, + "optional": true + }, + "jquery": { + "version": "3.1.1", + "from": "jquery@>=1.9.1 <4.0.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.1.1.tgz" + }, + "js-base64": { + "version": "2.1.9", + "from": "js-base64@>=2.1.9 <3.0.0", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.1.9.tgz", + "dev": true + }, + "js-tokens": { + "version": "2.0.0", + "from": "js-tokens@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-2.0.0.tgz", + "dev": true + }, + "js-yaml": { + "version": "3.6.1", + "from": "js-yaml@>=3.6.1 <3.7.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.6.1.tgz", + "dev": true + }, + "jsbn": { + "version": "0.1.0", + "from": "jsbn@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz", + "dev": true, + "optional": true + }, + "jsesc": { + "version": "0.5.0", + "from": "jsesc@>=0.5.0 <0.6.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "dev": true + }, + "json-loader": { + "version": "0.5.4", + "from": "json-loader@>=0.5.4 <0.6.0", + "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.4.tgz", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "from": "json-schema@0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "from": "json-stringify-safe@>=5.0.1 <5.1.0", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "dev": true + }, + "json3": { + "version": "3.2.6", + "from": "json3@3.2.6", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.2.6.tgz", + "dev": true + }, + "json5": { + "version": "0.5.1", + "from": "json5@>=0.5.0 <0.6.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz" + }, + "jsonfile": { + "version": "2.4.0", + "from": "jsonfile@>=2.1.0 <3.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "dev": true, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "from": "graceful-fs@>=4.1.6 <5.0.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "dev": true, + "optional": true + } + } + }, + "jsonpointer": { + "version": "4.0.0", + "from": "jsonpointer@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.0.tgz", + "dev": true + }, + "jsprim": { + "version": "1.3.1", + "from": "jsprim@>=1.2.2 <2.0.0", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.3.1.tgz", + "dev": true + }, + "jstransformer": { + "version": "0.0.2", + "from": "jstransformer@0.0.2", + "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-0.0.2.tgz", + "dev": true + }, + "karma": { + "version": "1.3.0", + "from": "karma@>=1.2.0 <2.0.0", + "resolved": "https://registry.npmjs.org/karma/-/karma-1.3.0.tgz", + "dev": true, + "dependencies": { + "bluebird": { + "version": "3.4.6", + "from": "bluebird@>=3.3.0 <4.0.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.6.tgz", + "dev": true + }, + "colors": { + "version": "1.1.2", + "from": "colors@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "dev": true + }, + "glob": { + "version": "7.1.1", + "from": "glob@>=7.0.3 <8.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "dev": true + }, + "graceful-fs": { + "version": "4.1.11", + "from": "graceful-fs@>=4.1.2 <5.0.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "dev": true + }, + "lodash": { + "version": "3.10.1", + "from": "lodash@>=3.8.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "dev": true + } + } + }, + "karma-chrome-launcher": { + "version": "2.0.0", + "from": "karma-chrome-launcher@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.0.0.tgz", + "dev": true + }, + "karma-coverage": { + "version": "1.1.1", + "from": "karma-coverage@>=1.1.1 <2.0.0", + "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-1.1.1.tgz", + "dev": true, + "dependencies": { + "lodash": { + "version": "3.10.1", + "from": "lodash@>=3.8.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "dev": true + } + } + }, + "karma-jasmine": { + "version": "1.1.0", + "from": "karma-jasmine@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-1.1.0.tgz", + "dev": true + }, + "karma-mocha-reporter": { + "version": "2.2.1", + "from": "karma-mocha-reporter@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/karma-mocha-reporter/-/karma-mocha-reporter-2.2.1.tgz", + "dev": true + }, + "karma-phantomjs-launcher": { + "version": "1.0.2", + "from": "karma-phantomjs-launcher@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/karma-phantomjs-launcher/-/karma-phantomjs-launcher-1.0.2.tgz", + "dev": true, + "dependencies": { + "fs-extra": { + "version": "1.0.0", + "from": "fs-extra@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", + "dev": true + }, + "graceful-fs": { + "version": "4.1.11", + "from": "graceful-fs@>=4.1.2 <5.0.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "dev": true + }, + "phantomjs-prebuilt": { + "version": "2.1.14", + "from": "phantomjs-prebuilt@>=2.1.7 <3.0.0", + "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.14.tgz", + "dev": true + } + } + }, + "karma-remap-coverage": { + "version": "0.1.2", + "from": "karma-remap-coverage@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/karma-remap-coverage/-/karma-remap-coverage-0.1.2.tgz", + "dev": true + }, + "karma-sourcemap-loader": { + "version": "0.3.7", + "from": "karma-sourcemap-loader@>=0.3.7 <0.4.0", + "resolved": "https://registry.npmjs.org/karma-sourcemap-loader/-/karma-sourcemap-loader-0.3.7.tgz", + "dev": true, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "from": "graceful-fs@>=4.1.2 <5.0.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "dev": true + } + } + }, + "karma-webpack": { + "version": "1.8.0", + "from": "karma-webpack@1.8.0", + "resolved": "https://registry.npmjs.org/karma-webpack/-/karma-webpack-1.8.0.tgz", + "dev": true, + "dependencies": { + "lodash": { + "version": "3.10.1", + "from": "lodash@>=3.8.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "dev": true + }, + "source-map": { + "version": "0.1.43", + "from": "source-map@>=0.1.41 <0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "dev": true + } + } + }, + "kew": { + "version": "0.7.0", + "from": "kew@>=0.7.0 <0.8.0", + "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", + "dev": true + }, + "kind-of": { + "version": "3.1.0", + "from": "kind-of@>=3.0.2 <4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.1.0.tgz", + "dev": true + }, + "klaw": { + "version": "1.3.1", + "from": "klaw@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "dev": true, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "from": "graceful-fs@>=4.1.9 <5.0.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "dev": true, + "optional": true + } + } + }, + "lazy-cache": { + "version": "1.0.4", + "from": "lazy-cache@>=1.0.3 <2.0.0", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "dev": true + }, + "lcid": { + "version": "1.0.0", + "from": "lcid@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "dev": true + }, + "levn": { + "version": "0.3.0", + "from": "levn@>=0.3.0 <0.4.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "dev": true + }, + "linkify-it": { + "version": "2.0.2", + "from": "linkify-it@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.2.tgz", + "dev": true + }, + "load-json-file": { + "version": "1.1.0", + "from": "load-json-file@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "dev": true, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "from": "graceful-fs@>=4.1.2 <5.0.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "dev": true + } + } + }, + "loader-runner": { + "version": "2.2.0", + "from": "loader-runner@>=2.1.0 <3.0.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.2.0.tgz", + "dev": true + }, + "loader-utils": { + "version": "0.2.16", + "from": "loader-utils@>=0.2.15 <0.3.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.16.tgz" + }, + "lodash": { + "version": "4.17.2", + "from": "lodash@>=4.13.1 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.2.tgz", + "dev": true + }, + "lodash._arraycopy": { + "version": "3.0.0", + "from": "lodash._arraycopy@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz" + }, + "lodash._arrayeach": { + "version": "3.0.0", + "from": "lodash._arrayeach@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz" + }, + "lodash._baseassign": { + "version": "3.2.0", + "from": "lodash._baseassign@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz" + }, + "lodash._basecallback": { + "version": "3.3.1", + "from": "lodash._basecallback@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._basecallback/-/lodash._basecallback-3.3.1.tgz", + "dev": true + }, + "lodash._basecopy": { + "version": "3.0.1", + "from": "lodash._basecopy@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz" + }, + "lodash._baseeach": { + "version": "3.0.4", + "from": "lodash._baseeach@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._baseeach/-/lodash._baseeach-3.0.4.tgz", + "dev": true + }, + "lodash._basefind": { + "version": "3.0.0", + "from": "lodash._basefind@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._basefind/-/lodash._basefind-3.0.0.tgz", + "dev": true + }, + "lodash._basefindindex": { + "version": "3.6.0", + "from": "lodash._basefindindex@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._basefindindex/-/lodash._basefindindex-3.6.0.tgz", + "dev": true + }, + "lodash._basefor": { + "version": "3.0.3", + "from": "lodash._basefor@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz" + }, + "lodash._baseisequal": { + "version": "3.0.7", + "from": "lodash._baseisequal@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._baseisequal/-/lodash._baseisequal-3.0.7.tgz", + "dev": true + }, + "lodash._basetostring": { + "version": "3.0.1", + "from": "lodash._basetostring@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", + "dev": true + }, + "lodash._basevalues": { + "version": "3.0.0", + "from": "lodash._basevalues@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", + "dev": true + }, + "lodash._bindcallback": { + "version": "3.0.1", + "from": "lodash._bindcallback@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz" + }, + "lodash._createassigner": { + "version": "3.1.1", + "from": "lodash._createassigner@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz" + }, + "lodash._createcompounder": { + "version": "3.0.0", + "from": "lodash._createcompounder@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._createcompounder/-/lodash._createcompounder-3.0.0.tgz", + "dev": true + }, + "lodash._getnative": { + "version": "3.9.1", + "from": "lodash._getnative@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz" + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "from": "lodash._isiterateecall@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz" + }, + "lodash._reescape": { + "version": "3.0.0", + "from": "lodash._reescape@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", + "dev": true + }, + "lodash._reevaluate": { + "version": "3.0.0", + "from": "lodash._reevaluate@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", + "dev": true + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "from": "lodash._reinterpolate@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "dev": true + }, + "lodash._root": { + "version": "3.0.1", + "from": "lodash._root@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", + "dev": true + }, + "lodash.assign": { + "version": "3.2.0", + "from": "lodash.assign@>=3.2.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz" + }, + "lodash.camelcase": { + "version": "3.0.1", + "from": "lodash.camelcase@>=3.0.1 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-3.0.1.tgz", + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "from": "lodash.clonedeep@>=4.3.2 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "dev": true + }, + "lodash.deburr": { + "version": "3.2.0", + "from": "lodash.deburr@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.deburr/-/lodash.deburr-3.2.0.tgz", + "dev": true + }, + "lodash.escape": { + "version": "3.2.0", + "from": "lodash.escape@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", + "dev": true + }, + "lodash.find": { + "version": "3.2.1", + "from": "lodash.find@>=3.2.1 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.find/-/lodash.find-3.2.1.tgz", + "dev": true + }, + "lodash.flow": { + "version": "3.5.0", + "from": "lodash.flow@>=3.1.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz", + "dev": true + }, + "lodash.indexof": { + "version": "4.0.5", + "from": "lodash.indexof@>=4.0.5 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash.indexof/-/lodash.indexof-4.0.5.tgz", + "dev": true + }, + "lodash.isarguments": { + "version": "3.1.0", + "from": "lodash.isarguments@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz" + }, + "lodash.isarray": { + "version": "3.0.4", + "from": "lodash.isarray@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz" + }, + "lodash.isequal": { + "version": "4.4.0", + "from": "lodash.isequal@>=4.2.0 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.4.0.tgz", + "dev": true + }, + "lodash.isplainobject": { + "version": "3.2.0", + "from": "lodash.isplainobject@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz" + }, + "lodash.istypedarray": { + "version": "3.0.6", + "from": "lodash.istypedarray@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz" + }, + "lodash.keys": { + "version": "3.1.2", + "from": "lodash.keys@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz" + }, + "lodash.keysin": { + "version": "3.0.8", + "from": "lodash.keysin@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz" + }, + "lodash.merge": { + "version": "3.3.2", + "from": "lodash.merge@>=3.3.2 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-3.3.2.tgz" + }, + "lodash.pairs": { + "version": "3.0.1", + "from": "lodash.pairs@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.pairs/-/lodash.pairs-3.0.1.tgz", + "dev": true + }, + "lodash.restparam": { + "version": "3.6.1", + "from": "lodash.restparam@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz" + }, + "lodash.template": { + "version": "3.6.2", + "from": "lodash.template@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", + "dev": true + }, + "lodash.templatesettings": { + "version": "3.1.1", + "from": "lodash.templatesettings@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", + "dev": true + }, + "lodash.toplainobject": { + "version": "3.0.0", + "from": "lodash.toplainobject@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz" + }, + "lodash.words": { + "version": "3.2.0", + "from": "lodash.words@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.words/-/lodash.words-3.2.0.tgz", + "dev": true + }, + "log4js": { + "version": "0.6.38", + "from": "log4js@>=0.6.31 <0.7.0", + "resolved": "https://registry.npmjs.com/log4js/-/log4js-0.6.38.tgz", + "dev": true, + "dependencies": { + "isarray": { + "version": "0.0.1", + "from": "isarray@0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "dev": true + }, + "readable-stream": { + "version": "1.0.34", + "from": "readable-stream@>=1.0.2 <1.1.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "dev": true + } + } + }, + "longest": { + "version": "1.0.1", + "from": "longest@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "dev": true + }, + "loud-rejection": { + "version": "1.6.0", + "from": "loud-rejection@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "dev": true + }, + "lower-case": { + "version": "1.1.3", + "from": "lower-case@>=1.1.1 <2.0.0", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.3.tgz", + "dev": true + }, + "lru-cache": { + "version": "2.2.4", + "from": "lru-cache@>=2.2.0 <2.3.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.2.4.tgz", + "dev": true + }, + "macaddress": { + "version": "0.2.8", + "from": "macaddress@>=0.2.8 <0.3.0", + "resolved": "https://registry.npmjs.org/macaddress/-/macaddress-0.2.8.tgz", + "dev": true + }, + "make-error": { + "version": "1.2.1", + "from": "make-error@>=1.1.1 <2.0.0", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.2.1.tgz", + "dev": true + }, + "map-obj": { + "version": "1.0.1", + "from": "map-obj@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "dev": true + }, + "markdown-it": { + "version": "8.2.1", + "from": "markdown-it@>=8.0.0 <9.0.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.2.1.tgz", + "dev": true + }, + "markdown-it-abbr": { + "version": "1.0.4", + "from": "markdown-it-abbr@>=1.0.4 <2.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-abbr/-/markdown-it-abbr-1.0.4.tgz", + "dev": true + }, + "markdown-it-container": { + "version": "2.0.0", + "from": "markdown-it-container@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-container/-/markdown-it-container-2.0.0.tgz", + "dev": true + }, + "markdown-it-deflist": { + "version": "2.0.1", + "from": "markdown-it-deflist@>=2.0.1 <3.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-deflist/-/markdown-it-deflist-2.0.1.tgz", + "dev": true + }, + "markdown-it-emoji": { + "version": "1.3.0", + "from": "markdown-it-emoji@>=1.3.0 <2.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-emoji/-/markdown-it-emoji-1.3.0.tgz", + "dev": true + }, + "markdown-it-footnote": { + "version": "3.0.1", + "from": "markdown-it-footnote@>=3.0.1 <4.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-footnote/-/markdown-it-footnote-3.0.1.tgz", + "dev": true + }, + "markdown-it-highlightjs": { + "version": "2.0.0", + "from": "markdown-it-highlightjs@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-highlightjs/-/markdown-it-highlightjs-2.0.0.tgz", + "dev": true, + "dependencies": { + "highlight.js": { + "version": "8.9.1", + "from": "highlight.js@>=8.4.0 <9.0.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-8.9.1.tgz", + "dev": true + } + } + }, + "markdown-it-ins": { + "version": "2.0.0", + "from": "markdown-it-ins@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-ins/-/markdown-it-ins-2.0.0.tgz", + "dev": true + }, + "markdown-it-loader": { + "version": "0.5.0", + "from": "markdown-it-loader@>=0.5.0 <0.6.0", + "resolved": "https://registry.npmjs.org/markdown-it-loader/-/markdown-it-loader-0.5.0.tgz", + "dev": true + }, + "markdown-it-mark": { + "version": "2.0.0", + "from": "markdown-it-mark@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-mark/-/markdown-it-mark-2.0.0.tgz", + "dev": true + }, + "markdown-it-sub": { + "version": "1.0.0", + "from": "markdown-it-sub@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-sub/-/markdown-it-sub-1.0.0.tgz", + "dev": true + }, + "markdown-it-sup": { + "version": "1.0.0", + "from": "markdown-it-sup@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-sup/-/markdown-it-sup-1.0.0.tgz", + "dev": true + }, + "marked": { + "version": "0.3.6", + "from": "marked@>=0.3.5 <0.4.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.6.tgz", + "dev": true + }, + "markup-inline-loader": { + "version": "0.1.1", + "from": "markup-inline-loader@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/markup-inline-loader/-/markup-inline-loader-0.1.1.tgz", + "dev": true, + "dependencies": { + "colors": { + "version": "1.1.2", + "from": "colors@>=1.1.2 <1.2.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "dev": true + }, + "csso": { + "version": "2.0.0", + "from": "csso@>=2.0.0 <2.1.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-2.0.0.tgz", + "dev": true + }, + "svgo": { + "version": "0.6.6", + "from": "svgo@>=0.6.6 <0.7.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.6.6.tgz", + "dev": true + } + } + }, + "math-expression-evaluator": { + "version": "1.2.14", + "from": "math-expression-evaluator@>=1.2.14 <2.0.0", + "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.14.tgz", + "dev": true + }, + "md5": { + "version": "2.2.1", + "from": "md5@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", + "dev": true + }, + "mdurl": { + "version": "1.0.1", + "from": "mdurl@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "dev": true + }, + "media-typer": { + "version": "0.3.0", + "from": "media-typer@0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "dev": true + }, + "memory-fs": { + "version": "0.3.0", + "from": "memory-fs@>=0.3.0 <0.4.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.3.0.tgz", + "dev": true + }, + "meow": { + "version": "3.7.0", + "from": "meow@>=3.3.0 <4.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "dev": true, + "dependencies": { + "minimist": { + "version": "1.2.0", + "from": "minimist@>=1.1.3 <2.0.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "dev": true + } + } + }, + "merge-descriptors": { + "version": "1.0.1", + "from": "merge-descriptors@1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "dev": true + }, + "methods": { + "version": "1.1.2", + "from": "methods@>=1.1.2 <1.2.0", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "dev": true + }, + "micromatch": { + "version": "2.3.11", + "from": "micromatch@>=2.1.5 <3.0.0", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "dev": true + }, + "miller-rabin": { + "version": "4.0.0", + "from": "miller-rabin@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.0.tgz", + "dev": true + }, + "mime": { + "version": "1.3.4", + "from": "mime@>=1.2.11 <2.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz" + }, + "mime-db": { + "version": "1.25.0", + "from": "mime-db@>=1.25.0 <1.26.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.25.0.tgz", + "dev": true + }, + "mime-types": { + "version": "2.1.13", + "from": "mime-types@>=2.1.7 <2.2.0", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.13.tgz", + "dev": true + }, + "mimeparse": { + "version": "0.1.4", + "from": "mimeparse@>=0.1.4 <0.2.0", + "resolved": "https://registry.npmjs.org/mimeparse/-/mimeparse-0.1.4.tgz", + "dev": true + }, + "minimalistic-assert": { + "version": "1.0.0", + "from": "minimalistic-assert@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz", + "dev": true + }, + "minimatch": { + "version": "3.0.3", + "from": "minimatch@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", + "dev": true + }, + "minimist": { + "version": "0.0.8", + "from": "minimist@0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" + }, + "mkdirp": { + "version": "0.5.1", + "from": "mkdirp@>=0.5.1 <0.6.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz" + }, + "ms": { + "version": "0.7.1", + "from": "ms@0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "dev": true + }, + "multipipe": { + "version": "0.1.2", + "from": "multipipe@>=0.1.2 <0.2.0", + "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", + "dev": true + }, + "nan": { + "version": "2.4.0", + "from": "nan@>=2.3.0 <3.0.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.4.0.tgz", + "dev": true + }, + "ncname": { + "version": "1.0.0", + "from": "ncname@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/ncname/-/ncname-1.0.0.tgz", + "dev": true + }, + "negotiator": { + "version": "0.4.9", + "from": "negotiator@0.4.9", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.4.9.tgz", + "dev": true + }, + "no-case": { + "version": "2.3.0", + "from": "no-case@>=2.2.0 <3.0.0", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.0.tgz", + "dev": true + }, + "node-dir": { + "version": "0.1.16", + "from": "node-dir@>=0.1.10 <0.2.0", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.16.tgz", + "dev": true + }, + "node-gyp": { + "version": "3.4.0", + "from": "node-gyp@>=3.3.1 <4.0.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.4.0.tgz", + "dev": true, + "dependencies": { + "glob": { + "version": "7.1.1", + "from": "glob@>=7.0.3 <8.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "dev": true + }, + "graceful-fs": { + "version": "4.1.11", + "from": "graceful-fs@>=4.1.2 <5.0.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "dev": true + }, + "npmlog": { + "version": "3.1.2", + "from": "npmlog@>=0.0.0 <1.0.0||>=1.0.0 <2.0.0||>=2.0.0 <3.0.0||>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-3.1.2.tgz", + "dev": true + } + } + }, + "node-libs-browser": { + "version": "1.1.1", + "from": "node-libs-browser@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-1.1.1.tgz", + "dev": true + }, + "node-sass": { + "version": "3.13.1", + "from": "node-sass@>=3.8.0 <4.0.0", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-3.13.1.tgz", + "dev": true, + "dependencies": { + "glob": { + "version": "7.1.1", + "from": "glob@>=7.0.3 <8.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "dev": true + }, + "lodash.assign": { + "version": "4.2.0", + "from": "lodash.assign@>=4.2.0 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "dev": true + } + } + }, + "nopt": { + "version": "3.0.6", + "from": "nopt@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "dev": true + }, + "normalize-package-data": { + "version": "2.3.5", + "from": "normalize-package-data@>=2.3.4 <3.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.5.tgz", + "dev": true + }, + "normalize-path": { + "version": "2.0.1", + "from": "normalize-path@>=2.0.1 <3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.0.1.tgz", + "dev": true + }, + "normalize-range": { + "version": "0.1.2", + "from": "normalize-range@>=0.1.2 <0.2.0", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "dev": true + }, + "normalize-url": { + "version": "1.8.0", + "from": "normalize-url@>=1.4.0 <2.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.8.0.tgz", + "dev": true + }, + "npmlog": { + "version": "4.0.2", + "from": "npmlog@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.0.2.tgz", + "dev": true, + "dependencies": { + "gauge": { + "version": "2.7.2", + "from": "gauge@>=2.7.1 <2.8.0", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.2.tgz", + "dev": true + }, + "supports-color": { + "version": "0.2.0", + "from": "supports-color@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz", + "dev": true + } + } + }, + "nth-check": { + "version": "1.0.1", + "from": "nth-check@>=1.0.1 <1.1.0", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz", + "dev": true + }, + "null-check": { + "version": "1.0.0", + "from": "null-check@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz", + "dev": true + }, + "num2fraction": { + "version": "1.2.2", + "from": "num2fraction@>=1.2.2 <2.0.0", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "dev": true + }, + "number-is-nan": { + "version": "1.0.1", + "from": "number-is-nan@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "from": "oauth-sign@>=0.8.1 <0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "dev": true + }, + "object-assign": { + "version": "4.1.0", + "from": "object-assign@>=4.0.1 <5.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz" + }, + "object-component": { + "version": "0.0.3", + "from": "object-component@0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "dev": true + }, + "object.omit": { + "version": "2.0.1", + "from": "object.omit@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "dev": true + }, + "obuf": { + "version": "1.1.1", + "from": "obuf@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.1.tgz", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "from": "on-finished@>=2.3.0 <2.4.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "dev": true + }, + "on-headers": { + "version": "1.0.1", + "from": "on-headers@>=1.0.1 <1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", + "dev": true + }, + "once": { + "version": "1.4.0", + "from": "once@>=1.3.0 <2.0.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "dev": true + }, + "opener": { + "version": "1.4.2", + "from": "opener@>=1.4.0 <1.5.0", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.4.2.tgz" + }, + "opn": { + "version": "4.0.2", + "from": "opn@4.0.2", + "resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz", + "dev": true + }, + "optimist": { + "version": "0.6.1", + "from": "optimist@>=0.6.0 <0.7.0", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz" + }, + "optionator": { + "version": "0.8.2", + "from": "optionator@>=0.8.1 <0.9.0", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "dev": true, + "dependencies": { + "wordwrap": { + "version": "1.0.0", + "from": "wordwrap@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "dev": true + } + } + }, + "options": { + "version": "0.0.6", + "from": "options@>=0.0.5", + "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", + "dev": true + }, + "original": { + "version": "1.0.0", + "from": "original@>=0.0.5", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.0.tgz", + "dev": true, + "dependencies": { + "url-parse": { + "version": "1.0.5", + "from": "url-parse@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.0.5.tgz", + "dev": true + } + } + }, + "os-browserify": { + "version": "0.2.1", + "from": "os-browserify@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.2.1.tgz", + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "from": "os-homedir@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "dev": true + }, + "os-locale": { + "version": "1.4.0", + "from": "os-locale@>=1.4.0 <2.0.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "dev": true + }, + "os-tmpdir": { + "version": "1.0.2", + "from": "os-tmpdir@>=1.0.1 <1.1.0", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "dev": true + }, + "osenv": { + "version": "0.1.3", + "from": "osenv@>=0.0.0 <1.0.0", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.3.tgz", + "dev": true + }, + "pako": { + "version": "0.2.9", + "from": "pako@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "dev": true + }, + "param-case": { + "version": "2.1.0", + "from": "param-case@>=2.1.0 <2.2.0", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.0.tgz", + "dev": true + }, + "parse-asn1": { + "version": "5.0.0", + "from": "parse-asn1@>=5.0.0 <6.0.0", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.0.0.tgz", + "dev": true + }, + "parse-glob": { + "version": "3.0.4", + "from": "parse-glob@>=3.0.4 <4.0.0", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "dev": true + }, + "parse-json": { + "version": "2.2.0", + "from": "parse-json@>=2.2.0 <3.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "dev": true + }, + "parse5": { + "version": "1.5.1", + "from": "parse5@>=1.3.2 <2.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz", + "dev": true + }, + "parsejson": { + "version": "0.0.1", + "from": "parsejson@0.0.1", + "resolved": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.1.tgz", + "dev": true + }, + "parseqs": { + "version": "0.0.2", + "from": "parseqs@0.0.2", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.2.tgz", + "dev": true + }, + "parseuri": { + "version": "0.0.4", + "from": "parseuri@0.0.4", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.4.tgz", + "dev": true + }, + "parseurl": { + "version": "1.3.1", + "from": "parseurl@>=1.3.1 <1.4.0", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz", + "dev": true + }, + "path-array": { + "version": "1.0.1", + "from": "path-array@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/path-array/-/path-array-1.0.1.tgz", + "dev": true + }, + "path-browserify": { + "version": "0.0.0", + "from": "path-browserify@0.0.0", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", + "dev": true + }, + "path-exists": { + "version": "2.1.0", + "from": "path-exists@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "from": "path-is-absolute@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "from": "path-to-regexp@0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "dev": true + }, + "path-type": { + "version": "1.1.0", + "from": "path-type@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "dev": true, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "from": "graceful-fs@>=4.1.2 <5.0.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "dev": true + } + } + }, + "pbkdf2": { + "version": "3.0.9", + "from": "pbkdf2@>=3.0.3 <4.0.0", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.9.tgz", + "dev": true + }, + "pend": { + "version": "1.2.0", + "from": "pend@>=1.2.0 <1.3.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "dev": true + }, + "phantomjs": { + "version": "2.1.7", + "from": "phantomjs@>=2.1.7 <3.0.0", + "resolved": "https://registry.npmjs.org/phantomjs/-/phantomjs-2.1.7.tgz", + "dev": true, + "dependencies": { + "async": { + "version": "2.1.4", + "from": "async@>=2.0.1 <3.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.1.4.tgz", + "dev": true + }, + "form-data": { + "version": "1.0.1", + "from": "form-data@>=1.0.0-rc3 <1.1.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz", + "dev": true + }, + "node-uuid": { + "version": "1.4.7", + "from": "node-uuid@>=1.4.7 <1.5.0", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz", + "dev": true + }, + "qs": { + "version": "5.2.1", + "from": "qs@>=5.2.0 <5.3.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.1.tgz", + "dev": true + }, + "request": { + "version": "2.67.0", + "from": "request@>=2.67.0 <2.68.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.67.0.tgz", + "dev": true + }, + "tough-cookie": { + "version": "2.2.2", + "from": "tough-cookie@>=2.2.0 <2.3.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.2.tgz", + "dev": true + } + } + }, + "pify": { + "version": "2.3.0", + "from": "pify@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "from": "pinkie@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "from": "pinkie-promise@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "dev": true + }, + "portfinder": { + "version": "0.4.0", + "from": "portfinder@>=0.4.0 <0.5.0", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-0.4.0.tgz" + }, + "postcss": { + "version": "5.2.6", + "from": "postcss@>=5.0.6 <6.0.0", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.6.tgz", + "dev": true, + "dependencies": { + "supports-color": { + "version": "3.1.2", + "from": "supports-color@>=3.1.2 <4.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "dev": true + } + } + }, + "postcss-calc": { + "version": "5.3.1", + "from": "postcss-calc@>=5.2.0 <6.0.0", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-5.3.1.tgz", + "dev": true + }, + "postcss-colormin": { + "version": "2.2.1", + "from": "postcss-colormin@>=2.1.8 <3.0.0", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-2.2.1.tgz", + "dev": true + }, + "postcss-convert-values": { + "version": "2.5.0", + "from": "postcss-convert-values@>=2.3.4 <3.0.0", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-2.5.0.tgz", + "dev": true + }, + "postcss-discard-comments": { + "version": "2.0.4", + "from": "postcss-discard-comments@>=2.0.4 <3.0.0", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz", + "dev": true + }, + "postcss-discard-duplicates": { + "version": "2.0.2", + "from": "postcss-discard-duplicates@>=2.0.1 <3.0.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-2.0.2.tgz", + "dev": true + }, + "postcss-discard-empty": { + "version": "2.1.0", + "from": "postcss-discard-empty@>=2.0.1 <3.0.0", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz", + "dev": true + }, + "postcss-discard-overridden": { + "version": "0.1.1", + "from": "postcss-discard-overridden@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz", + "dev": true + }, + "postcss-discard-unused": { + "version": "2.2.3", + "from": "postcss-discard-unused@>=2.2.1 <3.0.0", + "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz", + "dev": true + }, + "postcss-filter-plugins": { + "version": "2.0.2", + "from": "postcss-filter-plugins@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz", + "dev": true + }, + "postcss-merge-idents": { + "version": "2.1.7", + "from": "postcss-merge-idents@>=2.1.5 <3.0.0", + "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz", + "dev": true + }, + "postcss-merge-longhand": { + "version": "2.0.1", + "from": "postcss-merge-longhand@>=2.0.1 <3.0.0", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-2.0.1.tgz", + "dev": true + }, + "postcss-merge-rules": { + "version": "2.0.11", + "from": "postcss-merge-rules@>=2.0.3 <3.0.0", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-2.0.11.tgz", + "dev": true + }, + "postcss-message-helpers": { + "version": "2.0.0", + "from": "postcss-message-helpers@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz", + "dev": true + }, + "postcss-minify-font-values": { + "version": "1.0.5", + "from": "postcss-minify-font-values@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz", + "dev": true + }, + "postcss-minify-gradients": { + "version": "1.0.5", + "from": "postcss-minify-gradients@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz", + "dev": true + }, + "postcss-minify-params": { + "version": "1.0.5", + "from": "postcss-minify-params@>=1.0.4 <2.0.0", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-1.0.5.tgz", + "dev": true + }, + "postcss-minify-selectors": { + "version": "2.0.7", + "from": "postcss-minify-selectors@>=2.0.4 <3.0.0", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-2.0.7.tgz", + "dev": true + }, + "postcss-modules-extract-imports": { + "version": "1.0.1", + "from": "postcss-modules-extract-imports@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.0.1.tgz", + "dev": true + }, + "postcss-modules-local-by-default": { + "version": "1.1.1", + "from": "postcss-modules-local-by-default@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.1.1.tgz", + "dev": true + }, + "postcss-modules-scope": { + "version": "1.0.2", + "from": "postcss-modules-scope@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.0.2.tgz", + "dev": true + }, + "postcss-modules-values": { + "version": "1.2.2", + "from": "postcss-modules-values@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.2.2.tgz", + "dev": true + }, + "postcss-normalize-charset": { + "version": "1.1.1", + "from": "postcss-normalize-charset@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz", + "dev": true + }, + "postcss-normalize-url": { + "version": "3.0.7", + "from": "postcss-normalize-url@>=3.0.7 <4.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-3.0.7.tgz", + "dev": true + }, + "postcss-ordered-values": { + "version": "2.2.2", + "from": "postcss-ordered-values@>=2.1.0 <3.0.0", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-2.2.2.tgz", + "dev": true + }, + "postcss-reduce-idents": { + "version": "2.3.1", + "from": "postcss-reduce-idents@>=2.2.2 <3.0.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-2.3.1.tgz", + "dev": true + }, + "postcss-reduce-initial": { + "version": "1.0.0", + "from": "postcss-reduce-initial@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-1.0.0.tgz", + "dev": true + }, + "postcss-reduce-transforms": { + "version": "1.0.4", + "from": "postcss-reduce-transforms@>=1.0.3 <2.0.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz", + "dev": true + }, + "postcss-selector-parser": { + "version": "2.2.2", + "from": "postcss-selector-parser@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-2.2.2.tgz", + "dev": true + }, + "postcss-svgo": { + "version": "2.1.5", + "from": "postcss-svgo@>=2.1.1 <3.0.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-2.1.5.tgz", + "dev": true + }, + "postcss-unique-selectors": { + "version": "2.0.2", + "from": "postcss-unique-selectors@>=2.0.2 <3.0.0", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz", + "dev": true + }, + "postcss-value-parser": { + "version": "3.3.0", + "from": "postcss-value-parser@>=3.2.3 <4.0.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz", + "dev": true + }, + "postcss-zindex": { + "version": "2.2.0", + "from": "postcss-zindex@>=2.0.1 <3.0.0", + "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-2.2.0.tgz", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "from": "prelude-ls@>=1.1.2 <1.2.0", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "dev": true + }, + "prepend-http": { + "version": "1.0.4", + "from": "prepend-http@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "dev": true + }, + "preserve": { + "version": "0.2.0", + "from": "preserve@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "dev": true + }, + "pretty-error": { + "version": "2.0.2", + "from": "pretty-error@>=2.0.2 <3.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.0.2.tgz", + "dev": true + }, + "private": { + "version": "0.1.6", + "from": "private@>=0.1.5 <0.2.0", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.6.tgz", + "dev": true + }, + "process": { + "version": "0.11.9", + "from": "process@>=0.11.0 <0.12.0", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.9.tgz", + "dev": true + }, + "process-nextick-args": { + "version": "1.0.7", + "from": "process-nextick-args@>=1.0.6 <1.1.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "dev": true + }, + "progress": { + "version": "1.1.8", + "from": "progress@>=1.1.8 <1.2.0", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "dev": true + }, + "promise": { + "version": "6.1.0", + "from": "promise@>=6.0.1 <7.0.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-6.1.0.tgz", + "dev": true + }, + "protractor": { + "version": "3.3.0", + "from": "protractor@>=3.2.2 <4.0.0", + "resolved": "https://registry.npmjs.org/protractor/-/protractor-3.3.0.tgz", + "dev": true, + "dependencies": { + "async": { + "version": "2.1.4", + "from": "async@>=2.0.1 <3.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.1.4.tgz", + "dev": true + }, + "form-data": { + "version": "1.0.1", + "from": "form-data@>=1.0.0-rc3 <1.1.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz", + "dev": true + }, + "node-uuid": { + "version": "1.4.7", + "from": "node-uuid@~1.4.7", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz", + "dev": true + }, + "qs": { + "version": "5.2.1", + "from": "qs@>=5.2.0 <5.3.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.1.tgz", + "dev": true + }, + "request": { + "version": "2.67.0", + "from": "request@>=2.67.0 <2.68.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.67.0.tgz", + "dev": true + }, + "tough-cookie": { + "version": "2.2.2", + "from": "tough-cookie@>=2.2.0 <2.3.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.2.tgz", + "dev": true + } + } + }, + "proxy-addr": { + "version": "1.1.2", + "from": "proxy-addr@>=1.1.2 <1.2.0", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.2.tgz", + "dev": true + }, + "prr": { + "version": "0.0.0", + "from": "prr@>=0.0.0 <0.1.0", + "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "from": "pseudomap@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "dev": true + }, + "public-encrypt": { + "version": "4.0.0", + "from": "public-encrypt@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz", + "dev": true + }, + "punycode": { + "version": "1.4.1", + "from": "punycode@>=1.4.1 <2.0.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "dev": true + }, + "q": { + "version": "1.4.1", + "from": "q@>=1.1.2 <2.0.0", + "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", + "dev": true + }, + "q-io": { + "version": "1.13.2", + "from": "q-io@1.13.2", + "resolved": "https://registry.npmjs.org/q-io/-/q-io-1.13.2.tgz", + "dev": true, + "dependencies": { + "qs": { + "version": "1.2.2", + "from": "qs@>=1.2.1 <2.0.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-1.2.2.tgz", + "dev": true + } + } + }, + "qjobs": { + "version": "1.1.5", + "from": "qjobs@>=1.1.4 <2.0.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.1.5.tgz", + "dev": true + }, + "qs": { + "version": "2.3.3", + "from": "qs@>=2.3.3 <2.4.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-2.3.3.tgz" + }, + "query-string": { + "version": "4.2.3", + "from": "query-string@>=4.1.0 <5.0.0", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.2.3.tgz", + "dev": true + }, + "querystring": { + "version": "0.2.0", + "from": "querystring@0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "from": "querystring-es3@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "dev": true + }, + "querystringify": { + "version": "0.0.4", + "from": "querystringify@>=0.0.0 <0.1.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-0.0.4.tgz", + "dev": true + }, + "randomatic": { + "version": "1.1.6", + "from": "randomatic@>=1.1.3 <2.0.0", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.6.tgz", + "dev": true + }, + "randombytes": { + "version": "2.0.3", + "from": "randombytes@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.3.tgz", + "dev": true + }, + "range-parser": { + "version": "1.2.0", + "from": "range-parser@>=1.2.0 <2.0.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "dev": true + }, + "raw-body": { + "version": "2.1.7", + "from": "raw-body@>=2.1.7 <2.2.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.7.tgz", + "dev": true + }, + "raw-loader": { + "version": "0.5.1", + "from": "raw-loader@0.5.1", + "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-0.5.1.tgz", + "dev": true + }, + "read-pkg": { + "version": "1.1.0", + "from": "read-pkg@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "dev": true + }, + "read-pkg-up": { + "version": "1.0.1", + "from": "read-pkg-up@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "dev": true + }, + "readable-stream": { + "version": "2.2.2", + "from": "readable-stream@>=2.0.1 <3.0.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.2.tgz", + "dev": true + }, + "readdirp": { + "version": "2.1.0", + "from": "readdirp@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", + "dev": true, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "from": "graceful-fs@>=4.1.2 <5.0.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "dev": true + } + } + }, + "recast": { + "version": "0.11.18", + "from": "recast@>=0.11.12 <0.12.0", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.11.18.tgz", + "dev": true, + "dependencies": { + "esprima": { + "version": "3.1.2", + "from": "esprima@>=3.1.0 <3.2.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.2.tgz", + "dev": true + } + } + }, + "rechoir": { + "version": "0.6.2", + "from": "rechoir@>=0.6.2 <0.7.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "dev": true + }, + "redent": { + "version": "1.0.0", + "from": "redent@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "dev": true + }, + "reduce-css-calc": { + "version": "1.3.0", + "from": "reduce-css-calc@>=1.2.6 <2.0.0", + "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz", + "dev": true + }, + "reduce-function-call": { + "version": "1.0.2", + "from": "reduce-function-call@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.2.tgz", + "dev": true + }, + "regenerate": { + "version": "1.3.2", + "from": "regenerate@>=1.2.1 <2.0.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.2.tgz", + "dev": true + }, + "regex-cache": { + "version": "0.4.3", + "from": "regex-cache@>=0.4.2 <0.5.0", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz", + "dev": true + }, + "regexpu-core": { + "version": "1.0.0", + "from": "regexpu-core@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", + "dev": true + }, + "regjsgen": { + "version": "0.2.0", + "from": "regjsgen@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "dev": true + }, + "regjsparser": { + "version": "0.1.5", + "from": "regjsparser@>=0.1.4 <0.2.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "dev": true + }, + "relateurl": { + "version": "0.2.7", + "from": "relateurl@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "dev": true + }, + "remap-istanbul": { + "version": "0.7.0", + "from": "remap-istanbul@>=0.7.0 <0.8.0", + "resolved": "https://registry.npmjs.org/remap-istanbul/-/remap-istanbul-0.7.0.tgz", + "dev": true, + "dependencies": { + "amdefine": { + "version": "1.0.0", + "from": "amdefine@1.0.0", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz", + "dev": true + } + } + }, + "renderkid": { + "version": "2.0.0", + "from": "renderkid@>=2.0.0 <2.1.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.0.tgz", + "dev": true, + "dependencies": { + "utila": { + "version": "0.3.3", + "from": "utila@>=0.3.0 <0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.3.3.tgz", + "dev": true + } + } + }, + "repeat-element": { + "version": "1.1.2", + "from": "repeat-element@>=1.1.2 <2.0.0", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "from": "repeat-string@>=1.5.2 <2.0.0", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "dev": true + }, + "repeating": { + "version": "2.0.1", + "from": "repeating@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "dev": true + }, + "replace-ext": { + "version": "0.0.1", + "from": "replace-ext@0.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", + "dev": true + }, + "request": { + "version": "2.79.0", + "from": "request@>=2.42.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", + "dev": true, + "dependencies": { + "qs": { + "version": "6.3.0", + "from": "qs@>=6.3.0 <6.4.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.0.tgz", + "dev": true + } + } + }, + "request-progress": { + "version": "2.0.1", + "from": "request-progress@>=2.0.1 <2.1.0", + "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "from": "require-directory@>=2.1.1 <3.0.0", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "from": "require-main-filename@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "from": "requires-port@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" + }, + "resolve": { + "version": "1.1.7", + "from": "resolve@>=1.1.0 <1.2.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "dev": true + }, + "right-align": { + "version": "0.1.3", + "from": "right-align@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "dev": true + }, + "rimraf": { + "version": "2.5.4", + "from": "rimraf@>=2.5.2 <3.0.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz", + "dev": true, + "dependencies": { + "glob": { + "version": "7.1.1", + "from": "glob@>=7.0.5 <8.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "dev": true + } + } + }, + "ripemd160": { + "version": "1.0.1", + "from": "ripemd160@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-1.0.1.tgz", + "dev": true + }, + "rxjs": { + "version": "5.0.0-rc.4", + "from": "rxjs@5.0.0-rc.4", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.0.0-rc.4.tgz" + }, + "sass-graph": { + "version": "2.1.2", + "from": "sass-graph@>=2.1.1 <3.0.0", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.1.2.tgz", + "dev": true, + "dependencies": { + "cliui": { + "version": "3.2.0", + "from": "cliui@>=3.2.0 <4.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "dev": true + }, + "glob": { + "version": "7.1.1", + "from": "glob@>=7.0.0 <8.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "dev": true + }, + "lodash.assign": { + "version": "4.2.0", + "from": "lodash.assign@>=4.0.3 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "dev": true + }, + "window-size": { + "version": "0.2.0", + "from": "window-size@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "dev": true + }, + "yargs": { + "version": "4.8.1", + "from": "yargs@>=4.7.1 <5.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "dev": true + } + } + }, + "sass-loader": { + "version": "4.0.2", + "from": "sass-loader@>=4.0.1 <5.0.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-4.0.2.tgz", + "dev": true, + "dependencies": { + "async": { + "version": "2.1.4", + "from": "async@>=2.0.1 <3.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.1.4.tgz", + "dev": true + } + } + }, + "saucelabs": { + "version": "1.0.1", + "from": "saucelabs@>=1.0.1 <1.1.0", + "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.0.1.tgz", + "dev": true + }, + "sax": { + "version": "1.2.1", + "from": "sax@>=1.2.1 <1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "dev": true + }, + "select-hose": { + "version": "2.0.0", + "from": "select-hose@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "dev": true + }, + "selenium-webdriver": { + "version": "2.52.0", + "from": "selenium-webdriver@2.52.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-2.52.0.tgz", + "dev": true, + "dependencies": { + "adm-zip": { + "version": "0.4.4", + "from": "adm-zip@0.4.4", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.4.tgz", + "dev": true + }, + "tmp": { + "version": "0.0.24", + "from": "tmp@0.0.24", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.24.tgz", + "dev": true + } + } + }, + "semver": { + "version": "4.3.6", + "from": "semver@>=4.3.3 <4.4.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", + "dev": true + }, + "send": { + "version": "0.14.1", + "from": "send@0.14.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.14.1.tgz", + "dev": true + }, + "serve-index": { + "version": "1.8.0", + "from": "serve-index@>=1.7.2 <2.0.0", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.8.0.tgz", + "dev": true, + "dependencies": { + "accepts": { + "version": "1.3.3", + "from": "accepts@>=1.3.3 <1.4.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", + "dev": true + }, + "negotiator": { + "version": "0.6.1", + "from": "negotiator@0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "dev": true + } + } + }, + "serve-static": { + "version": "1.11.1", + "from": "serve-static@>=1.11.1 <1.12.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.11.1.tgz", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "from": "set-blocking@>=2.0.0 <2.1.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "dev": true + }, + "set-immediate-shim": { + "version": "1.0.1", + "from": "set-immediate-shim@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "dev": true + }, + "setprototypeof": { + "version": "1.0.2", + "from": "setprototypeof@1.0.2", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.2.tgz", + "dev": true + }, + "sha.js": { + "version": "2.4.8", + "from": "sha.js@>=2.3.6 <3.0.0", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.8.tgz", + "dev": true + }, + "shelljs": { + "version": "0.7.5", + "from": "shelljs@>=0.7.0 <0.8.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.5.tgz", + "dev": true, + "dependencies": { + "glob": { + "version": "7.1.1", + "from": "glob@>=7.0.0 <8.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "dev": true + } + } + }, + "sigmund": { + "version": "1.0.1", + "from": "sigmund@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "from": "signal-exit@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "dev": true + }, + "sntp": { + "version": "1.0.9", + "from": "sntp@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "dev": true + }, + "socket.io": { + "version": "1.4.7", + "from": "socket.io@1.4.7", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.4.7.tgz", + "dev": true + }, + "socket.io-adapter": { + "version": "0.4.0", + "from": "socket.io-adapter@0.4.0", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.4.0.tgz", + "dev": true, + "dependencies": { + "isarray": { + "version": "0.0.1", + "from": "isarray@0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "dev": true + }, + "socket.io-parser": { + "version": "2.2.2", + "from": "socket.io-parser@2.2.2", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.2.2.tgz", + "dev": true, + "dependencies": { + "debug": { + "version": "0.7.4", + "from": "debug@0.7.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", + "dev": true + } + } + } + } + }, + "socket.io-client": { + "version": "1.4.6", + "from": "socket.io-client@1.4.6", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.4.6.tgz", + "dev": true, + "dependencies": { + "component-emitter": { + "version": "1.2.0", + "from": "component-emitter@1.2.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.0.tgz", + "dev": true + } + } + }, + "socket.io-parser": { + "version": "2.2.6", + "from": "socket.io-parser@2.2.6", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.2.6.tgz", + "dev": true, + "dependencies": { + "isarray": { + "version": "0.0.1", + "from": "isarray@0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "dev": true + }, + "json3": { + "version": "3.3.2", + "from": "json3@3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "dev": true + } + } + }, + "sockjs": { + "version": "0.3.18", + "from": "sockjs@0.3.18", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.18.tgz", + "dev": true, + "dependencies": { + "uuid": { + "version": "2.0.3", + "from": "uuid@>=2.0.2 <3.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", + "dev": true + } + } + }, + "sockjs-client": { + "version": "1.1.1", + "from": "sockjs-client@1.1.1", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.1.1.tgz", + "dev": true, + "dependencies": { + "faye-websocket": { + "version": "0.11.0", + "from": "faye-websocket@>=0.11.0 <0.12.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.0.tgz", + "dev": true + }, + "json3": { + "version": "3.3.2", + "from": "json3@>=3.3.2 <4.0.0", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "dev": true + } + } + }, + "sort-keys": { + "version": "1.1.2", + "from": "sort-keys@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "dev": true + }, + "source-list-map": { + "version": "0.1.7", + "from": "source-list-map@>=0.1.4 <0.2.0", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-0.1.7.tgz", + "dev": true + }, + "source-map": { + "version": "0.5.6", + "from": "source-map@>=0.5.3 <0.6.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "dev": true + }, + "source-map-loader": { + "version": "0.1.5", + "from": "source-map-loader@>=0.1.5 <0.2.0", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-0.1.5.tgz", + "dev": true, + "dependencies": { + "source-map": { + "version": "0.1.43", + "from": "source-map@>=0.1.33 <0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "dev": true + } + } + }, + "source-map-support": { + "version": "0.4.6", + "from": "source-map-support@>=0.4.0 <0.5.0", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.6.tgz", + "dev": true + }, + "sourcemap-istanbul-instrumenter-loader": { + "version": "0.2.0", + "from": "sourcemap-istanbul-instrumenter-loader@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/sourcemap-istanbul-instrumenter-loader/-/sourcemap-istanbul-instrumenter-loader-0.2.0.tgz", + "dev": true + }, + "sparkles": { + "version": "1.0.0", + "from": "sparkles@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.0.tgz", + "dev": true + }, + "spdx-correct": { + "version": "1.0.2", + "from": "spdx-correct@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "dev": true + }, + "spdx-expression-parse": { + "version": "1.0.4", + "from": "spdx-expression-parse@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", + "dev": true + }, + "spdx-license-ids": { + "version": "1.2.2", + "from": "spdx-license-ids@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "dev": true + }, + "spdy": { + "version": "3.4.4", + "from": "spdy@>=3.4.1 <4.0.0", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-3.4.4.tgz", + "dev": true + }, + "spdy-transport": { + "version": "2.0.18", + "from": "spdy-transport@>=2.0.15 <3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-2.0.18.tgz", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "from": "sprintf-js@>=1.0.3 <2.0.0", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "dev": true + }, + "sshpk": { + "version": "1.10.1", + "from": "sshpk@>=1.7.0 <2.0.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.10.1.tgz", + "dev": true, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "from": "assert-plus@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "dev": true + } + } }, - "@angular/router": { - "version": "3.0.0-rc.2", - "from": "@angular/router@3.0.0-rc.2", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-3.0.0-rc.2.tgz" + "statuses": { + "version": "1.3.1", + "from": "statuses@>=1.3.1 <2.0.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "dev": true }, - "@angularclass/conventions-loader": { - "version": "1.0.12", - "from": "@angularclass/conventions-loader@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/@angularclass/conventions-loader/-/conventions-loader-1.0.12.tgz" + "stream-browserify": { + "version": "2.0.1", + "from": "stream-browserify@>=2.0.1 <3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", + "dev": true }, - "@angularclass/request-idle-callback": { - "version": "1.0.7", - "from": "@angularclass/request-idle-callback@>=1.0.7 <2.0.0", - "resolved": "https://registry.npmjs.org/@angularclass/request-idle-callback/-/request-idle-callback-1.0.7.tgz" + "stream-http": { + "version": "2.5.0", + "from": "stream-http@>=2.3.1 <3.0.0", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.5.0.tgz", + "dev": true }, - "@angularclass/webpack-toolkit": { - "version": "1.3.3", - "from": "@angularclass/webpack-toolkit@>=1.3.3 <2.0.0", - "resolved": "https://registry.npmjs.org/@angularclass/webpack-toolkit/-/webpack-toolkit-1.3.3.tgz" + "strict-uri-encode": { + "version": "1.1.0", + "from": "strict-uri-encode@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "dev": true }, - "async": { - "version": "0.9.0", - "from": "async@0.9.0", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.0.tgz" + "string_decoder": { + "version": "0.10.31", + "from": "string_decoder@>=0.10.0 <0.11.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "dev": true }, - "big.js": { - "version": "3.1.3", - "from": "big.js@>=3.1.3 <4.0.0", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.1.3.tgz" + "string-replace-loader": { + "version": "1.0.5", + "from": "string-replace-loader@1.0.5", + "resolved": "https://registry.npmjs.org/string-replace-loader/-/string-replace-loader-1.0.5.tgz", + "dev": true, + "dependencies": { + "lodash": { + "version": "3.10.1", + "from": "lodash@>=3.10.1 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "dev": true + } + } }, - "colors": { - "version": "1.0.3", - "from": "colors@1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz" + "string-width": { + "version": "1.0.2", + "from": "string-width@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "dev": true }, - "core-js": { - "version": "2.4.1", - "from": "core-js@>=2.4.1 <3.0.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz" + "stringstream": { + "version": "0.0.5", + "from": "stringstream@>=0.0.4 <0.1.0", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "dev": true }, - "corser": { + "strip-ansi": { + "version": "3.0.1", + "from": "strip-ansi@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "dev": true + }, + "strip-bom": { + "version": "2.0.0", + "from": "strip-bom@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "dev": true + }, + "strip-indent": { + "version": "1.0.1", + "from": "strip-indent@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "dev": true + }, + "strip-json-comments": { "version": "2.0.1", - "from": "corser@>=2.0.0 <2.1.0", - "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz" + "from": "strip-json-comments@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "dev": true }, - "ecstatic": { - "version": "1.4.1", - "from": "ecstatic@>=1.4.0 <2.0.0", - "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-1.4.1.tgz" + "style-loader": { + "version": "0.13.1", + "from": "style-loader@>=0.13.1 <0.14.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.13.1.tgz", + "dev": true }, - "emojis-list": { + "supports-color": { + "version": "2.0.0", + "from": "supports-color@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "dev": true + }, + "svgo": { + "version": "0.7.1", + "from": "svgo@>=0.7.0 <0.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.1.tgz", + "dev": true, + "dependencies": { + "colors": { + "version": "1.1.2", + "from": "colors@>=1.1.2 <1.2.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "dev": true + } + } + }, + "symbol-observable": { + "version": "1.0.4", + "from": "symbol-observable@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.4.tgz" + }, + "tapable": { + "version": "0.2.5", + "from": "tapable@>=0.2.3 <0.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.5.tgz", + "dev": true + }, + "tar": { + "version": "2.2.1", + "from": "tar@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "dev": true + }, + "temp": { + "version": "0.5.1", + "from": "temp@>=0.5.1 <0.6.0", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.5.1.tgz", + "dev": true, + "dependencies": { + "rimraf": { + "version": "2.1.4", + "from": "rimraf@>=2.1.4 <2.2.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.1.4.tgz", + "dev": true + } + } + }, + "tether": { + "version": "1.4.0", + "from": "tether@>=1.3.7 <2.0.0", + "resolved": "https://registry.npmjs.org/tether/-/tether-1.4.0.tgz" + }, + "throttleit": { + "version": "1.0.0", + "from": "throttleit@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", + "dev": true + }, + "through": { + "version": "2.3.8", + "from": "through@>=2.3.6 <2.4.0", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "dev": true + }, + "through2": { "version": "2.0.1", - "from": "emojis-list@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.0.1.tgz" + "from": "through2@2.0.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.1.tgz", + "dev": true, + "dependencies": { + "readable-stream": { + "version": "2.0.6", + "from": "readable-stream@>=2.0.0 <2.1.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "dev": true + } + } }, - "eventemitter3": { - "version": "1.2.0", - "from": "eventemitter3@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz" + "time-stamp": { + "version": "1.0.1", + "from": "time-stamp@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.0.1.tgz", + "dev": true }, - "he": { - "version": "0.5.0", - "from": "he@>=0.5.0 <0.6.0", - "resolved": "https://registry.npmjs.org/he/-/he-0.5.0.tgz" + "timers-browserify": { + "version": "1.4.2", + "from": "timers-browserify@>=1.4.2 <2.0.0", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", + "dev": true }, - "http-proxy": { - "version": "1.14.0", - "from": "http-proxy@>=1.8.1 <2.0.0", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.14.0.tgz" + "tmp": { + "version": "0.0.28", + "from": "tmp@0.0.28", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.28.tgz", + "dev": true }, - "http-server": { - "version": "0.9.0", - "from": "http-server@>=0.9.0 <0.10.0", - "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.9.0.tgz" + "to-array": { + "version": "0.1.4", + "from": "to-array@0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "dev": true }, - "ie-shim": { - "version": "0.1.0", - "from": "ie-shim@>=0.1.0 <0.2.0", - "resolved": "https://registry.npmjs.org/ie-shim/-/ie-shim-0.1.0.tgz" + "to-arraybuffer": { + "version": "1.0.1", + "from": "to-arraybuffer@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "dev": true }, - "json5": { - "version": "0.5.0", - "from": "json5@>=0.5.0 <0.6.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.0.tgz" + "to-string-loader": { + "version": "1.1.5", + "from": "to-string-loader@>=1.1.4 <2.0.0", + "resolved": "https://registry.npmjs.org/to-string-loader/-/to-string-loader-1.1.5.tgz", + "dev": true }, - "loader-utils": { - "version": "0.2.15", - "from": "loader-utils@>=0.2.15 <0.3.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.15.tgz" + "toposort": { + "version": "1.0.0", + "from": "toposort@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.0.tgz", + "dev": true }, - "mime": { - "version": "1.3.4", - "from": "mime@>=1.2.11 <2.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz" + "tough-cookie": { + "version": "2.3.2", + "from": "tough-cookie@>=2.3.0 <2.4.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", + "dev": true }, - "minimist": { - "version": "1.2.0", - "from": "minimist@>=1.1.0 <2.0.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz" + "transformers": { + "version": "2.1.0", + "from": "transformers@2.1.0", + "resolved": "https://registry.npmjs.org/transformers/-/transformers-2.1.0.tgz", + "dev": true, + "dependencies": { + "is-promise": { + "version": "1.0.1", + "from": "is-promise@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-1.0.1.tgz", + "dev": true + }, + "optimist": { + "version": "0.3.7", + "from": "optimist@>=0.3.5 <0.4.0", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", + "dev": true + }, + "promise": { + "version": "2.0.0", + "from": "promise@>=2.0.0 <2.1.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-2.0.0.tgz", + "dev": true + }, + "source-map": { + "version": "0.1.43", + "from": "source-map@>=0.1.7 <0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "dev": true + }, + "uglify-js": { + "version": "2.2.5", + "from": "uglify-js@>=2.2.5 <2.3.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.2.5.tgz", + "dev": true + } + } }, - "mkdirp": { - "version": "0.5.1", - "from": "mkdirp@>=0.5.0 <0.6.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "trim-newlines": { + "version": "1.0.0", + "from": "trim-newlines@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "dev": true + }, + "ts-helpers": { + "version": "1.1.1", + "from": "ts-helpers@1.1.1", + "resolved": "https://registry.npmjs.org/ts-helpers/-/ts-helpers-1.1.1.tgz", + "dev": true + }, + "ts-node": { + "version": "1.7.2", + "from": "ts-node@>=1.3.0 <2.0.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-1.7.2.tgz", + "dev": true, "dependencies": { "minimist": { - "version": "0.0.8", - "from": "minimist@0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" + "version": "1.2.0", + "from": "minimist@>=1.2.0 <2.0.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "dev": true } } }, - "object-assign": { - "version": "4.1.0", - "from": "object-assign@>=4.0.1 <5.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz" + "tsconfig": { + "version": "5.0.3", + "from": "tsconfig@>=5.0.2 <6.0.0", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-5.0.3.tgz", + "dev": true }, - "opener": { - "version": "1.4.1", - "from": "opener@>=1.4.0 <1.5.0", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.4.1.tgz" + "tslint": { + "version": "3.15.1", + "from": "tslint@3.15.1", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-3.15.1.tgz", + "dev": true, + "dependencies": { + "colors": { + "version": "1.1.2", + "from": "colors@>=1.1.2 <2.0.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "dev": true + }, + "diff": { + "version": "2.2.3", + "from": "diff@>=2.2.1 <3.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-2.2.3.tgz", + "dev": true + }, + "glob": { + "version": "7.1.1", + "from": "glob@>=7.0.3 <8.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "dev": true + } + } }, - "optimist": { - "version": "0.6.1", - "from": "optimist@>=0.6.0 <0.7.0", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "tslint-loader": { + "version": "2.1.5", + "from": "tslint-loader@>=2.1.3 <3.0.0", + "resolved": "https://registry.npmjs.org/tslint-loader/-/tslint-loader-2.1.5.tgz", + "dev": true, "dependencies": { - "minimist": { - "version": "0.0.10", - "from": "minimist@>=0.0.1 <0.1.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz" + "strip-json-comments": { + "version": "1.0.4", + "from": "strip-json-comments@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "dev": true } } }, - "parse5": { - "version": "1.3.2", - "from": "parse5@1.3.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.3.2.tgz" + "tty-browserify": { + "version": "0.0.0", + "from": "tty-browserify@0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "dev": true }, - "portfinder": { - "version": "0.4.0", - "from": "portfinder@>=0.4.0 <0.5.0", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-0.4.0.tgz" + "tunnel-agent": { + "version": "0.4.3", + "from": "tunnel-agent@>=0.4.1 <0.5.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "dev": true }, - "qs": { - "version": "2.3.3", - "from": "qs@>=2.3.3 <2.4.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-2.3.3.tgz" + "tweetnacl": { + "version": "0.14.4", + "from": "tweetnacl@>=0.14.0 <0.15.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.4.tgz", + "dev": true, + "optional": true }, - "requires-port": { - "version": "1.0.0", - "from": "requires-port@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" + "type-check": { + "version": "0.3.2", + "from": "type-check@>=0.3.2 <0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "dev": true }, - "rxjs": { - "version": "5.0.0-beta.11", - "from": "rxjs@5.0.0-beta.11", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.0.0-beta.11.tgz" + "type-is": { + "version": "1.6.14", + "from": "type-is@>=1.6.13 <1.7.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.14.tgz", + "dev": true }, - "symbol-observable": { + "typedarray": { + "version": "0.0.6", + "from": "typedarray@>=0.0.5 <0.1.0", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "dev": true + }, + "typedoc": { + "version": "0.4.5", + "from": "typedoc@>=0.4.5 <0.5.0", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.4.5.tgz", + "dev": true, + "dependencies": { + "async": { + "version": "1.5.2", + "from": "async@>=1.4.0 <2.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "dev": true + }, + "fs-extra": { + "version": "0.30.0", + "from": "fs-extra@>=0.30.0 <0.31.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "dev": true + }, + "graceful-fs": { + "version": "4.1.11", + "from": "graceful-fs@>=4.1.2 <5.0.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "dev": true + }, + "handlebars": { + "version": "4.0.5", + "from": "handlebars@4.0.5", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.5.tgz", + "dev": true + }, + "source-map": { + "version": "0.4.4", + "from": "source-map@>=0.4.4 <0.5.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "dev": true + }, + "typescript": { + "version": "1.8.10", + "from": "typescript@1.8.10", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-1.8.10.tgz", + "dev": true + } + } + }, + "typedoc-default-themes": { + "version": "0.4.1", + "from": "typedoc-default-themes@>=0.4.0 <0.5.0", + "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.4.1.tgz", + "dev": true + }, + "typescript": { + "version": "2.0.3", + "from": "typescript@2.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.0.3.tgz", + "dev": true + }, + "uc.micro": { + "version": "1.0.3", + "from": "uc.micro@>=1.0.3 <2.0.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.3.tgz", + "dev": true + }, + "uglify-js": { + "version": "2.7.5", + "from": "uglify-js@>=2.7.0 <2.8.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.7.5.tgz", + "dev": true, + "dependencies": { + "async": { + "version": "0.2.10", + "from": "async@>=0.2.6 <0.3.0", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "dev": true + } + } + }, + "uglify-to-browserify": { "version": "1.0.2", - "from": "symbol-observable@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.2.tgz" + "from": "uglify-to-browserify@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "dev": true + }, + "ultron": { + "version": "1.0.2", + "from": "ultron@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", + "dev": true + }, + "underscore.string": { + "version": "3.3.4", + "from": "underscore.string@>=3.3.4 <4.0.0", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.4.tgz", + "dev": true }, "union": { - "version": "0.4.4", + "version": "0.4.6", "from": "union@>=0.4.3 <0.5.0", - "resolved": "https://registry.npmjs.org/union/-/union-0.4.4.tgz" + "resolved": "https://registry.npmjs.org/union/-/union-0.4.6.tgz" + }, + "uniq": { + "version": "1.0.1", + "from": "uniq@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "dev": true + }, + "uniqid": { + "version": "4.1.0", + "from": "uniqid@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/uniqid/-/uniqid-4.1.0.tgz", + "dev": true + }, + "uniqs": { + "version": "2.0.0", + "from": "uniqs@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "from": "unpipe@1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "dev": true + }, + "upper-case": { + "version": "1.1.3", + "from": "upper-case@>=1.1.1 <2.0.0", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "dev": true + }, + "url": { + "version": "0.11.0", + "from": "url@>=0.11.0 <0.12.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "dev": true, + "dependencies": { + "punycode": { + "version": "1.3.2", + "from": "punycode@1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "dev": true + } + } }, "url-join": { "version": "1.1.0", "from": "url-join@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/url-join/-/url-join-1.1.0.tgz" }, + "url-loader": { + "version": "0.5.7", + "from": "url-loader@>=0.5.7 <0.6.0", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-0.5.7.tgz", + "dev": true, + "dependencies": { + "mime": { + "version": "1.2.11", + "from": "mime@>=1.2.0 <1.3.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", + "dev": true + } + } + }, + "url-parse": { + "version": "1.1.7", + "from": "url-parse@>=1.1.1 <2.0.0", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.1.7.tgz", + "dev": true + }, + "url2": { + "version": "0.0.0", + "from": "url2@>=0.0.0 <0.0.1", + "resolved": "https://registry.npmjs.org/url2/-/url2-0.0.0.tgz", + "dev": true + }, + "urlgrey": { + "version": "0.4.4", + "from": "urlgrey@>=0.4.0", + "resolved": "https://registry.npmjs.org/urlgrey/-/urlgrey-0.4.4.tgz", + "dev": true + }, + "user-home": { + "version": "1.1.1", + "from": "user-home@>=1.1.1 <2.0.0", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", + "dev": true + }, + "useragent": { + "version": "2.1.9", + "from": "useragent@>=2.1.9 <3.0.0", + "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.1.9.tgz", + "dev": true + }, + "utf8": { + "version": "2.1.0", + "from": "utf8@2.1.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.0.tgz", + "dev": true + }, + "util": { + "version": "0.10.3", + "from": "util@>=0.10.3 <0.11.0", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "dev": true, + "dependencies": { + "inherits": { + "version": "2.0.1", + "from": "inherits@2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "dev": true + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "from": "util-deprecate@>=1.0.1 <1.1.0", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "dev": true + }, + "utila": { + "version": "0.4.0", + "from": "utila@>=0.4.0 <0.5.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "dev": true + }, + "utils-merge": { + "version": "1.0.0", + "from": "utils-merge@1.0.0", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", + "dev": true + }, + "uuid": { + "version": "3.0.1", + "from": "uuid@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz", + "dev": true + }, + "v8flags": { + "version": "2.0.11", + "from": "v8flags@>=2.0.11 <3.0.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.0.11.tgz", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.1", + "from": "validate-npm-package-license@>=3.0.1 <4.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "dev": true + }, + "vary": { + "version": "1.1.0", + "from": "vary@>=1.1.0 <1.2.0", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.0.tgz", + "dev": true + }, + "vendors": { + "version": "1.0.1", + "from": "vendors@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.1.tgz", + "dev": true + }, + "verror": { + "version": "1.3.6", + "from": "verror@1.3.6", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", + "dev": true + }, + "vinyl": { + "version": "0.5.3", + "from": "vinyl@>=0.5.0 <0.6.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", + "dev": true + }, + "vm-browserify": { + "version": "0.0.4", + "from": "vm-browserify@0.0.4", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "dev": true + }, + "void-elements": { + "version": "2.0.1", + "from": "void-elements@>=2.0.1 <2.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "dev": true + }, + "watchpack": { + "version": "1.1.0", + "from": "watchpack@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.1.0.tgz", + "dev": true, + "dependencies": { + "async": { + "version": "2.0.0-rc.4", + "from": "async@2.0.0-rc.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.0.0-rc.4.tgz", + "dev": true + }, + "graceful-fs": { + "version": "4.1.11", + "from": "graceful-fs@>=4.1.2 <5.0.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "dev": true + } + } + }, + "wbuf": { + "version": "1.7.2", + "from": "wbuf@>=1.4.0 <2.0.0", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.2.tgz", + "dev": true + }, + "weak-map": { + "version": "1.0.0", + "from": "weak-map@1.0.0", + "resolved": "https://registry.npmjs.org/weak-map/-/weak-map-1.0.0.tgz", + "dev": true + }, + "webpack": { + "version": "2.1.0-beta.22", + "from": "webpack@2.1.0-beta.22", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-2.1.0-beta.22.tgz", + "dev": true, + "dependencies": { + "acorn": { + "version": "3.3.0", + "from": "acorn@>=3.2.0 <4.0.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "dev": true + }, + "async": { + "version": "1.5.2", + "from": "async@>=1.3.0 <2.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "dev": true + }, + "lodash.assign": { + "version": "4.2.0", + "from": "lodash.assign@>=4.0.3 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "dev": true + }, + "supports-color": { + "version": "3.1.2", + "from": "supports-color@>=3.1.0 <4.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "dev": true + }, + "uglify-js": { + "version": "2.6.4", + "from": "uglify-js@>=2.6.0 <2.7.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.4.tgz", + "dev": true, + "dependencies": { + "async": { + "version": "0.2.10", + "from": "async@>=0.2.6 <0.3.0", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "dev": true + }, + "yargs": { + "version": "3.10.0", + "from": "yargs@~3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "dev": true + } + } + }, + "yargs": { + "version": "4.8.1", + "from": "yargs@>=4.7.1 <5.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "dev": true, + "dependencies": { + "cliui": { + "version": "3.2.0", + "from": "cliui@>=3.2.0 <4.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "dev": true + }, + "window-size": { + "version": "0.2.0", + "from": "window-size@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "dev": true + } + } + } + } + }, + "webpack-dev-middleware": { + "version": "1.8.4", + "from": "webpack-dev-middleware@>=1.6.1 <2.0.0", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-1.8.4.tgz", + "dev": true + }, + "webpack-dev-server": { + "version": "2.1.0-beta.10", + "from": "webpack-dev-server@2.1.0-beta.10", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.1.0-beta.10.tgz", + "dev": true, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "from": "camelcase@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "dev": true + }, + "cliui": { + "version": "3.2.0", + "from": "cliui@>=3.2.0 <4.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "dev": true + }, + "supports-color": { + "version": "3.1.2", + "from": "supports-color@>=3.1.1 <4.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "dev": true + }, + "window-size": { + "version": "0.2.0", + "from": "window-size@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "dev": true + }, + "yargs": { + "version": "6.5.0", + "from": "yargs@>=6.0.0 <7.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.5.0.tgz", + "dev": true + }, + "yargs-parser": { + "version": "4.2.0", + "from": "yargs-parser@>=4.2.0 <5.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.0.tgz", + "dev": true + } + } + }, + "webpack-md5-hash": { + "version": "0.0.5", + "from": "webpack-md5-hash@>=0.0.5 <0.0.6", + "resolved": "https://registry.npmjs.org/webpack-md5-hash/-/webpack-md5-hash-0.0.5.tgz", + "dev": true + }, + "webpack-merge": { + "version": "0.14.1", + "from": "webpack-merge@>=0.14.1 <0.15.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-0.14.1.tgz", + "dev": true + }, + "webpack-sources": { + "version": "0.1.3", + "from": "webpack-sources@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-0.1.3.tgz", + "dev": true + }, + "websocket-driver": { + "version": "0.6.5", + "from": "websocket-driver@>=0.5.1", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz", + "dev": true + }, + "websocket-extensions": { + "version": "0.1.1", + "from": "websocket-extensions@>=0.1.1", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz", + "dev": true + }, + "whet.extend": { + "version": "0.9.9", + "from": "whet.extend@>=0.9.9 <0.10.0", + "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz", + "dev": true + }, + "which": { + "version": "1.2.12", + "from": "which@>=1.1.1 <2.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-1.2.12.tgz", + "dev": true + }, + "which-module": { + "version": "1.0.0", + "from": "which-module@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "dev": true + }, + "wide-align": { + "version": "1.1.0", + "from": "wide-align@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.0.tgz", + "dev": true + }, + "window-size": { + "version": "0.1.0", + "from": "window-size@0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "dev": true + }, + "with": { + "version": "4.0.3", + "from": "with@>=4.0.0 <4.1.0", + "resolved": "https://registry.npmjs.org/with/-/with-4.0.3.tgz", + "dev": true, + "dependencies": { + "acorn": { + "version": "1.2.2", + "from": "acorn@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz", + "dev": true + } + } + }, "wordwrap": { "version": "0.0.3", "from": "wordwrap@>=0.0.2 <0.1.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz" }, + "wrap-ansi": { + "version": "2.1.0", + "from": "wrap-ansi@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "from": "wrappy@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "dev": true + }, + "wrench": { + "version": "1.5.8", + "from": "wrench@1.5.8", + "resolved": "https://registry.npmjs.org/wrench/-/wrench-1.5.8.tgz", + "dev": true + }, + "ws": { + "version": "1.0.1", + "from": "ws@1.0.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-1.0.1.tgz", + "dev": true + }, + "xml-char-classes": { + "version": "1.0.0", + "from": "xml-char-classes@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/xml-char-classes/-/xml-char-classes-1.0.0.tgz", + "dev": true + }, + "xml2js": { + "version": "0.4.4", + "from": "xml2js@0.4.4", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.4.tgz", + "dev": true, + "dependencies": { + "sax": { + "version": "0.6.1", + "from": "sax@>=0.6.0 <0.7.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-0.6.1.tgz", + "dev": true + } + } + }, + "xmlbuilder": { + "version": "8.2.2", + "from": "xmlbuilder@>=1.0.0", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-8.2.2.tgz", + "dev": true + }, + "xmlhttprequest-ssl": { + "version": "1.5.1", + "from": "xmlhttprequest-ssl@1.5.1", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.1.tgz", + "dev": true + }, + "xtend": { + "version": "4.0.1", + "from": "xtend@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "dev": true + }, + "y18n": { + "version": "3.2.1", + "from": "y18n@>=3.2.1 <4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "dev": true + }, + "yallist": { + "version": "2.0.0", + "from": "yallist@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.0.0.tgz", + "dev": true + }, + "yargs": { + "version": "3.10.0", + "from": "yargs@>=3.10.0 <3.11.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "dev": true + }, + "yargs-parser": { + "version": "2.4.1", + "from": "yargs-parser@>=2.4.1 <3.0.0", + "resolved": "https://registry.npmjs.com/yargs-parser/-/yargs-parser-2.4.1.tgz", + "dev": true, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "from": "camelcase@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "dev": true + }, + "lodash.assign": { + "version": "4.2.0", + "from": "lodash.assign@>=4.0.6 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "dev": true + } + } + }, + "yauzl": { + "version": "2.4.1", + "from": "yauzl@2.4.1", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", + "dev": true + }, + "yeast": { + "version": "0.1.2", + "from": "yeast@0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "dev": true + }, + "yn": { + "version": "1.2.0", + "from": "yn@>=1.2.0 <2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-1.2.0.tgz", + "dev": true + }, "zone.js": { - "version": "0.6.17", - "from": "zone.js@>=0.6.17 <0.7.0", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.6.17.tgz" + "version": "0.7.2", + "from": "zone.js@>=0.7.2 <0.8.0", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.7.2.tgz" } } } diff --git a/package.json b/package.json index 6c8f1de..6cccbe2 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "http-server": "^0.9.0", "ie-shim": "^0.1.0", "rxjs": "5.0.0-rc.4", - "zone.js": "~0.6.17" + "zone.js": "^0.7.2" }, "devDependencies": { "@types/hammerjs": "^2.0.33", From c1adc3c048894c7a79d3993c612ad913111656df Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Thu, 15 Dec 2016 14:37:02 +0800 Subject: [PATCH 120/177] [article] adds angular-versioning-and-release-cycle --- src/app/_shared/api/articles/index.ts | 10 ++ .../timliu/angular-versioning/_index.md | 89 ++++++++++++++++++ .../angular-versioning/angular-releases.png | Bin 0 -> 42036 bytes .../angular-versioning/angular2-versions.png | Bin 0 -> 33865 bytes .../angular4-tentativeschedule.png | Bin 0 -> 69789 bytes .../timliu/angular-versioning/semver.png | Bin 0 -> 32299 bytes 6 files changed, 99 insertions(+) create mode 100644 src/app/_shared/api/articles/timliu/angular-versioning/_index.md create mode 100644 src/app/_shared/api/articles/timliu/angular-versioning/angular-releases.png create mode 100644 src/app/_shared/api/articles/timliu/angular-versioning/angular2-versions.png create mode 100644 src/app/_shared/api/articles/timliu/angular-versioning/angular4-tentativeschedule.png create mode 100644 src/app/_shared/api/articles/timliu/angular-versioning/semver.png diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index c0f3832..4f1480e 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -3,6 +3,16 @@ import {Article} from '../../models/article'; import {Observable} from 'rxjs/Observable'; const items: Article[] = [ + { + id: 'Angular 的版本号与发布周期', + title: 'Angular 的版本号与发布周期', + summary: '本文摘译了 Angular 官方博客中关于版本号与发布周期的内容。', + content: require('./timliu/angular-versioning/_index.md'), + first: true, + translation: true, + tags: ['Angular', 'semver'], + authors: ['timliu'], + }, { id: 'Angular2中的StructuralDirective', title: 'Angular 2 中的 Sturctural Directive', diff --git a/src/app/_shared/api/articles/timliu/angular-versioning/_index.md b/src/app/_shared/api/articles/timliu/angular-versioning/_index.md new file mode 100644 index 0000000..2f3c66c --- /dev/null +++ b/src/app/_shared/api/articles/timliu/angular-versioning/_index.md @@ -0,0 +1,89 @@ +# Angular 的版本号与发布周期 + +初稿日期:2016年12月15日 + +## 读者指引 +阅读本文需要读者对 [semver][](semantic versioning,语义化版本)有一定了解。 + +## 写作原因 +听说 Angular 要出 version 4 了。 +如果你一直关注 Angular 的官方博客,一定知道 Angular 从 v2.0.0 开始已经在使用 semver 了,所以不会觉得出个 MAJOR version 有什么值得大惊小怪的。可是,version 3 哪去了? +如果你最近很忙,9月份开始就没看过 Angular 的博客,而且你正在将自己的 Angular 1 项目迁移到 Angular 2,深知迁移过程是一个...额...过程,当你听到 Angular 要出 version 4 的时候,笑 cry 吧。 +其实,大家大可不必担心 Angular 版本跟新过快。要了解 Angular 的 version 4 是怎么来的,你可以翻阅 Angular 的博客(相关文章列表在文末参考列表),或者继续阅读本文。 +本文主要是摘译 Angular 官方博客中关于 Angular 使用 semver 以及发布计划的内容。 + +## Angular 发布计划 +先来看两个表: +表1,Angular 发布计划 weekly: +![angular4-tentativeschedule](./angular4-tentativeschedule.png) +大概意思就是:在2016年12月14日,我们可以拿到 v2.3.1 以及 v4.0.0-beta0。 +用 `npm show` 来验证一下: +``` +> npm show @angular/core time + + { ... , + '2.0.0': '2016-09-15T02:32:24.032Z', + ... , + '4.0.0-beta.0': '2016-12-15T00:34:53.925Z', + '2.3.1': '2016-12-15T02:26:53.076Z' } +``` +12月15日?好像逾期了。换成加州时间就是14日了,准时。 + += = = = = 分隔线 = = = = = = +表2,Angular MAJOR 版本发布计划: +![angular-releases](./angular-releases.png) +Version 4?不是事儿。 + +为什么会有这样两个表呢? + +## 为什么有这样的发布计划 +先看2016年9月14日的博文,《[Angular, version 2: proprioception-reinforcement][]》,其中有一段: +> Semantic Versioning +... To make it easy to manage dependencies on stable Angular releases, starting today with Angular 2.0.0, we will move to semantic versioning. Angular versioning will then follow the MAJOR.MINOR.PATCH scheme as described by semver: + +这段是说,从 v2.0.0 开始,Angular 将使用 semver(具体内容参见[链接][semver]),即版本号会遵从 `MAJOR.MINOR.PATCH` 的格式,比如: +![semver](./semver.png) + += = = = = 分隔线 = = = = = = +然后来到2016年10月7日,《[Versioning and Releasing Angular][]》: +> Time-based Release Cycles +... In general you can expect a patch release each week, about 3 minor updates and one major update every 6 months. We’re also baking quality into our schedule by providing Betas and RCs for each major and minor release. + +这段是说:每周发布一个 PATCH 版本,每6个月发布3个 MINOR 版本(译注:MINOR 版本的发布间隔没有说明)以及1个 MAJOR 版本。MINOR 以及 MAJOR 版本正式发布之前,会发布相应的 Betas、RCs。 +现在回过头看表1,我们就知道了:v2.3.0 这个 PATCH 版本发布后,每周有一个新的 PATCH 版本;每个 MAJOR 版本之间有3个 MINOR 版本,所以 v2.3 是 v2 这个 MAJOR 版本里的最后一个 MINOR 版本;2016年9月14日发布的 v2.0.0 ,那么6个月以后,即2017年3月14日前后应该有 v3。可是,为什么是 v4.0.0 呢? + += = = = = 分隔线 = = = = = = +然后是2016年12月13日,《[Ok... let me explain: it's going to be Angular 4.0, or just Angular][]》: +> Why not version 3 then? +The core Angular libraries live in one single GitHub repository at github.com/angular/angular. All of them are versioned the same way, but distributed as different NPM packages: +![angular2-versions](./angular2-versions.png) +Due to this misalignment of the router package’s version, the team decided to go straight for Angular v4. + +原来是 @angular/router 跑得太快,已经是 v3 了,统一起见,直接上 v4。 + +## 哪些 package 会遵从这样的发布计划 +Angular 由若干部分构成,比如 @angular/core, @angular/router,等等。哪些 package 的版本号会同步更新呢?参见 [Supported Public API Surface of Angular][]。 + +## 如何应对版本变更 +PATCH、MINOR 版本更新发布的时候,都是向下兼容的,拿过来用就是了。升级小版本的时候,如果遇到 'UNMET PEER DEPENDENCY' 或者其他版本问题的时候,可以参见木丁糖的《[如何优雅升级ng2小版本][]》。 + +MAJOR 版本更新时怎么办?这方面大家也不必担心,Angular Team 会在废除某个 API 的之前,给出升级路径,并继续支持旧 API 一段时间,为开发者预留足够的升级时间。详见《[Versioning and Releasing Angular][]》中的 Deprecation Policy。 + +## 总结 +甲:“听说 Angular 要出 v4 了?” +乙:“嗯,怎么啦?2018年9、10月还要出 v7 呢!” + +## 参考 +- [semver][] +- [Angular, version 2: proprioception-reinforcement][] +- [Versioning and Releasing Angular][] +- [Ok... let me explain: it's going to be Angular 4.0, or just Angular][] +- [Supported Public API Surface of Angular][] +- [如何优雅升级ng2小版本][] + +[semver]: (http://semver.org/lang/zh-CN/) +[Angular, version 2: proprioception-reinforcement]: (angularjs.blogspot.com/2016/09/angular2-final.html) +[Versioning and Releasing Angular]: (http://angularjs.blogspot.com/2016/10/versioning-and-releasing-angular.html) +[Ok... let me explain: it's going to be Angular 4.0, or just Angular]: (http://angularjs.blogspot.com/2016/12/ok-let-me-explain-its-going-to-be.html) +[Supported Public API Surface of Angular]: (https://github.com/angular/angular/blob/master/docs/PUBLIC_API.md) +[如何优雅升级ng2小版本]: (https://wx.angular.cn/library/article/%E5%A6%82%E4%BD%95%E4%BC%98%E9%9B%85%E5%8D%87%E7%BA%A7ng2%E5%B0%8F%E7%89%88%E6%9C%AC) diff --git a/src/app/_shared/api/articles/timliu/angular-versioning/angular-releases.png b/src/app/_shared/api/articles/timliu/angular-versioning/angular-releases.png new file mode 100644 index 0000000000000000000000000000000000000000..500a92ac910dc6e0e3e79d8c4a72477fa39476ec GIT binary patch literal 42036 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 A>i_@% literal 0 HcmV?d00001 diff --git a/src/app/_shared/api/articles/timliu/angular-versioning/angular2-versions.png b/src/app/_shared/api/articles/timliu/angular-versioning/angular2-versions.png new file mode 100644 index 0000000000000000000000000000000000000000..b0915d9e17da75f084dfa73d6e135a0a5ff0526d GIT binary patch literal 33865 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

    `。 +- 这里不讨论上面的这样的组件结构是否是最优的、是否应该是用“结构 directive”等等,只以实现这组标签的写法为努力方向。 + +我们希望这组标签呈现的效果是: +![页面显示](./screen-shot.png) +初始显示 title0、content0、title1;点击 title1,显示 content1,隐藏 content0;点击 title0,显示 content0,隐藏 content1。 + +## 代码编写 + +### 脚手架搭建(生成基础代码) +我们需要的 component 包括:accordion、panel、panel-title、panel-content,另外还需要一个 interface 文件。 +``` +> ng g module tl-accordion +... (生成 TlAccordionModule 以及 TlAccordionComponent) +> ng g component tl-accordion/tl-accordion-panel +... (生成 TlAccordionPanelComponent) +> ng g component tl-accordion/tl-accordion-panel-title +... (生成 TlAccordionPanelTitleComponent) +> ng g component tl-accordion/tl-accordion-panel-content +... (生成 TlAccordionPanelContentComponent) +> (假设当前目录为 app)touch tl-accordion/tl-accordion.interface.ts +``` +我们需要 accordion component,但用的指令是 ng g module,即生成了 accordion module 和 accordion component。这样做的目的是预留 provider 位置(在 module 里),方便以后配置全局变量,比如要求 app 里所有的 accordion 都是怎么怎么样的(仿照 ng-bootstrap的做法)。 +注:因为像 TlAccordionPanelContentComponent 这样的名字太长,后文会用最后两个词(即 content component)代替。 + +### 实现 title 组件显示 title,content 组件显示 content +要显示 `This is a title.` 里的 'This is a title.',我们只需要在 title component 的 template 里写一行:``。content component 同理。完。 + +### 实现 pannel 里显示 title 和 content +我们在 app.component.html 里写道: + +```html + + + title + content + +``` +要将 tl-accordion-panel-title 和 tl-accordion-panel-content 的内容在 tl-accordion-panel 里面显示出来,我们需要两个 ng-content,分别放置 title 和 content。在 panel component 的 template 里写: + +```html + + +
    + +
    +``` +role 和 class 是抄来的(配合 bootstrap 使用),重点是 ng-content 的 select 属性 -- select 里面是选择器,`select="tl-accordion-panel-title"` 的意思是:选择 tag 为 tl-accordion-panel-title 的元素,并将其内容放置到这个 ng-content 里面。tl-accordion-panel-content 同理。 + +### 实现 click on title => toggle content ( panel 内部解决) +承接上面的 `tl-accordion-panel.component.html`,我们需要实现能够初始化是否显示 `.card-block`,而且在点击 `.card-header` 时,切换 `.card-block` 的显示。可以这样: + +```typescript +// tl-accordion-panel.component.ts +export class TlAccordionPanelComponent { + @Input() expanded: boolean = false; +} +``` +初始化就是: + +```html + + + ... + +``` + +点击切换就是: + +```html + + +
    ...
    +``` + +### 实现 expandOneOnly( panel 传递给 accordion 统一解决) +其实在完成上一步之后,这个 accordion component 已经可以用了。只是,如果我们希望 accordion 下面的 panel,在某一时间只有一个是 expanded,点开另外一个 panel 的同时,关闭之前展开的 panel,这个该如何实现呢? +我们需要 accordion component 来统一安排 panel 的显示状态: +- 首先,accordion component 记录了点击之前展开着的 panel 的 id, +- 在点击某个 title 以后,被点击的 panel 展开,并向 accordion component 发送状态数据,数据中包含 panel 的 id, +- accordion component 对比 id,如果 id 不同,accordion component 指示之前展开的 panel 收起,并记录新的展开着的 panel 的 id。 +这个 id 是什么呢?在 template 里没有设置啊?我们可以用 panel 实例来作为 panel 实例的 id。看代码: + +```typescript +// tl-accordion.interface.ts +export interface PanelState { + panel: TlAccordionPanelComponent; // 我为自己带盐 + expanded: boolean; +} +export type PanelStateRxx = Subject; // 这个会在 tl-accordion.component.ts 里面用到 + +// tl-accordion-panel.component.ts +export class TlAccordionPanelComponent { + ... + stateRxx: Subject = new Subject(); +} +``` + +```html + + +... +``` +上面这个 `{panel: this, ...}` 里的这个 this,就是 panel 实例自身。每次点击,stateRxx 都会把这个 data 发送出去。接下来看 accordion component 的代码: + + +```ts +// tl-accordion.component.ts +export class TlAccordionComponent { + @Input() public expandOneOnly: boolean = false; + @ContentChildren(TlAccordionPanelComponent) private panels: QueryList; + private lastExpandedAtPanel: TlAccordionPanelComponent = null; + + ngAfterContentInit() { + if (this.expandOneOnly) { + // initialize this.lastExpandedAtPanel + this.lastExpandedAtPanel = this.panels.filter(panel => panel.expanded === true)[0]; + + // subscribe to mergedPanelStatesRx + const panelStateRxxArr: PanelStateRxx[] = this.panels.map(panel => panel.stateRxx); + const mergedPanelStatesRx: Observable = Observable.merge(...panelStateRxxArr); + const subscription = mergedPanelStatesRx + .filter(panelState => panelState.expanded === true && this.lastExpandedAtPanel !== panelState.panel) + .do(panelState => { + this.lastExpandedAtPanel.expanded = false; + this.lastExpandedAtPanel = panelState.panel; + }) + .subscribe(); + } + } +} + +``` +说明如下: +- `@Input() public expandOneOnly: boolean`:这个就是用来控制是否只展开一个 panel 的开关,在 app.component.html 里就是 ``。 +- `@ContentChildren(TlAccordionPanelComponent) private panels: QueryList`:在 app.component.html 里,我们看到,每个 panel 都是 accordion 的 contentChild,所以这里用 ContentChildren 来获取所有 panel 实例,得到一个 QueryList,这个 QueryList 有与 Array 类似的方法,如 filter、map等等。 +- `private lastExpandedAtPanel: TlAccordionPanelComponent`:这个记录上一个展开着的 panel 实例。 +- `ngAfterContentInit`:因为我们使用 Subject 向 accordion 传送数据,subscribe 之后不用做其他操作,所以只要在 ngAfterContentInit 运行一次就可以了。 +- `this.lastExpandedAtPanel = ...`:我们获取初始化 template 中的 expanded panel。(如果同时设置多于一个 `[expanded]="true"`,需要额外处理) +- 我们有一个 panel 的 QueryList(类似 Array),map 到panel.stateRxx,就是 `[panel0, panel1] => [panel0.stateRxx, panel1.stateRxx]`。 +- 然后将所有 stateRxx 用 Observable.merge 合并。 +- 每次点击 `.card-header`(即title),都会推送一个 PanelState,我们只关心那些包含 `expanded === true`的 PanelState。使用 `Observable.prototype.filter` 来过滤。 +- 如果收到的 PanelState 中包含的 panel 与 this.lastExpandedAtPanel 中记录的不一致,将 this.lastExpandedAtPanel.expanded 设置为 false,并设置新的 this.lastExpandedAtPanel。 +- 另外,我们需要记录 subscription,并在 ngOnDestroy 是 unsubscribe 所有相关的 subscription(代码部分略去)。 + +### 实现 panel 的 disabled 属性( panel 内部解决) +如果一个 panel 的 template 上有了 `[disabled]=true`,那么这个 panel 点不开,title 灰色,而且 mouse hover 的时候显示 tooltip。有兴趣的同学可以自己试试看。 + +### 实现全局配置 app 内所有 accordion +比如我们需要配置 app 内所有的 accordion 都是 expandOneOnly,这里需要一个 AccordionConfig,作为 TlAccordionModule 的 provider,在 app 启动时注册这个 provider,然后在每个 TlAccordionComponent 的 constructor 里注入这个依赖,当 template 了没有注明 expandOneOnly 时,使用全局配置。大家可以参看 [ng-bootstrap/accordion src][]。 + +## 总结 +- panel 内的问题很好解决,panel 之间的问题就要 parent (即 accordion)出面了。 +- panel 向 parent 传递信息,借助 RxJS/Subject,并以 panel 实例作为自己的 id (为自己带盐)。 + +最后顺便提一句:ng-bootstrap/accordion 的实现大量使用了 templateRef 和 ngTemplateOutlet,检查 panel 状态用的是 ngAfterContentChecked 这个钩子,没有用到 RxJS。 + +## 参考 +- [Angular 2 Transclusion using ng-content][] +- [ng-bootstrap/accordion api][] +- [ng-bootstrap/accordion src][] + +[ng-bootstrap/accordion api]: https://ng-bootstrap.github.io/#/components/accordion +[ng-bootstrap/accordion src]: https://github.com/ng-bootstrap/ng-bootstrap/tree/master/src/accordion +[Angular 2 Transclusion using ng-content]: https://scotch.io/tutorials/angular-2-transclusion-using-ng-content +[展开运算符]: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Spread_operator +[generate 指令]: https://github.com/angular/angular-cli#generating-components-directives-pipes-and-services + diff --git a/src/app/_shared/api/articles/timliu/simple-accordion/screen-shot.png b/src/app/_shared/api/articles/timliu/simple-accordion/screen-shot.png new file mode 100644 index 0000000000000000000000000000000000000000..47a4e55348438cd117bbe751444f5849276af209 GIT binary patch literal 3174 zcmb`Kdpy(oAIHC&<+d=?lw9T#p(ux>!Y~=Rl-7l?jw3^wki=YeIF99>m*dA~n@JYSz{$J`v{ zWL0GW0FZM+qdWir1lx!i(vlmqs_NK{jRh3p;b;fcFx6%^5(v)L)fNEivY=}}ZraFY zE}=am006%8w*hkU&|LxmsK^Ori@EB%SUh&&1Xr`8ReVybEKuF8qaZ{CKmAIt{6Lu3 z!L8>#6b1CheW?x9VPn*tQiMwj7<$+fjeEuFjli_z;T=H4kF*s_ zX~#sV!CHCO4k>E$tYxINi*_PNfq6tksV6v*6z~@WES>0Yp6mR;D*Ca zg|8d(v+|si`rzW!%%?;>(OYK)<4QI4G}6xy-OJGvq*3dlH{tY8fD6^#DpiNX?C$(<%A%m%L?46WFE|h`EH|#K7tsbk|-adz>_e(0$9=%q&XN|c2 z)1Lgj=Q-*N(u}FQldp_1#)e$nQC_4uqOQAS3C|_(u7X9~q9PE`7xTfpN+;Xo`j5AU z1Z~Y$j#Wr?Nw>-lT0z1ZSA|mTCMVhRJyti5(5>>=%VNfD zqhC4CTm_%nxh8LJcg+yJ`GgiycBSbLwt{>Z`*Z2Br)$pSfh9&YtWr zvo=a3W$2kANZ*3dNLb%)kS(en0#WQyf}zZg{!O6>{J6O}ofHU_28by{fVdqD1_Gp| zfdVZAaPHUN1+;c$ph1KaEmSD35?IrgKh?&2bEL;4(8iGVF)`3%fO_i=(%fa`S8&(>V=^MII-;dQ{ooRFCp%c^K1pd^5yDM=P-wQ z3rF)EZe?;7+ZCv=*l&ZmdERP+^8pXIC;uDKV`N;`7WkZ|H~y;y)$as*?qWf6jsW zK21@KFQFSNk(mPl3Cjne_PkMhK@!<$Yr@SrkEt7l1wEPLUj$~mF9JCZkHJa{QVVY_ z1Vz)Xs-qmA@a00-JFa}Nyw^4Ay_s(u^TRTkmGvcRI|UIvk-yiqhB9aKQw8JH zeUqdy&Xbh7;~6h!g&8A@M+<_HPwbSn*49pY(vgWy80642+dnqJ+r5qTZWnXrM(4+B z?wuN8t1#k&f5?i;;Q&8|WZ5i5gXN?DjT1oF_QLdhTCr4FR;VAMPuCFf0z!Bn5Kx={ zCIpMPJxuA^=JLFtPHcv#6T#08)hLUonZ=N@b?P($(RXO)M#n3OW}+j0%8jw#YG+%J z%km%FdOz^m(ul4b@};P?l63Kr zneNy0ISV_UmpiX#X0CH+dd3Z`#J;#-HOUJe!ZdT4+tqyDF3iTAbuWc$UifSz_P;OU z1gLL9OUpn>6{Y$ScMq~6-?$u zlf-E@HkTj9v{*<{U`?}U2zy(WJw2o%zm-w*pstIP3%ZEWGkuFog*hua%Gb-ijze{D zZCo$;`-0N6$uFU?fRZg(0t`Ho{Zl~ycZC06cN9o`W?>U%N9u82Sgd2a&wT?#!uM6& zLKiG7Do9p3N`o|GzDbvdB0Ux9{!QHf<`ClKByt9i8CJKrXiZz8VhdYLL0vevT{Lkj zFK=>e?DG_)tl^SFF@0oM0ILiB51c1_B5t`X5Xvk@a07J^q+au%K~<9HDzy+{aMOx` zA)DoXut&kVmzBupz>3;QcN36p$WG9;r&rf2nOP>g_`GmSRrvnDA@U`e7NLlSa_BEQx=IK>Q%xy1t<7ea&1E-{gB$XlK+alY%S;j+<=YF9iGK9^-7 z*ZJvJS_XsoFyAb0f3-bJ(}B^j;ntq){}~irc7b1hlSe*Qlg%nl#wJdNfed Date: Sun, 18 Dec 2016 19:05:29 +0800 Subject: [PATCH 125/177] adds intro to animation --- .../api/articles/timliu/simple-accordion/_index.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md index b078e73..1c94da4 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md @@ -197,6 +197,14 @@ export class TlAccordionComponent { ### 实现全局配置 app 内所有 accordion 比如我们需要配置 app 内所有的 accordion 都是 expandOneOnly,这里需要一个 AccordionConfig,作为 TlAccordionModule 的 provider,在 app 启动时注册这个 provider,然后在每个 TlAccordionComponent 的 constructor 里注入这个依赖,当 template 了没有注明 expandOneOnly 时,使用全局配置。大家可以参看 [ng-bootstrap/accordion src][]。 +### 添加 Amination +```html + +... +
    ...
    +``` +Oh, Angular ... + ## 总结 - panel 内的问题很好解决,panel 之间的问题就要 parent (即 accordion)出面了。 - panel 向 parent 传递信息,借助 RxJS/Subject,并以 panel 实例作为自己的 id (为自己带盐)。 From a04eb1d13d64e06dc88069689ae132682add0e47 Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Sun, 18 Dec 2016 20:28:27 +0800 Subject: [PATCH 126/177] minor changes --- .../timliu/simple-accordion/_index.md | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md index 1c94da4..2f8e178 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md @@ -44,7 +44,7 @@ 几点不那么重要的旁注: - tl 是前缀,前缀可以是随便什么。 - expandedOneOnly 和 expanded 这两个属性写在 template 里是用来初始化的,后面具体说明其功能。 -- title 和 content 可以是 html 代码,比如 `
    ...
    `。 +- title0 和 content0 可以是 html 代码,比如 `
    ...
    `。 - 这里不讨论上面的这样的组件结构是否是最优的、是否应该是用“结构 directive”等等,只以实现这组标签的写法为努力方向。 我们希望这组标签呈现的效果是: @@ -184,18 +184,18 @@ export class TlAccordionComponent { - `@ContentChildren(TlAccordionPanelComponent) private panels: QueryList`:在 app.component.html 里,我们看到,每个 panel 都是 accordion 的 contentChild,所以这里用 ContentChildren 来获取所有 panel 实例,得到一个 QueryList,这个 QueryList 有与 Array 类似的方法,如 filter、map等等。 - `private lastExpandedAtPanel: TlAccordionPanelComponent`:这个记录上一个展开着的 panel 实例。 - `ngAfterContentInit`:因为我们使用 Subject 向 accordion 传送数据,subscribe 之后不用做其他操作,所以只要在 ngAfterContentInit 运行一次就可以了。 -- `this.lastExpandedAtPanel = ...`:我们获取初始化 template 中的 expanded panel。(如果同时设置多于一个 `[expanded]="true"`,需要额外处理) -- 我们有一个 panel 的 QueryList(类似 Array),map 到panel.stateRxx,就是 `[panel0, panel1] => [panel0.stateRxx, panel1.stateRxx]`。 -- 然后将所有 stateRxx 用 Observable.merge 合并。 +- `this.lastExpandedAtPanel = ...`:我们获取初始化 template 中的 expanded panel。(如果在 template 中同时设置多于一个 `[expanded]="true"`,需要额外处理,比如发送 warning) +- 我们有一个包含了所有 panel 的 QueryList(类似 Array),将其 map 到panel.stateRxx,就是 `[panel0, panel1] => [panel0.stateRxx, panel1.stateRxx]`。 +- 然后将所有 stateRxx 用 Observable.merge 合并,即 `Observable.merge(...panelStateRxxArr)`。这里用到了 ES6 的[展开运算符]。 - 每次点击 `.card-header`(即title),都会推送一个 PanelState,我们只关心那些包含 `expanded === true`的 PanelState。使用 `Observable.prototype.filter` 来过滤。 - 如果收到的 PanelState 中包含的 panel 与 this.lastExpandedAtPanel 中记录的不一致,将 this.lastExpandedAtPanel.expanded 设置为 false,并设置新的 this.lastExpandedAtPanel。 -- 另外,我们需要记录 subscription,并在 ngOnDestroy 是 unsubscribe 所有相关的 subscription(代码部分略去)。 +- 另外,我们需要记录 subscription,并在 ngOnDestroy 时 unsubscribe 所有相关的 subscription(代码部分略去)。 ### 实现 panel 的 disabled 属性( panel 内部解决) -如果一个 panel 的 template 上有了 `[disabled]=true`,那么这个 panel 点不开,title 灰色,而且 mouse hover 的时候显示 tooltip。有兴趣的同学可以自己试试看。 +如果一个 panel 的 template 上有了 `[disabled]=true`,那么这个 panel 点不开,title 灰色,而且 mouse hover title 的时候显示 tooltip。有兴趣的同学可以自己试试看。 ### 实现全局配置 app 内所有 accordion -比如我们需要配置 app 内所有的 accordion 都是 expandOneOnly,这里需要一个 AccordionConfig,作为 TlAccordionModule 的 provider,在 app 启动时注册这个 provider,然后在每个 TlAccordionComponent 的 constructor 里注入这个依赖,当 template 了没有注明 expandOneOnly 时,使用全局配置。大家可以参看 [ng-bootstrap/accordion src][]。 +比如我们需要配置 app 内所有的 accordion 都是 expandOneOnly,这里需要一个 TlAccordionConfig,作为 TlAccordionModule 的 provider,在 app 启动时注册这个 provider,然后在每个 TlAccordionComponent 的 constructor 里注入这个依赖,当 template 了没有注明 expandOneOnly 时,使用全局配置。大家可以参看 [ng-bootstrap/accordion src][]。 ### 添加 Amination ```html @@ -203,7 +203,16 @@ export class TlAccordionComponent { ...
    ...
    ``` -Oh, Angular ... + +```ts +// tl-accordion-panel.component.ts +@Component({ + ..., + animations: [trigger('contentState', [...])] +}) +export class TlAccordionPanelComponent {...} +``` +有需要的同学可以参考 [angular.cn 里的文档](https://angular.cn/docs/ts/latest/guide/animations.html)来实现动画效果。 ## 总结 - panel 内的问题很好解决,panel 之间的问题就要 parent (即 accordion)出面了。 From 89d95988eaa522936e3c9a5e135a0e371313fa3f Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Sun, 18 Dec 2016 20:30:50 +0800 Subject: [PATCH 127/177] minor changes on summary in index.ts --- src/app/_shared/api/articles/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 136c94a..aeefd27 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -6,7 +6,7 @@ const items: Article[] = [ { id: '使用 Angular 2、RxJS 制作简单的 Accordion 组件', title: '使用 Angular 2、RxJS 制作简单的 Accordion 组件', - summary: '受 ng-bootstrap/accordion 启发,制作一个 Accordion 组件 。', + summary: '在 ng-bootstrap/accordion 的启发下,使用 NG2、RxJS 制作一个 Accordion 组件 。', content: require('./timliu/simple-accordion/_index.md'), first: true, tags: ['Angular', 'RxJS'], From 2ed26b4215512a790fbf95b7930255c7c5cb0d00 Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Mon, 19 Dec 2016 02:11:41 +0800 Subject: [PATCH 128/177] adds 'template drive' in title --- src/app/_shared/api/articles/index.ts | 6 +-- .../timliu/simple-accordion/_index.md | 50 +++++++++++-------- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index aeefd27..2f38d43 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -4,9 +4,9 @@ import {Observable} from 'rxjs/Observable'; const items: Article[] = [ { - id: '使用 Angular 2、RxJS 制作简单的 Accordion 组件', - title: '使用 Angular 2、RxJS 制作简单的 Accordion 组件', - summary: '在 ng-bootstrap/accordion 的启发下,使用 NG2、RxJS 制作一个 Accordion 组件 。', + id: '使用 Angular 2 制作简单的 Accordion 组件 - Template Driven', + title: '使用 Angular 2 制作简单的 Accordion 组件 - Template Driven', + summary: '在 ng-bootstrap/accordion 的启发下,使用 Angular 2,以 template driven 的思路制作一个 Accordion 组件 。', content: require('./timliu/simple-accordion/_index.md'), first: true, tags: ['Angular', 'RxJS'], diff --git a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md index 2f8e178..5e8ac2f 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md @@ -1,9 +1,11 @@ -# 使用 Angular 2、RxJS 制作简单的 Accordion 组件 +# 使用 Angular 2 制作简单的 Accordion 组件 - Template Driven ## 写作原因 -练习使用 Angular 2、RxJS 制作一个简单的 Accordion 组件。 +Angular 的文档翻了一遍又一遍,还是记不住,边用边学效果会不会好一些?设个小目标吧 -- 比如,制作一个 Accordion 组件。 +我们知道,Angular 的 form 有两种:template driven form 和 model drive form(或者叫 reactive form)。组件的制作也可以参照这两种不同的思路。本篇是一个系列的上集,即使用 template driven 思路,应用 Angular 2 制作一个 Accordion 组件。下集将切换至 model driven/reactive 思路。 ## 读者指引 +- 首先剧透笔者的一个偏见:model driven 大法好。template driven 的组件除了标签一目了然以外,我个人觉得都是缺点:写起来麻烦,读起来费劲,css匹配奇怪,测试起来...(这个 spec 我还没写过)。所以,即使你对制作组件如果有兴趣,我也只建议大概看一下本文,了解“子组件向父组件推送、子组件之间的互动由父组件来协调”即可。 - 本文内容很大程度上受到下列的文章、代码的启发,有兴趣的同学可以先翻阅一下: - [Angular 2 Transclusion using ng-content][](NG1 的 Transclusion 在 NG2 里改名为 content projection) - [ng-bootstrap/accordion api][]、[源码][ng-bootstrap/accordion src] @@ -19,10 +21,16 @@ - 文章使用 angular-cli 的 [generate 指令][](简写为 `ng g`)来生成基础代码。 +- Suject 变量以 Rxx 结尾(比如 stateRxx),Observable 变量以 Rx 结尾(比如 mergedPanelStatesRx)。 + - 相应代码可以在[这个 Repo](https://github.com/rxjs-space/try-out-u/tree/master/src/app/tl-ui/tl-accordion) 找到。 ## 小目标 -我们希望有一个 accordion component,可以在 template 里这样使用: +我们希望呈现的效果是: +![页面显示](./screen-shot.png) +初始显示 title0、content0、title1;点击 title1,显示 content1,隐藏 content0;点击 title0,显示 content0,隐藏 content1。 + +这背后是一个 accordion component,可以在 template 里这样使用(不需要在 app.component.ts 里做任何事): ```html @@ -47,9 +55,6 @@ - title0 和 content0 可以是 html 代码,比如 `
    ...
    `。 - 这里不讨论上面的这样的组件结构是否是最优的、是否应该是用“结构 directive”等等,只以实现这组标签的写法为努力方向。 -我们希望这组标签呈现的效果是: -![页面显示](./screen-shot.png) -初始显示 title0、content0、title1;点击 title1,显示 content1,隐藏 content0;点击 title0,显示 content0,隐藏 content1。 ## 代码编写 @@ -66,7 +71,10 @@ ... (生成 TlAccordionPanelContentComponent) > (假设当前目录为 app)touch tl-accordion/tl-accordion.interface.ts ``` -我们需要 accordion component,但用的指令是 ng g module,即生成了 accordion module 和 accordion component。这样做的目的是预留 provider 位置(在 module 里),方便以后配置全局变量,比如要求 app 里所有的 accordion 都是怎么怎么样的(仿照 ng-bootstrap的做法)。 +然后在 TlAccordionModule 里,加上 `exports: [TlAccordionComponent]`,在 app.module 里加上 `imports: [TlAccordionModule]`,就可以开始在 app.component.html 里面使用 tl-accordion 等标签了。 + +我们需要 accordion component,但用的指令是 ng g module,即同时生成了 accordion module 和 accordion component。这样做的目的是预留 provider 位置(在 module 里),方便以后配置全局变量,比如要求 app 里所有的 accordion 都是怎么怎么样的(仿照 ng-bootstrap的做法)。 + 注:因为像 TlAccordionPanelContentComponent 这样的名字太长,后文会用最后两个词(即 content component)代替。 ### 实现 title 组件显示 title,content 组件显示 content @@ -96,7 +104,7 @@ role 和 class 是抄来的(配合 bootstrap 使用),重点是 ng-content 的 select 属性 -- select 里面是选择器,`select="tl-accordion-panel-title"` 的意思是:选择 tag 为 tl-accordion-panel-title 的元素,并将其内容放置到这个 ng-content 里面。tl-accordion-panel-content 同理。 ### 实现 click on title => toggle content ( panel 内部解决) -承接上面的 `tl-accordion-panel.component.html`,我们需要实现能够初始化是否显示 `.card-block`,而且在点击 `.card-header` 时,切换 `.card-block` 的显示。可以这样: +承接上面的 `tl-accordion-panel.component.html`,我们需要实现能够初始化是否显示 `.card-block`,并且在点击 `.card-header` 时,切换 `.card-block` 的显示。可以这样: ```typescript // tl-accordion-panel.component.ts @@ -149,7 +157,7 @@ export class TlAccordionPanelComponent { ... ``` -上面这个 `{panel: this, ...}` 里的这个 this,就是 panel 实例自身。每次点击,stateRxx 都会把这个 data 发送出去。接下来看 accordion component 的代码: + `{panel: this, ...}` 里的这个 this,就是 panel 实例自身。每次点击,stateRxx 都会把这个 data 发送出去。接下来看 accordion component 的代码: ```ts @@ -157,21 +165,21 @@ export class TlAccordionPanelComponent { export class TlAccordionComponent { @Input() public expandOneOnly: boolean = false; @ContentChildren(TlAccordionPanelComponent) private panels: QueryList; - private lastExpandedAtPanel: TlAccordionPanelComponent = null; + private lastExpandedPanel: TlAccordionPanelComponent = null; ngAfterContentInit() { if (this.expandOneOnly) { - // initialize this.lastExpandedAtPanel - this.lastExpandedAtPanel = this.panels.filter(panel => panel.expanded === true)[0]; + // initialize this.lastExpandedPanel + this.lastExpandedPanel = this.panels.filter(panel => panel.expanded === true)[0]; // subscribe to mergedPanelStatesRx const panelStateRxxArr: PanelStateRxx[] = this.panels.map(panel => panel.stateRxx); const mergedPanelStatesRx: Observable = Observable.merge(...panelStateRxxArr); const subscription = mergedPanelStatesRx - .filter(panelState => panelState.expanded === true && this.lastExpandedAtPanel !== panelState.panel) + .filter(panelState => panelState.expanded === true && this.lastExpandedPanel !== panelState.panel) .do(panelState => { - this.lastExpandedAtPanel.expanded = false; - this.lastExpandedAtPanel = panelState.panel; + this.lastExpandedPanel.expanded = false; + this.lastExpandedPanel = panelState.panel; }) .subscribe(); } @@ -182,17 +190,17 @@ export class TlAccordionComponent { 说明如下: - `@Input() public expandOneOnly: boolean`:这个就是用来控制是否只展开一个 panel 的开关,在 app.component.html 里就是 ``。 - `@ContentChildren(TlAccordionPanelComponent) private panels: QueryList`:在 app.component.html 里,我们看到,每个 panel 都是 accordion 的 contentChild,所以这里用 ContentChildren 来获取所有 panel 实例,得到一个 QueryList,这个 QueryList 有与 Array 类似的方法,如 filter、map等等。 -- `private lastExpandedAtPanel: TlAccordionPanelComponent`:这个记录上一个展开着的 panel 实例。 +- `private lastExpandedPanel: TlAccordionPanelComponent`:这个记录上一个展开着的 panel 实例。 - `ngAfterContentInit`:因为我们使用 Subject 向 accordion 传送数据,subscribe 之后不用做其他操作,所以只要在 ngAfterContentInit 运行一次就可以了。 -- `this.lastExpandedAtPanel = ...`:我们获取初始化 template 中的 expanded panel。(如果在 template 中同时设置多于一个 `[expanded]="true"`,需要额外处理,比如发送 warning) -- 我们有一个包含了所有 panel 的 QueryList(类似 Array),将其 map 到panel.stateRxx,就是 `[panel0, panel1] => [panel0.stateRxx, panel1.stateRxx]`。 -- 然后将所有 stateRxx 用 Observable.merge 合并,即 `Observable.merge(...panelStateRxxArr)`。这里用到了 ES6 的[展开运算符]。 +- `this.lastExpandedPanel = ...`:我们获取初始化 template 中的 expanded panel。(如果在 template 中同时设置多于一个 `[expanded]="true"`,需要额外处理,比如发送 warning) +- `const panelStateRxxArr`:将 panels map 到panel.stateRxx,即 `[panel0, panel1] => [panel0.stateRxx, panel1.stateRxx]`。 +- 然后将所有 stateRxx 用 Observable.merge 合并,即 `Observable.merge(...panelStateRxxArr)`。这里用到了 ES6 的[展开运算符][]。 - 每次点击 `.card-header`(即title),都会推送一个 PanelState,我们只关心那些包含 `expanded === true`的 PanelState。使用 `Observable.prototype.filter` 来过滤。 -- 如果收到的 PanelState 中包含的 panel 与 this.lastExpandedAtPanel 中记录的不一致,将 this.lastExpandedAtPanel.expanded 设置为 false,并设置新的 this.lastExpandedAtPanel。 +- 如果收到的 PanelState 中包含的 panel 与 this.lastExpandedPanel 中记录的不一致,将 this.lastExpandedPanel.expanded 设置为 false,并设置新的 this.lastExpandedPanel。 - 另外,我们需要记录 subscription,并在 ngOnDestroy 时 unsubscribe 所有相关的 subscription(代码部分略去)。 ### 实现 panel 的 disabled 属性( panel 内部解决) -如果一个 panel 的 template 上有了 `[disabled]=true`,那么这个 panel 点不开,title 灰色,而且 mouse hover title 的时候显示 tooltip。有兴趣的同学可以自己试试看。 +如果一个 panel 的 template 上有了 `[disabled]=true`,那么这个 panel 点不开,title 灰色,而且 mouse over title 的时候显示 tooltip。有兴趣的同学可以自己试试看。 ### 实现全局配置 app 内所有 accordion 比如我们需要配置 app 内所有的 accordion 都是 expandOneOnly,这里需要一个 TlAccordionConfig,作为 TlAccordionModule 的 provider,在 app 启动时注册这个 provider,然后在每个 TlAccordionComponent 的 constructor 里注入这个依赖,当 template 了没有注明 expandOneOnly 时,使用全局配置。大家可以参看 [ng-bootstrap/accordion src][]。 From c6b80f65f0d96d08521e9555cf71e312b5df1023 Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Mon, 19 Dec 2016 02:15:36 +0800 Subject: [PATCH 129/177] minor changes --- .../_shared/api/articles/timliu/simple-accordion/_index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md index 5e8ac2f..062427e 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md @@ -80,7 +80,7 @@ Angular 的文档翻了一遍又一遍,还是记不住,边用边学效果会 ### 实现 title 组件显示 title,content 组件显示 content 要显示 `This is a title.` 里的 'This is a title.',我们只需要在 title component 的 template 里写一行:``。content component 同理。完。 -### 实现 pannel 里显示 title 和 content +### 实现 pannel 组件显示 title 和 content 我们在 app.component.html 里写道: ```html @@ -129,7 +129,7 @@ export class TlAccordionPanelComponent {
    ...
    ``` -### 实现 expandOneOnly( panel 传递给 accordion 统一解决) +### 实现 expandOneOnly( panel 推送状态信息给 accordion 统一解决) 其实在完成上一步之后,这个 accordion component 已经可以用了。只是,如果我们希望 accordion 下面的 panel,在某一时间只有一个是 expanded,点开另外一个 panel 的同时,关闭之前展开的 panel,这个该如何实现呢? 我们需要 accordion component 来统一安排 panel 的显示状态: - 首先,accordion component 记录了点击之前展开着的 panel 的 id, @@ -203,7 +203,7 @@ export class TlAccordionComponent { 如果一个 panel 的 template 上有了 `[disabled]=true`,那么这个 panel 点不开,title 灰色,而且 mouse over title 的时候显示 tooltip。有兴趣的同学可以自己试试看。 ### 实现全局配置 app 内所有 accordion -比如我们需要配置 app 内所有的 accordion 都是 expandOneOnly,这里需要一个 TlAccordionConfig,作为 TlAccordionModule 的 provider,在 app 启动时注册这个 provider,然后在每个 TlAccordionComponent 的 constructor 里注入这个依赖,当 template 了没有注明 expandOneOnly 时,使用全局配置。大家可以参看 [ng-bootstrap/accordion src][]。 +比如我们需要配置 app 内所有的 accordion 都是 expandOneOnly,这里需要一个 TlAccordionConfig,作为 TlAccordionModule 的 provider,在 app 启动时注册这个 provider(或者使用 useValue 替换成别的配置),然后在每个 TlAccordionComponent 的 constructor 里注入这个依赖,当 template 里没有注明 expandOneOnly 时,使用全局配置。大家可以参看 [ng-bootstrap/accordion src][]。 ### 添加 Amination ```html From 0bfe3a68937875404ef6f58906197cf8f1abfdd8 Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Mon, 19 Dec 2016 11:03:40 +0800 Subject: [PATCH 130/177] adds links for template-d form and model-d form --- .../_shared/api/articles/timliu/simple-accordion/_index.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md index 062427e..437504b 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md @@ -2,7 +2,11 @@ ## 写作原因 Angular 的文档翻了一遍又一遍,还是记不住,边用边学效果会不会好一些?设个小目标吧 -- 比如,制作一个 Accordion 组件。 -我们知道,Angular 的 form 有两种:template driven form 和 model drive form(或者叫 reactive form)。组件的制作也可以参照这两种不同的思路。本篇是一个系列的上集,即使用 template driven 思路,应用 Angular 2 制作一个 Accordion 组件。下集将切换至 model driven/reactive 思路。 +我们知道,Angular 的 form 有两种: +- [template driven form](https://scotch.io/tutorials/using-angular-2s-template-driven-forms),几乎可以把所有的数据和逻辑(比如 validation)都放在 template 里; +- [model driven form](https://scotch.io/tutorials/using-angular-2s-model-driven-forms-with-formgroup-and-formcontrol)(或者叫 reactive form),template 很简单,数据和逻辑放在 model 里。 + +组件的制作也可以参照这两种不同的思路。本篇是一个系列的上集,即使用 template driven 思路,应用 Angular 2 制作一个 Accordion 组件。下集将切换至 model driven/reactive 思路。 ## 读者指引 - 首先剧透笔者的一个偏见:model driven 大法好。template driven 的组件除了标签一目了然以外,我个人觉得都是缺点:写起来麻烦,读起来费劲,css匹配奇怪,测试起来...(这个 spec 我还没写过)。所以,即使你对制作组件如果有兴趣,我也只建议大概看一下本文,了解“子组件向父组件推送、子组件之间的互动由父组件来协调”即可。 From b4efaca5145a18e8c8b026e49d844a09d490aa48 Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Mon, 19 Dec 2016 11:06:11 +0800 Subject: [PATCH 131/177] minor fix --- src/app/_shared/api/articles/timliu/simple-accordion/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md index 437504b..7998301 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md @@ -6,7 +6,7 @@ Angular 的文档翻了一遍又一遍,还是记不住,边用边学效果会 - [template driven form](https://scotch.io/tutorials/using-angular-2s-template-driven-forms),几乎可以把所有的数据和逻辑(比如 validation)都放在 template 里; - [model driven form](https://scotch.io/tutorials/using-angular-2s-model-driven-forms-with-formgroup-and-formcontrol)(或者叫 reactive form),template 很简单,数据和逻辑放在 model 里。 -组件的制作也可以参照这两种不同的思路。本篇是一个系列的上集,即使用 template driven 思路,应用 Angular 2 制作一个 Accordion 组件。下集将切换至 model driven/reactive 思路。 +组件的制作也可以参照这两种不同的思路。本篇是一个系列的上集,即按照 template driven 思路,应用 Angular 2 制作一个 Accordion 组件。下集将切换至 model driven/reactive 思路。 ## 读者指引 - 首先剧透笔者的一个偏见:model driven 大法好。template driven 的组件除了标签一目了然以外,我个人觉得都是缺点:写起来麻烦,读起来费劲,css匹配奇怪,测试起来...(这个 spec 我还没写过)。所以,即使你对制作组件如果有兴趣,我也只建议大概看一下本文,了解“子组件向父组件推送、子组件之间的互动由父组件来协调”即可。 From 7dfbfad1e357b6ed18b8070b675ad9e2dcb6d5f6 Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Mon, 19 Dec 2016 11:08:59 +0800 Subject: [PATCH 132/177] minor fix --- src/app/_shared/api/articles/timliu/simple-accordion/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md index 7998301..b5baf18 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md @@ -25,7 +25,7 @@ Angular 的文档翻了一遍又一遍,还是记不住,边用边学效果会 - 文章使用 angular-cli 的 [generate 指令][](简写为 `ng g`)来生成基础代码。 -- Suject 变量以 Rxx 结尾(比如 stateRxx),Observable 变量以 Rx 结尾(比如 mergedPanelStatesRx)。 +- 变量命名:Suject 变量以 Rxx 结尾(比如 stateRxx),Observable 变量以 Rx 结尾(比如 mergedPanelStatesRx)。 - 相应代码可以在[这个 Repo](https://github.com/rxjs-space/try-out-u/tree/master/src/app/tl-ui/tl-accordion) 找到。 From 97fdac0ed2d1a69e883193afb6072750d360899b Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Mon, 19 Dec 2016 11:45:43 +0800 Subject: [PATCH 133/177] refactors explanation block for TlAccordionComponent --- .../timliu/simple-accordion/_index.md | 74 +++++++++++-------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md index b5baf18..50d32bf 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md @@ -57,7 +57,7 @@ Angular 的文档翻了一遍又一遍,还是记不住,边用边学效果会 - tl 是前缀,前缀可以是随便什么。 - expandedOneOnly 和 expanded 这两个属性写在 template 里是用来初始化的,后面具体说明其功能。 - title0 和 content0 可以是 html 代码,比如 `
    ...
    `。 -- 这里不讨论上面的这样的组件结构是否是最优的、是否应该是用“结构 directive”等等,只以实现这组标签的写法为努力方向。 +- 这里不讨论上面的这样的组件结构是否是最优的、是否应该使用“结构 directive”等等,只以实现这组标签的写法为努力方向。 ## 代码编写 @@ -139,20 +139,22 @@ export class TlAccordionPanelComponent { - 首先,accordion component 记录了点击之前展开着的 panel 的 id, - 在点击某个 title 以后,被点击的 panel 展开,并向 accordion component 发送状态数据,数据中包含 panel 的 id, - accordion component 对比 id,如果 id 不同,accordion component 指示之前展开的 panel 收起,并记录新的展开着的 panel 的 id。 -这个 id 是什么呢?在 template 里没有设置啊?我们可以用 panel 实例来作为 panel 实例的 id。看代码: +这个 id 是什么呢?我们可以用 panel 实例来作为 panel 实例的 id。看代码: ```typescript // tl-accordion.interface.ts +// 点击 title 时,向外推送一个数据,长这样: export interface PanelState { - panel: TlAccordionPanelComponent; // 我为自己带盐 + panel: TlAccordionPanelComponent; expanded: boolean; } -export type PanelStateRxx = Subject; // 这个会在 tl-accordion.component.ts 里面用到 +// 下面这个是个中间状态,会在 tl-accordion.component.ts 里面用到 +export type PanelStateRxx = Subject; // tl-accordion-panel.component.ts export class TlAccordionPanelComponent { ... - stateRxx: Subject = new Subject(); + stateRxx: Subject = new Subject(); // 点击 title,触发 stateRxx.next(...) } ``` @@ -161,8 +163,9 @@ export class TlAccordionPanelComponent { ... ``` - `{panel: this, ...}` 里的这个 this,就是 panel 实例自身。每次点击,stateRxx 都会把这个 data 发送出去。接下来看 accordion component 的代码: - + `{panel: this, ...}` 里的这个 this,就是 panel 实例自身(我为自己带盐)。每次点击,stateRxx 都会把这个 data 发送出去。 + + 接下来看 accordion component 的代码: ```ts // tl-accordion.component.ts @@ -174,34 +177,38 @@ export class TlAccordionComponent { ngAfterContentInit() { if (this.expandOneOnly) { // initialize this.lastExpandedPanel - this.lastExpandedPanel = this.panels.filter(panel => panel.expanded === true)[0]; - - // subscribe to mergedPanelStatesRx - const panelStateRxxArr: PanelStateRxx[] = this.panels.map(panel => panel.stateRxx); - const mergedPanelStatesRx: Observable = Observable.merge(...panelStateRxxArr); - const subscription = mergedPanelStatesRx - .filter(panelState => panelState.expanded === true && this.lastExpandedPanel !== panelState.panel) - .do(panelState => { - this.lastExpandedPanel.expanded = false; - this.lastExpandedPanel = panelState.panel; - }) - .subscribe(); +/*lx01*/ this.lastExpandedPanel = this.panels.filter(panel => panel.expanded === true)[0]; + + // subscribe to mergedPanelStatesRx +/*lx02*/ const panelStateRxxArr: PanelStateRxx[] = this.panels.map(panel => panel.stateRxx); +/*lx03*/ const mergedPanelStatesRx: Observable = Observable.merge(...panelStateRxxArr); + const subscription = mergedPanelStatesRx +/*lx04*/ .filter(panelState => panelState.expanded === true && this.lastExpandedPanel !== panelState.panel) + .do(panelState => { +/*lx05*/ this.lastExpandedPanel.expanded = false; +/*lx06*/ this.lastExpandedPanel = panelState.panel; + }) +/*lx07*/ .subscribe(); } } } ``` -说明如下: -- `@Input() public expandOneOnly: boolean`:这个就是用来控制是否只展开一个 panel 的开关,在 app.component.html 里就是 ``。 -- `@ContentChildren(TlAccordionPanelComponent) private panels: QueryList`:在 app.component.html 里,我们看到,每个 panel 都是 accordion 的 contentChild,所以这里用 ContentChildren 来获取所有 panel 实例,得到一个 QueryList,这个 QueryList 有与 Array 类似的方法,如 filter、map等等。 -- `private lastExpandedPanel: TlAccordionPanelComponent`:这个记录上一个展开着的 panel 实例。 -- `ngAfterContentInit`:因为我们使用 Subject 向 accordion 传送数据,subscribe 之后不用做其他操作,所以只要在 ngAfterContentInit 运行一次就可以了。 -- `this.lastExpandedPanel = ...`:我们获取初始化 template 中的 expanded panel。(如果在 template 中同时设置多于一个 `[expanded]="true"`,需要额外处理,比如发送 warning) -- `const panelStateRxxArr`:将 panels map 到panel.stateRxx,即 `[panel0, panel1] => [panel0.stateRxx, panel1.stateRxx]`。 -- 然后将所有 stateRxx 用 Observable.merge 合并,即 `Observable.merge(...panelStateRxxArr)`。这里用到了 ES6 的[展开运算符][]。 -- 每次点击 `.card-header`(即title),都会推送一个 PanelState,我们只关心那些包含 `expanded === true`的 PanelState。使用 `Observable.prototype.filter` 来过滤。 -- 如果收到的 PanelState 中包含的 panel 与 this.lastExpandedPanel 中记录的不一致,将 this.lastExpandedPanel.expanded 设置为 false,并设置新的 this.lastExpandedPanel。 -- 另外,我们需要记录 subscription,并在 ngOnDestroy 时 unsubscribe 所有相关的 subscription(代码部分略去)。 +说明如下: + +1. accordion component 的属性: + - `expandOneOnly`:这个就是用来控制是否只展开一个 panel 的开关,在 app.component.html 里就是 ``。 + - `panels`:在 app.component.html 里,我们看到,每个 panel 都是 accordion 的 ContentChild,所以这里用 ContentChildren 来获取所有 panel 实例,得到一个 QueryList,这个 QueryList 有与 Array 类似的方法,如 filter、map等等。 + - `lastExpandedPanel`:这个记录上一个展开着的 panel 实例。 +2. accordion component 的方法: + - `ngAfterContentInit`:因为我们使用 Subject 向 accordion 传送数据,subscribe 之后不用做其他操作,所以只要在 ngAfterContentInit 运行一次就可以了。 + - lx01:我们获取初始化 template 中的 expanded panel。(如果在 template 中同时设置多于一个 `[expanded]="true"`,需要额外处理,比如发送 warning) + - lx02:将 panels map 到panel.stateRxx,即 `[panel0, panel1] => [panel0.stateRxx, panel1.stateRxx]`。 + - lx03:然后将所有 stateRxx 合并,即 `Observable.merge(...panelStateRxxArr)`。这里用到了 ES6 的[展开运算符][]。 + - lx04:每次点击 `.card-header`(即title),都会推送一个 PanelState,我们只关心那些包含 `expanded === true` 的 PanelState。使用 `Observable.prototype.filter` 来过滤。 + - lx04 + lx05 + lx06:如果收到的 PanelState 中包含的 panel 与 '上一个展开着的 panel' 不一致,闭合 '上一个展开着的 panel',并重置 '上一个展开着的 panel' 。 + - lx07:使用 `Observable.prototype.subscribe` 方法启动 Observable 运行。 + - 另外,我们需要记录 subscription,并在 ngOnDestroy 时 unsubscribe 所有相关的 subscription(代码部分略去)。 ### 实现 panel 的 disabled 属性( panel 内部解决) 如果一个 panel 的 template 上有了 `[disabled]=true`,那么这个 panel 点不开,title 灰色,而且 mouse over title 的时候显示 tooltip。有兴趣的同学可以自己试试看。 @@ -224,11 +231,14 @@ export class TlAccordionComponent { }) export class TlAccordionPanelComponent {...} ``` -有需要的同学可以参考 [angular.cn 里的文档](https://angular.cn/docs/ts/latest/guide/animations.html)来实现动画效果。 +有需要的同学可以参考 [angular.cn 里 animation 的文档](https://angular.cn/docs/ts/latest/guide/animations.html)来实现动画效果。 + +### 测试 +(挠头...) ## 总结 - panel 内的问题很好解决,panel 之间的问题就要 parent (即 accordion)出面了。 -- panel 向 parent 传递信息,借助 RxJS/Subject,并以 panel 实例作为自己的 id (为自己带盐)。 +- panel 向 parent 传递信息,借助 RxJS/Subject,并以 panel 实例作为自己的 id。 最后顺便提一句:ng-bootstrap/accordion 的实现大量使用了 templateRef 和 ngTemplateOutlet,检查 panel 状态用的是 ngAfterContentChecked 这个钩子,没有用到 RxJS。 From 83d0459245c5edb9c15a4c985975388e04a8cf2a Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Mon, 19 Dec 2016 11:53:56 +0800 Subject: [PATCH 134/177] more minor fixes --- .../timliu/simple-accordion/_index.md | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md index 50d32bf..ff1953d 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md @@ -120,9 +120,7 @@ export class TlAccordionPanelComponent { ```html - - ... - +... ``` 点击切换就是: @@ -192,18 +190,17 @@ export class TlAccordionComponent { } } } - ``` 说明如下: 1. accordion component 的属性: - `expandOneOnly`:这个就是用来控制是否只展开一个 panel 的开关,在 app.component.html 里就是 ``。 - `panels`:在 app.component.html 里,我们看到,每个 panel 都是 accordion 的 ContentChild,所以这里用 ContentChildren 来获取所有 panel 实例,得到一个 QueryList,这个 QueryList 有与 Array 类似的方法,如 filter、map等等。 - - `lastExpandedPanel`:这个记录上一个展开着的 panel 实例。 + - `lastExpandedPanel`:这个指向 '上一个展开着的 panel'。 2. accordion component 的方法: - `ngAfterContentInit`:因为我们使用 Subject 向 accordion 传送数据,subscribe 之后不用做其他操作,所以只要在 ngAfterContentInit 运行一次就可以了。 - lx01:我们获取初始化 template 中的 expanded panel。(如果在 template 中同时设置多于一个 `[expanded]="true"`,需要额外处理,比如发送 warning) - - lx02:将 panels map 到panel.stateRxx,即 `[panel0, panel1] => [panel0.stateRxx, panel1.stateRxx]`。 + - lx02:将 panels 'map 成' panel.stateRxx,即 `[panel0, panel1] => [panel0.stateRxx, panel1.stateRxx]`。 - lx03:然后将所有 stateRxx 合并,即 `Observable.merge(...panelStateRxxArr)`。这里用到了 ES6 的[展开运算符][]。 - lx04:每次点击 `.card-header`(即title),都会推送一个 PanelState,我们只关心那些包含 `expanded === true` 的 PanelState。使用 `Observable.prototype.filter` 来过滤。 - lx04 + lx05 + lx06:如果收到的 PanelState 中包含的 panel 与 '上一个展开着的 panel' 不一致,闭合 '上一个展开着的 panel',并重置 '上一个展开着的 panel' 。 @@ -211,7 +208,7 @@ export class TlAccordionComponent { - 另外,我们需要记录 subscription,并在 ngOnDestroy 时 unsubscribe 所有相关的 subscription(代码部分略去)。 ### 实现 panel 的 disabled 属性( panel 内部解决) -如果一个 panel 的 template 上有了 `[disabled]=true`,那么这个 panel 点不开,title 灰色,而且 mouse over title 的时候显示 tooltip。有兴趣的同学可以自己试试看。 +如果有 `...`,那么这个 panel 点不开,title 灰色,而且 mouse over title 的时候显示 tooltip。有兴趣的同学可以自己试试看。 ### 实现全局配置 app 内所有 accordion 比如我们需要配置 app 内所有的 accordion 都是 expandOneOnly,这里需要一个 TlAccordionConfig,作为 TlAccordionModule 的 provider,在 app 启动时注册这个 provider(或者使用 useValue 替换成别的配置),然后在每个 TlAccordionComponent 的 constructor 里注入这个依赖,当 template 里没有注明 expandOneOnly 时,使用全局配置。大家可以参看 [ng-bootstrap/accordion src][]。 @@ -219,16 +216,11 @@ export class TlAccordionComponent { ### 添加 Amination ```html -... -
    ...
    +...
    ...
    ``` - ```ts // tl-accordion-panel.component.ts -@Component({ - ..., - animations: [trigger('contentState', [...])] -}) +@Component({..., animations: [trigger('contentState', [...])]}) export class TlAccordionPanelComponent {...} ``` 有需要的同学可以参考 [angular.cn 里 animation 的文档](https://angular.cn/docs/ts/latest/guide/animations.html)来实现动画效果。 From f357ac3a115543a431272f7b7a7c4240314554a6 Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Mon, 19 Dec 2016 12:04:52 +0800 Subject: [PATCH 135/177] more minor fixes --- .../timliu/simple-accordion/_index.md | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md index ff1953d..2d9a979 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md @@ -161,7 +161,7 @@ export class TlAccordionPanelComponent { ... ``` - `{panel: this, ...}` 里的这个 this,就是 panel 实例自身(我为自己带盐)。每次点击,stateRxx 都会把这个 data 发送出去。 + `{panel: this, ...}` 里的这个 this,就是 panel 实例自身(我为自己带盐)。每次点击,stateRxx 都会把这个 PanelState 发送出去。 接下来看 accordion component 的代码: @@ -193,19 +193,19 @@ export class TlAccordionComponent { ``` 说明如下: -1. accordion component 的属性: +- accordion component 的属性: - `expandOneOnly`:这个就是用来控制是否只展开一个 panel 的开关,在 app.component.html 里就是 ``。 - `panels`:在 app.component.html 里,我们看到,每个 panel 都是 accordion 的 ContentChild,所以这里用 ContentChildren 来获取所有 panel 实例,得到一个 QueryList,这个 QueryList 有与 Array 类似的方法,如 filter、map等等。 - `lastExpandedPanel`:这个指向 '上一个展开着的 panel'。 -2. accordion component 的方法: - - `ngAfterContentInit`:因为我们使用 Subject 向 accordion 传送数据,subscribe 之后不用做其他操作,所以只要在 ngAfterContentInit 运行一次就可以了。 - - lx01:我们获取初始化 template 中的 expanded panel。(如果在 template 中同时设置多于一个 `[expanded]="true"`,需要额外处理,比如发送 warning) - - lx02:将 panels 'map 成' panel.stateRxx,即 `[panel0, panel1] => [panel0.stateRxx, panel1.stateRxx]`。 - - lx03:然后将所有 stateRxx 合并,即 `Observable.merge(...panelStateRxxArr)`。这里用到了 ES6 的[展开运算符][]。 - - lx04:每次点击 `.card-header`(即title),都会推送一个 PanelState,我们只关心那些包含 `expanded === true` 的 PanelState。使用 `Observable.prototype.filter` 来过滤。 - - lx04 + lx05 + lx06:如果收到的 PanelState 中包含的 panel 与 '上一个展开着的 panel' 不一致,闭合 '上一个展开着的 panel',并重置 '上一个展开着的 panel' 。 - - lx07:使用 `Observable.prototype.subscribe` 方法启动 Observable 运行。 - - 另外,我们需要记录 subscription,并在 ngOnDestroy 时 unsubscribe 所有相关的 subscription(代码部分略去)。 +- accordion component 的方法: + - `ngAfterContentInit`:因为我们使用 Subject 向 accordion 推送数据,subscribe 之后不用做其他操作,所以只要在 ngAfterContentInit 运行一次就可以了。 + lx01:我们获取初始化 template 中的 expanded panel。(如果在 template 中同时设置多于一个 `[expanded]="true"`,需要额外处理,比如发送 warning) + lx02:将 panels 'map 成' panel.stateRxx,即 `[panel0, panel1] => [panel0.stateRxx, panel1.stateRxx]`。 + lx03:然后将所有 stateRxx 合并,即 `Observable.merge(...panelStateRxxArr)`。这里用到了 ES6 的[展开运算符][]。 + lx04:每次点击 `.card-header`(即title),都会推送一个 PanelState,我们只关心那些包含 `expanded === true` 的 PanelState。使用 `Observable.prototype.filter` 来过滤。 + lx04 + lx05 + lx06:如果收到的 PanelState 中包含的 panel 与 '上一个展开着的 panel' 不一致,闭合 '上一个展开着的 panel',并重置 '上一个展开着的 panel' 。 + lx07:使用 `Observable.prototype.subscribe` 方法启动 Observable 运行。 + - `ngOnDestroy`:另外,我们需要记录 subscription,并在 component destroy 时 unsubscribe 所有相关的 subscription(代码部分略去)。 ### 实现 panel 的 disabled 属性( panel 内部解决) 如果有 `...`,那么这个 panel 点不开,title 灰色,而且 mouse over title 的时候显示 tooltip。有兴趣的同学可以自己试试看。 From 9e15920fc0bd16cb7f9eb8a7557687193b13220a Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Mon, 19 Dec 2016 12:18:42 +0800 Subject: [PATCH 136/177] more minor fixes --- .../timliu/simple-accordion/_index.md | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md index 2d9a979..99de1cc 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md @@ -198,20 +198,20 @@ export class TlAccordionComponent { - `panels`:在 app.component.html 里,我们看到,每个 panel 都是 accordion 的 ContentChild,所以这里用 ContentChildren 来获取所有 panel 实例,得到一个 QueryList,这个 QueryList 有与 Array 类似的方法,如 filter、map等等。 - `lastExpandedPanel`:这个指向 '上一个展开着的 panel'。 - accordion component 的方法: - - `ngAfterContentInit`:因为我们使用 Subject 向 accordion 推送数据,subscribe 之后不用做其他操作,所以只要在 ngAfterContentInit 运行一次就可以了。 - lx01:我们获取初始化 template 中的 expanded panel。(如果在 template 中同时设置多于一个 `[expanded]="true"`,需要额外处理,比如发送 warning) - lx02:将 panels 'map 成' panel.stateRxx,即 `[panel0, panel1] => [panel0.stateRxx, panel1.stateRxx]`。 - lx03:然后将所有 stateRxx 合并,即 `Observable.merge(...panelStateRxxArr)`。这里用到了 ES6 的[展开运算符][]。 - lx04:每次点击 `.card-header`(即title),都会推送一个 PanelState,我们只关心那些包含 `expanded === true` 的 PanelState。使用 `Observable.prototype.filter` 来过滤。 - lx04 + lx05 + lx06:如果收到的 PanelState 中包含的 panel 与 '上一个展开着的 panel' 不一致,闭合 '上一个展开着的 panel',并重置 '上一个展开着的 panel' 。 - lx07:使用 `Observable.prototype.subscribe` 方法启动 Observable 运行。 - - `ngOnDestroy`:另外,我们需要记录 subscription,并在 component destroy 时 unsubscribe 所有相关的 subscription(代码部分略去)。 + - `ngAfterContentInit`:因为我们使用 Subject 向 accordion 推送数据,subscribe 之后不用做其他操作,所以只要在 ngAfterContentInit 运行一次就可以了。 + lx01行:我们获取初始化 template 中的 expanded panel。(如果在 template 中同时设置多于一个 `[expanded]="true"`,需要额外处理,比如发送 warning) + lx02行:将 panels 'map 成' panel.stateRxx,即 `[panel0, panel1] => [panel0.stateRxx, panel1.stateRxx]`。 + lx03行:然后将所有 stateRxx 合并,即 `Observable.merge(...panelStateRxxArr)`。这里用到了 ES6 的[展开运算符][]。 + lx04行:每次点击 `.card-header`(即title),都会推送一个 PanelState,我们只关心那些包含 `expanded === true` 的 PanelState。使用 `Observable.prototype.filter` 来过滤。 + lx04 + lx05 + lx06行:如果收到的 PanelState 中包含的 panel 与 '上一个展开着的 panel' 不一致,收起 '上一个展开着的 panel',并重置 '上一个展开着的 panel' 。 + lx07行:使用 `Observable.prototype.subscribe` 方法启动 Observable 运行。 + - `ngOnDestroy`:另外,我们需要记录 subscriptions 列表,并在 component destroy 时 unsubscribe 所有相关的 subscriptions。(代码部分略去) ### 实现 panel 的 disabled 属性( panel 内部解决) -如果有 `...`,那么这个 panel 点不开,title 灰色,而且 mouse over title 的时候显示 tooltip。有兴趣的同学可以自己试试看。 +如果有 `...`,那么这个 panel 点不开,title 灰色,而且 mouse over title 的时候显示 tooltip。(代码部分略去) ### 实现全局配置 app 内所有 accordion -比如我们需要配置 app 内所有的 accordion 都是 expandOneOnly,这里需要一个 TlAccordionConfig,作为 TlAccordionModule 的 provider,在 app 启动时注册这个 provider(或者使用 useValue 替换成别的配置),然后在每个 TlAccordionComponent 的 constructor 里注入这个依赖,当 template 里没有注明 expandOneOnly 时,使用全局配置。大家可以参看 [ng-bootstrap/accordion src][]。 +比如我们需要配置 app 内所有的 accordion 都是 expandOneOnly,这里需要一个 TlAccordionConfig,作为 TlAccordionModule 的 provider,在 app 启动时注册这个 provider(或者使用 useValue 替换成别的配置),然后在每个 TlAccordionComponent 的 constructor 里注入这个依赖,当 template 里没有注明 expandOneOnly 时,使用全局配置。大家可以参看 [ng-bootstrap/accordion src][]。(代码部分略去) ### 添加 Amination ```html @@ -230,9 +230,9 @@ export class TlAccordionPanelComponent {...} ## 总结 - panel 内的问题很好解决,panel 之间的问题就要 parent (即 accordion)出面了。 -- panel 向 parent 传递信息,借助 RxJS/Subject,并以 panel 实例作为自己的 id。 +- panel 向 parent 推送信息,借助 RxJS/Subject,并以 panel 实例作为自己的 id。 -最后顺便提一句:ng-bootstrap/accordion 的实现大量使用了 templateRef 和 ngTemplateOutlet,检查 panel 状态用的是 ngAfterContentChecked 这个钩子,没有用到 RxJS。 +顺便提一句:ng-bootstrap/accordion 大量使用了 templateRef 和 ngTemplateOutlet,检查 panel 状态用的是 ngAfterContentChecked 这个钩子,没有用到 RxJS。 ## 参考 - [Angular 2 Transclusion using ng-content][] From fffbf96037ff32f0f145afef4e610dfec3262db9 Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Mon, 19 Dec 2016 13:04:36 +0800 Subject: [PATCH 137/177] minor fix --- src/app/_shared/api/articles/timliu/simple-accordion/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md index 99de1cc..652cfca 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md @@ -9,7 +9,7 @@ Angular 的文档翻了一遍又一遍,还是记不住,边用边学效果会 组件的制作也可以参照这两种不同的思路。本篇是一个系列的上集,即按照 template driven 思路,应用 Angular 2 制作一个 Accordion 组件。下集将切换至 model driven/reactive 思路。 ## 读者指引 -- 首先剧透笔者的一个偏见:model driven 大法好。template driven 的组件除了标签一目了然以外,我个人觉得都是缺点:写起来麻烦,读起来费劲,css匹配奇怪,测试起来...(这个 spec 我还没写过)。所以,即使你对制作组件如果有兴趣,我也只建议大概看一下本文,了解“子组件向父组件推送、子组件之间的互动由父组件来协调”即可。 +- 首先剧透笔者的一个偏见:model driven 大法好。template driven 的组件除了标签一目了然以外,我个人觉得都是缺点:写起来麻烦,读起来费劲,css匹配奇怪,测试起来...(这个 spec 我还没写过)。所以,即使你对制作组件有兴趣,我也只建议大概看一下本文,了解“子组件向父组件推送、子组件之间的互动由父组件来协调”即可。 - 本文内容很大程度上受到下列的文章、代码的启发,有兴趣的同学可以先翻阅一下: - [Angular 2 Transclusion using ng-content][](NG1 的 Transclusion 在 NG2 里改名为 content projection) - [ng-bootstrap/accordion api][]、[源码][ng-bootstrap/accordion src] From 3bcec942884f6585633cfc146291fe2f7f66c104 Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Mon, 19 Dec 2016 13:17:10 +0800 Subject: [PATCH 138/177] adds link between requirement and codes --- .../articles/timliu/simple-accordion/_index.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md index 652cfca..263c158 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md @@ -134,10 +134,9 @@ export class TlAccordionPanelComponent { ### 实现 expandOneOnly( panel 推送状态信息给 accordion 统一解决) 其实在完成上一步之后,这个 accordion component 已经可以用了。只是,如果我们希望 accordion 下面的 panel,在某一时间只有一个是 expanded,点开另外一个 panel 的同时,关闭之前展开的 panel,这个该如何实现呢? 我们需要 accordion component 来统一安排 panel 的显示状态: -- 首先,accordion component 记录了点击之前展开着的 panel 的 id, -- 在点击某个 title 以后,被点击的 panel 展开,并向 accordion component 发送状态数据,数据中包含 panel 的 id, -- accordion component 对比 id,如果 id 不同,accordion component 指示之前展开的 panel 收起,并记录新的展开着的 panel 的 id。 -这个 id 是什么呢?我们可以用 panel 实例来作为 panel 实例的 id。看代码: +- 需求一:accordion component 记录了点击之前展开着的 panel 的 id, +- 需求二:在点击某个 title 以后,被点击的 panel 展开,并向 accordion component 发送状态数据,数据中包含 panel 的 id, +- 需求三:accordion component 对比 id,如果 id 不同,accordion component 指示之前展开的 panel 收起,并记录新的展开着的 panel 的 id。这个 id 是什么呢?我们可以用 panel 实例来作为 panel 实例的 id。看代码: ```typescript // tl-accordion.interface.ts @@ -161,9 +160,9 @@ export class TlAccordionPanelComponent { ... ``` - `{panel: this, ...}` 里的这个 this,就是 panel 实例自身(我为自己带盐)。每次点击,stateRxx 都会把这个 PanelState 发送出去。 +这部分对应上面的“需求二”。 `{panel: this, ...}` 里的这个 this,就是 panel 实例自身(我为自己带盐)。每次点击,stateRxx 都会把这个 PanelState 发送出去。 - 接下来看 accordion component 的代码: +接下来看 accordion component 的代码: ```ts // tl-accordion.component.ts @@ -196,14 +195,14 @@ export class TlAccordionComponent { - accordion component 的属性: - `expandOneOnly`:这个就是用来控制是否只展开一个 panel 的开关,在 app.component.html 里就是 ``。 - `panels`:在 app.component.html 里,我们看到,每个 panel 都是 accordion 的 ContentChild,所以这里用 ContentChildren 来获取所有 panel 实例,得到一个 QueryList,这个 QueryList 有与 Array 类似的方法,如 filter、map等等。 - - `lastExpandedPanel`:这个指向 '上一个展开着的 panel'。 + - `lastExpandedPanel`:对应“需求一”,指向 '上一个展开着的 panel'。 - accordion component 的方法: - `ngAfterContentInit`:因为我们使用 Subject 向 accordion 推送数据,subscribe 之后不用做其他操作,所以只要在 ngAfterContentInit 运行一次就可以了。 - lx01行:我们获取初始化 template 中的 expanded panel。(如果在 template 中同时设置多于一个 `[expanded]="true"`,需要额外处理,比如发送 warning) + lx01行:对应“需求一”,我们获取初始化 template 中的 expanded panel。(如果在 template 中同时设置多于一个 `[expanded]="true"`,需要额外处理,比如发送 warning) lx02行:将 panels 'map 成' panel.stateRxx,即 `[panel0, panel1] => [panel0.stateRxx, panel1.stateRxx]`。 lx03行:然后将所有 stateRxx 合并,即 `Observable.merge(...panelStateRxxArr)`。这里用到了 ES6 的[展开运算符][]。 lx04行:每次点击 `.card-header`(即title),都会推送一个 PanelState,我们只关心那些包含 `expanded === true` 的 PanelState。使用 `Observable.prototype.filter` 来过滤。 - lx04 + lx05 + lx06行:如果收到的 PanelState 中包含的 panel 与 '上一个展开着的 panel' 不一致,收起 '上一个展开着的 panel',并重置 '上一个展开着的 panel' 。 + lx04 + lx05 + lx06行:对应“需求三”,如果收到的 PanelState 中包含的 panel 与 '上一个展开着的 panel' 不一致,收起 '上一个展开着的 panel',并重置 '上一个展开着的 panel' 。 lx07行:使用 `Observable.prototype.subscribe` 方法启动 Observable 运行。 - `ngOnDestroy`:另外,我们需要记录 subscriptions 列表,并在 component destroy 时 unsubscribe 所有相关的 subscriptions。(代码部分略去) From 642dc3b0d9da781526f3b4f70d78351e6523a8a9 Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Mon, 19 Dec 2016 13:18:03 +0800 Subject: [PATCH 139/177] minor fix --- .../_shared/api/articles/timliu/simple-accordion/_index.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md index 263c158..d1745b3 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md @@ -136,7 +136,9 @@ export class TlAccordionPanelComponent { 我们需要 accordion component 来统一安排 panel 的显示状态: - 需求一:accordion component 记录了点击之前展开着的 panel 的 id, - 需求二:在点击某个 title 以后,被点击的 panel 展开,并向 accordion component 发送状态数据,数据中包含 panel 的 id, -- 需求三:accordion component 对比 id,如果 id 不同,accordion component 指示之前展开的 panel 收起,并记录新的展开着的 panel 的 id。这个 id 是什么呢?我们可以用 panel 实例来作为 panel 实例的 id。看代码: +- 需求三:accordion component 对比 id,如果 id 不同,accordion component 指示之前展开的 panel 收起,并记录新的展开着的 panel 的 id。 + +这个 id 是什么呢?我们可以用 panel 实例来作为 panel 实例的 id。看代码: ```typescript // tl-accordion.interface.ts From 3f1cc7a1e3df4c7e00849ce8db831421b387c192 Mon Sep 17 00:00:00 2001 From: lhtin Date: Mon, 19 Dec 2016 13:23:06 +0800 Subject: [PATCH 140/177] adjust articles order --- src/app/_shared/api/articles/index.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 4f1480e..7d3e517 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -3,16 +3,6 @@ import {Article} from '../../models/article'; import {Observable} from 'rxjs/Observable'; const items: Article[] = [ - { - id: 'Angular 的版本号与发布周期', - title: 'Angular 的版本号与发布周期', - summary: '本文摘译了 Angular 官方博客中关于版本号与发布周期的内容。', - content: require('./timliu/angular-versioning/_index.md'), - first: true, - translation: true, - tags: ['Angular', 'semver'], - authors: ['timliu'], - }, { id: 'Angular2中的StructuralDirective', title: 'Angular 2 中的 Sturctural Directive', @@ -23,6 +13,16 @@ const items: Article[] = [ tags: ['ng2', 'Structural Directive'], authors: ['trotyl'], }, + { + id: 'Angular 的版本号与发布周期', + title: 'Angular 的版本号与发布周期', + summary: '本文摘译了 Angular 官方博客中关于版本号与发布周期的内容。', + content: require('./timliu/angular-versioning/_index.md'), + first: true, + translation: true, + tags: ['Angular', 'semver'], + authors: ['timliu'], + }, { id: '单例模式与Angular', title: '单例模式与Angular', From 6484b3e57dc70275eb13305218b41502215358bb Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Mon, 19 Dec 2016 20:59:18 +0800 Subject: [PATCH 141/177] minor fix --- src/app/_shared/api/articles/timliu/simple-accordion/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md index d1745b3..97f62c1 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md @@ -57,7 +57,7 @@ Angular 的文档翻了一遍又一遍,还是记不住,边用边学效果会 - tl 是前缀,前缀可以是随便什么。 - expandedOneOnly 和 expanded 这两个属性写在 template 里是用来初始化的,后面具体说明其功能。 - title0 和 content0 可以是 html 代码,比如 `
    ...
    `。 -- 这里不讨论上面的这样的组件结构是否是最优的、是否应该使用“结构 directive”等等,只以实现这组标签的写法为努力方向。 +- 这里不讨论上面的这样的组件结构是否是最优的、是否应该使用 attribute directive 等等,只以实现这组标签的写法为努力方向。 ## 代码编写 From 23f68c611b979066f60eaa35b80c9d13b27319c5 Mon Sep 17 00:00:00 2001 From: xiedapao <846432362@qq.com> Date: Mon, 19 Dec 2016 23:10:30 +0800 Subject: [PATCH 142/177] =?UTF-8?q?=E5=8A=A0=E5=85=A5web=E5=AE=89=E5=85=A8?= =?UTF-8?q?=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 39 ++++++++++++++++-- .../pic.png" | Bin 0 -> 82272 bytes 2 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 "src/app/_shared/api/articles/231.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256\357\274\210\344\270\212\347\257\207\347\273\255\357\274\211/pic.png" diff --git "a/src/app/_shared/api/articles/231.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256\357\274\210\344\270\212\347\257\207\347\273\255\357\274\211/_index.md" "b/src/app/_shared/api/articles/231.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256\357\274\210\344\270\212\347\257\207\347\273\255\357\274\211/_index.md" index 8ea126c..528fa9a 100644 --- "a/src/app/_shared/api/articles/231.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256\357\274\210\344\270\212\347\257\207\347\273\255\357\274\211/_index.md" +++ "b/src/app/_shared/api/articles/231.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256\357\274\210\344\270\212\347\257\207\347\273\255\357\274\211/_index.md" @@ -20,13 +20,14 @@ ├── protractor.conf.js ├── README.md ├── src // 项目主入口 +├── e2e +├── test ├── .stylelintrc ├── tools // 共用工具类,里面主要管理gulp不同任务脚本,以及依赖的一些第三方库管理,还包括自己写一些.d.ts声明文件 ├── tsconfig.json ├── tslint.json ├── yarn.lock -├── 代码规范V2 -└── 测试修改方法.MD +├── 代码规范V2.MD ``` 看完上面罗列的只是一级目录(ps:大家可以自己用tree -L 1等命令,查看自己的项目目录结构),其中一些大家都是可以通用的。 @@ -65,4 +66,36 @@ │   ``` -app.component作为组件树,首当其冲放在应用根目录下。项目里默认在app.component放置路由插座,也包括一些 +app.component作为组件树顶级,首当其冲放在应用根目录下。项目里默认在app.component放置路由插座,也包括一些共用的sidebar和toolbar或者tabbar。大概构成整个web app的骨架。main目录则是我们应用主入口。对于shared资源共享目录,特地把共用的组件、服务工厂、pipe全部封装到SharedModule里。 +利用Angular模块的特性,我想用你把你这个模块import进来就行。不用额外去找我想要的组件或者服务工厂一一导入进来。当然SharedModule会面临一个越来越臃肿的问题,随着项目变大,我们可以把这个再进行下一拆分成多个小的Module,职能划分更加清楚。 +对于单个功能如何如何去命名规范,其实Angular官方已经有很好的风格指南===》[传送门](https://www.angular.cn/docs/ts/latest/guide/style-guide.html),对于单一功能主要有Module,Router,Component,Service,Model组成,一个大的功能也是由这些小的模块组成。其实module隔离性确实不错,有时担心某一模块的css会不会影响其他模块,其实不必担心。当然如果是*{}全局就另当别论了。 +```bash +. +├── index.ts +├── pay.module.ts +├── pay-router.component.ts +├── pay.routes.ts +├── qrcode +│   ├── index.ts +│   ├── qrcode-show.component.html +│   ├── qrcode-show.component.scss +│   └── qrcode-show.component.ts +├── shared +│   ├── index.ts +│   ├── product.model.ts +│   └── wx-pay.service.ts +``` +为了让其他功能引用多个该目录指定函数, 对象或者基础类型,为了代码看上去更加清爽,如下面 +```typescript +import { a, b, c, d } from '../shared/index'; +``` +在每个目录定义一个index.ts,导出该目录下的函数, 对象或者基础类型 +```typescript +export * from './a.model'; +``` + +## Web安全 +先上图: + +![事例](./pic.png) +对于运营商的劫持注入,大家应该都见过。这种方法最快的解决方案是把网站升级为https,还是http的朋友建议尽快升级为https,chrome对http默认视为不安全网站 diff --git "a/src/app/_shared/api/articles/231.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256\357\274\210\344\270\212\347\257\207\347\273\255\357\274\211/pic.png" "b/src/app/_shared/api/articles/231.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256\357\274\210\344\270\212\347\257\207\347\273\255\357\274\211/pic.png" new file mode 100644 index 0000000000000000000000000000000000000000..0d0ebc07de8b017582bf84bdd14ae624f995aa54 GIT binary patch literal 82272 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≫HXX7sS7ou@QynU@22E(4r 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 Date: Wed, 21 Dec 2016 12:40:26 +0800 Subject: [PATCH 143/177] adds bootstrap.scss --- .../_shared/api/articles/timliu/simple-accordion/_index.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md index 97f62c1..12792c8 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md @@ -65,6 +65,8 @@ Angular 的文档翻了一遍又一遍,还是记不住,边用边学效果会 ### 脚手架搭建(生成基础代码) 我们需要的 component 包括:accordion、panel、panel-title、panel-content,另外还需要一个 interface 文件。 ``` +> ng new my-awesome-package --style=scss +> cd my-awesome-package > ng g module tl-accordion ... (生成 TlAccordionModule 以及 TlAccordionComponent) > ng g component tl-accordion/tl-accordion-panel @@ -81,6 +83,11 @@ Angular 的文档翻了一遍又一遍,还是记不住,边用边学效果会 注:因为像 TlAccordionPanelContentComponent 这样的名字太长,后文会用最后两个词(即 content component)代替。 +### 引入 bootstrap.scss +本文参考 ng-bootstrap,使用 bootstrap 4 的样式。 +- 敲指令:`npm install bootstrap@4.0.0-alpha.5 -S`; +- 在 `my-awesome-package\src\styles.scss` 中添加 `@import 'http://github.com/~bootstrap/scss/bootstrap.scss';`。 + ### 实现 title 组件显示 title,content 组件显示 content 要显示 `This is a title.` 里的 'This is a title.',我们只需要在 title component 的 template 里写一行:``。content component 同理。完。 From b3afdab732908174f4cd3717766b438b6ad96d6c Mon Sep 17 00:00:00 2001 From: angular-x <737590527@qq.com> Date: Wed, 21 Dec 2016 16:20:32 +0800 Subject: [PATCH 144/177] =?UTF-8?q?=E6=8A=95=E7=A8=BF=20=E3=80=8AGDD?= =?UTF-8?q?=E5=A4=A7=E4=BC=9AAngular2=E4=BC=98=E7=A7=80=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=A1=88=E4=BE=8B-=E4=BB=BB=E6=84=8F=E9=97=A8=E3=80=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 110 ++++++++++++++++++ src/app/_shared/api/articles/index.ts | 9 ++ .../api/authors/280.\346\230\223sense.md" | 5 + .../authors/_images/\346\230\223sense.jpg" | Bin 0 -> 64408 bytes src/app/_shared/api/authors/index.ts | 9 ++ 5 files changed, 133 insertions(+) create mode 100644 "src/app/_shared/api/articles/310.GDD\345\244\247\344\274\232Angular2\344\274\230\347\247\200\351\241\271\347\233\256\346\241\210\344\276\213-\344\273\273\346\204\217\351\227\250/_index.md" create mode 100644 "src/app/_shared/api/authors/280.\346\230\223sense.md" create mode 100644 "src/app/_shared/api/authors/_images/\346\230\223sense.jpg" diff --git "a/src/app/_shared/api/articles/310.GDD\345\244\247\344\274\232Angular2\344\274\230\347\247\200\351\241\271\347\233\256\346\241\210\344\276\213-\344\273\273\346\204\217\351\227\250/_index.md" "b/src/app/_shared/api/articles/310.GDD\345\244\247\344\274\232Angular2\344\274\230\347\247\200\351\241\271\347\233\256\346\241\210\344\276\213-\344\273\273\346\204\217\351\227\250/_index.md" new file mode 100644 index 0000000..f035f94 --- /dev/null +++ "b/src/app/_shared/api/articles/310.GDD\345\244\247\344\274\232Angular2\344\274\230\347\247\200\351\241\271\347\233\256\346\241\210\344\276\213-\344\273\273\346\204\217\351\227\250/_index.md" @@ -0,0 +1,110 @@ +##任意门项目背景## + +---------- + +VR(即虚拟现实科技)打造的360度全景视效,是一种全新的视觉体验。“VR,可以完美且生动地复现‘现场’和‘全貌’,为观者带来全新生动的第一视角沉浸式感官体验。 + +民宿有别于旅馆或饭店,是结合了当地人文、自然景观、生态、环境资源的新兴型态,由于民宿具有强烈的个性化特征,较好的体验感,备受游客关注。 + +真正去过民宿的游客,都会有个感觉,这里通过照片甚至普通的视频没法全面展示,去过才知道,只有身临其境才能体验出民宿的精髓。 + +通过VR技术,消费者自由自主地选择观看视角,可轻松、全面地了解民宿的特色优势、硬件配套,所见即所得,从这点上来说,VR和民宿是天作之合。 + + + +##任意门的目标## + +---------- + +任意门将民宿预定平台与VR技术结合,旨在让旅客在订房前,通过沉浸式体验,可身临其境,轻松、全面地了解民宿的特色。 + +##项目技术框架及实现## + +---------- + +###技术选型### + + +- angular2 + + 使用angular2作为该前端框架缘由,社区早有讨论: + + [https://www.zhihu.com/question/38989845](https://www.zhihu.com/question/38989845 "vue、react和angular 2.x谁是2016年的主流?") + + [http://sanwen8.cn/p/2226GkX.html](http://sanwen8.cn/p/2226GkX.html "作为前端,我为什么选择 Angular 2?") + + 但是,有句古话:“任凭弱水三千 我只取一瓢饮”。 + +- bootstrap3 + + 前端样式库 + +- webpack + + 项目打包工具 + +- Cardborad + + 3D眼镜(Goolgle) + +- Matterport + + 模型扫描平台 + +###项目结构划分### + +![项目结构](http://upload-images.jianshu.io/upload_images/2433010-dfa20ed0ffbf49cf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +> 注:文件定义规则基本按照官方风格进行命名; + +###项目中主要难点及解决方案### + +- #### 懒加载(lazy load) #### + + 懒加载按照官方配置基本可以满足要求: + + [https://www.angular.cn/docs/ts/latest/guide/ngmodule.html](https://www.angular.cn/docs/ts/latest/guide/ngmodule.html "惰性加载模块") + +- #### 预编译(aot) #### + + 开发时在`JIT`环境上便于开发,打包发布时建议采用`AOT`编译,当然个人觉得更好的还是`server render`。 + + [https://www.angular.cn/docs/ts/latest/cookbook/aot-compiler.html](https://www.angular.cn/docs/ts/latest/cookbook/aot-compiler.html "预 (AOT) 编译器") + +- #### i18n国际化(ng2-translate) #### + + 因为个人有相关的国际化json文件,所以该项目倒是没采用官方给出的国际化方案, + + 这是github社区提供的一个不错i18n方案。 + + [https://github.com/ocombe/ng2-translate](https://github.com/ocombe/ng2-translate) + +- #### 测试(protractor) #### + + Protractor 是 Angular 团队构建的一个端对端的测试运行工具,模拟用户交互,帮助你验证你的Angular应用的运行状况。 + + [http://www.protractortest.org/](http://www.protractortest.org/) + +- #### 项目打包工具(webpack) #### + + 官方推荐webpack,当然社区里面也看到有人使用webpack+gulp组合打包。 + + @AngularClass [https://github.com/AngularClass/angular2-webpack-starter](https://github.com/AngularClass/angular2-webpack-starter) + +当然,在项目实际开发中会有许多问题,大部分都有做整理,可以看看我个人的文章及我们团队的博客: + +个人技术文档: + +[http://www.jianshu.com/users/d0244c5326c5/latest_articles](http://www.jianshu.com/users/d0244c5326c5/latest_articles "个人技术文档") + +唯幻科技技术博客: + +[http://blog.arvix.cn/blog/category/arvix-tech/](http://blog.arvix.cn/blog/category/arvix-tech/) + +## 项目运行地址 ## + +---------- + +[http://www.ostay.cn](http://www.ostay.cn "任意门") + +![唯幻科技官方微信](http://upload-images.jianshu.io/upload_images/2433010-b01bde508595a06c.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 7d3e517..f08976a 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -3,6 +3,15 @@ import {Article} from '../../models/article'; import {Observable} from 'rxjs/Observable'; const items: Article[] = [ + { + id: 'GDD大会Angular2优秀项目案例-任意门', + title: 'GDD大会Angular2优秀项目案例-任意门', + summary: '本文主要介绍了GDD大会上angular2优秀案例-任意门,其中包含了任意门开发中遇到的一些重难点。', + content: require('./310.GDD大会Angular2优秀项目案例-任意门/_index.md'), + first: true, + tags: ['Angular2','项目实例'], + authors: ['易sense'], + }, { id: 'Angular2中的StructuralDirective', title: 'Angular 2 中的 Sturctural Directive', diff --git "a/src/app/_shared/api/authors/280.\346\230\223sense.md" "b/src/app/_shared/api/authors/280.\346\230\223sense.md" new file mode 100644 index 0000000..2acc603 --- /dev/null +++ "b/src/app/_shared/api/authors/280.\346\230\223sense.md" @@ -0,0 +1,5 @@ +- angular程序员 + +- 前端\摄影\篮球 + +- [个人主页](http://www.jianshu.com/users/d0244c5326c5/latest_articles) diff --git "a/src/app/_shared/api/authors/_images/\346\230\223sense.jpg" "b/src/app/_shared/api/authors/_images/\346\230\223sense.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..49fe1b923361203bbedc9582fe72ce47aa9dd2d8 GIT binary patch literal 64408 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

    b-vx@q+ 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 literal 0 HcmV?d00001 diff --git a/src/app/_shared/api/authors/index.ts b/src/app/_shared/api/authors/index.ts index 669debe..3220efd 100644 --- a/src/app/_shared/api/authors/index.ts +++ b/src/app/_shared/api/authors/index.ts @@ -87,6 +87,15 @@ const items: Author[] = [ columnist: false, homepage: 'http://www.jianshu.com/users/d614825bc8a1/latest_articles' }, + { + id: '易sense', + name: '易sense', + bio: '一生中可以喜欢很多人,但心疼的只有一个', + description: require('./280.易sense.md'), + avatar: require('./_images/易sense.jpg'), + columnist: false, + homepage: 'http://www.jianshu.com/users/d0244c5326c5/latest_articles' + } ]; @Injectable() From 4feb70ab6b7d682ad12e6368a03e9610bdb87efc Mon Sep 17 00:00:00 2001 From: Trotyl Date: Thu, 22 Dec 2016 00:44:32 +0800 Subject: [PATCH 145/177] Add article: ng-container introduction. --- .../310.ng-container introduction/_index.md | 127 ++++++++++++++++++ src/app/_shared/api/articles/index.ts | 10 ++ 2 files changed, 137 insertions(+) create mode 100644 src/app/_shared/api/articles/310.ng-container introduction/_index.md diff --git a/src/app/_shared/api/articles/310.ng-container introduction/_index.md b/src/app/_shared/api/articles/310.ng-container introduction/_index.md new file mode 100644 index 0000000..858239e --- /dev/null +++ b/src/app/_shared/api/articles/310.ng-container introduction/_index.md @@ -0,0 +1,127 @@ +# ng-container 简介 + +写在前面: + ++ 如无特殊说明,本文中所有 Angular 均指代 Angular 2+ 版本。 + +在 Angular 中,我们经常可以见到类似于如下的代码: + +```html + + + ... + + +``` + +这里我们可以见到一个特殊的元素名:`ng-container`。那么,这个 `ng-container` 到底是一个什么样的东西,起着什么样的作用呢? + + +## What is ng-container? + +`ng-container` 既不是一个 Component,也不是一个 Directive,只是单纯的一个特殊 tag。 + +这点类似于 `template`,Angular 复用了 HTML5 规范中 `template` 的 tag 的语义,不过并没有真正利用其实现,因此在审查元素中是永远也找不到一个 `template` 元素的。 + +不过,由于 `ng-container` 并不是 HTML5 中的,为了保持区分度,采用了 `ng-` 作为前缀。所以现在我们可以知道,`ng-container` 是 Angular 所定义的一个特殊 tag。 + + +## What does ng-container do? + +我们可以先简单尝试一下在模版中使用 `ng-container`,类似于: + +```html +

    + +

    This is paragraph 1.

    +

    This is paragraph 2.

    +
    +
    +``` + +*运行效果可以参见[在线示例1](http://embed.plnkr.co/bjiLdGS8XhGpgeFoCZEW/)。* + +我们可能会对运行结果很惊讶,因为渲染出来的实际内容仅仅是: + +```html +
    +

    This is paragraph 1.

    +

    This is paragraph 2.

    +
    +``` + +我们可能会感到一些失望,因为除了 `ng-container` 不见了之外,什么事情都没有发生。 + +没错,这就是 `ng-container` 所具备的唯一功能:不存在的功能。(注意断句) + + +## Why we need ng-container? + +上面我们说到,`ng-container` 唯一的功能就是让自己消失,那么它到底有着什么样的应用场景呢? + +对于接触过 AngularJS 1.x 的童鞋来说,会知道 Directive 有一个 `multiElement` 属性,能够使得其并不应用在某个特定元素上,而是应用在某一段元素集合的范围中。 + +*万一有不知道的可以参考 [AngularJS 1.x 的 API](https://docs.angularjs.org/api/ng/service/$compile#-multielement-)。* + +一个最常用的例子就是 ngRepeat,可以 `ng-repeat-start` 和 `ng-repeat-end` 来重复多个元素(并且不使用额外元素包装),类似于: + +```html +
      +
    • {{ book.name }}
    • +
    • {{ book.author }}
    • +
    • {{ book.price }}
    • +
    +``` + +这里,假设我们要求 `li` 必须是 `ul` 的直接子节点,而每个循环项又需要具备多个 `li` 节点,这是我们就可以使用 multiElement 的方式,直接匹配一个连续的元素集合。 + +而在 Angular 2+ 中,我们直接使用 selector 来指定 Directive 的宿主,而 selector 是没有进行区域选择的功能的,于是不能使用类似于 AngularJS 1.x 的方式来实现这个操作。 + +不过,选择我们有一个好消息,我们有一个永远都不会真实存在的 tag,也就是 `ng-container`,我们可以利用这一点来实现我们的需求: + +```html +
      + +
    • {{ book.title }}
    • +
    • {{ book.author }}
    • +
    • {{ book.price }}
    • +
      +
    +``` + +*运行效果可以参见[在线示例2](http://embed.plnkr.co/pAJ2xSaVSZtiXsigBfVK/)。* + +虽然看起来我们使用了 `ng-container` 进行了包装,但是由于其永远不存在的特性,`ul` 下面的节点就直接是 `li` 节点了,于是我们可以直接把循环项展开为多个元素。 + +另一个 AngularJS 1.x 中常见的场景是在同一级元素上同时使用 ngIf 和 ngRepeat,类似于: + +```html +
    +

    {{ item.name }}

    +
    +``` + +虽然从实现上而言这种做法是完全不必要的,但是由于书写上的简便性仍然受到大量使用。 + +而在 Angular 2+ 中,正如我们在 [Structural Directive](https://wx.angular.cn/library/article/Angular2%E4%B8%AD%E7%9A%84StructuralDirective) 中所介绍的那样,从翻译规则上就可以确定一个元素上绝不可能同时使用多个星号语法糖。 + +而有了 `ng-container` 这个不存在的包装元素之后,我们就实现同样的效果: + +```html +
    + +

    + {{ item.name }} +

    +
    +
    +``` + +*运行效果可以参见[在线示例3](http://embed.plnkr.co/hR3FbldJ3Jd4A3VCEHXk/)。* + +这样就可以不借助包装元素同时使用 ngFor 和 ngIf 了,并且逻辑层次上也更加清晰。 + + +## 总结 + +"不存在的功能" 也是一个相当强大的功能的哦,千万不要小看它。 diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 7d3e517..1555076 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -3,6 +3,16 @@ import {Article} from '../../models/article'; import {Observable} from 'rxjs/Observable'; const items: Article[] = [ + { + id: 'ng-container introduction', + title: 'ng-container 简介', + summary: 'Angular 2 的模版中,有一系列特殊的存在,ng-container 就是其中之一,在本文中将会进行简要介绍', + content: require('./310.ng-container introduction/_index.md'), + first: true, + column: 'trotyl', + tags: ['ng2'], + authors: ['trotyl'], + }, { id: 'Angular2中的StructuralDirective', title: 'Angular 2 中的 Sturctural Directive', From aa917662a5b1f870fcec54c8c06fa45c5bda0ce5 Mon Sep 17 00:00:00 2001 From: Trotyl Date: Thu, 22 Dec 2016 09:27:44 +0800 Subject: [PATCH 146/177] Fix typo. --- .../api/articles/310.ng-container introduction/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/_shared/api/articles/310.ng-container introduction/_index.md b/src/app/_shared/api/articles/310.ng-container introduction/_index.md index 858239e..d811b80 100644 --- a/src/app/_shared/api/articles/310.ng-container introduction/_index.md +++ b/src/app/_shared/api/articles/310.ng-container introduction/_index.md @@ -77,7 +77,7 @@ 而在 Angular 2+ 中,我们直接使用 selector 来指定 Directive 的宿主,而 selector 是没有进行区域选择的功能的,于是不能使用类似于 AngularJS 1.x 的方式来实现这个操作。 -不过,选择我们有一个好消息,我们有一个永远都不会真实存在的 tag,也就是 `ng-container`,我们可以利用这一点来实现我们的需求: +不过,现在我们有一个好消息,我们有一个永远都不会真实存在的 tag,也就是 `ng-container`,我们可以利用这一点来实现我们的需求: ```html
      From ecd9f4bca8c42d0cc7e8992f8948c7f85248fb18 Mon Sep 17 00:00:00 2001 From: angular-x <737590527@qq.com> Date: Thu, 22 Dec 2016 10:38:14 +0800 Subject: [PATCH 147/177] add chat.jpg --- .../_index.md" | 2 +- .../chat.jpg" | Bin 0 -> 15976 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 "src/app/_shared/api/articles/310.GDD\345\244\247\344\274\232Angular2\344\274\230\347\247\200\351\241\271\347\233\256\346\241\210\344\276\213-\344\273\273\346\204\217\351\227\250/chat.jpg" diff --git "a/src/app/_shared/api/articles/310.GDD\345\244\247\344\274\232Angular2\344\274\230\347\247\200\351\241\271\347\233\256\346\241\210\344\276\213-\344\273\273\346\204\217\351\227\250/_index.md" "b/src/app/_shared/api/articles/310.GDD\345\244\247\344\274\232Angular2\344\274\230\347\247\200\351\241\271\347\233\256\346\241\210\344\276\213-\344\273\273\346\204\217\351\227\250/_index.md" index f035f94..1eb90e9 100644 --- "a/src/app/_shared/api/articles/310.GDD\345\244\247\344\274\232Angular2\344\274\230\347\247\200\351\241\271\347\233\256\346\241\210\344\276\213-\344\273\273\346\204\217\351\227\250/_index.md" +++ "b/src/app/_shared/api/articles/310.GDD\345\244\247\344\274\232Angular2\344\274\230\347\247\200\351\241\271\347\233\256\346\241\210\344\276\213-\344\273\273\346\204\217\351\227\250/_index.md" @@ -107,4 +107,4 @@ VR(即虚拟现实科技)打造的360度全景视效,是一种全新的视觉 [http://www.ostay.cn](http://www.ostay.cn "任意门") -![唯幻科技官方微信](http://upload-images.jianshu.io/upload_images/2433010-b01bde508595a06c.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) +![唯幻科技官方微信](./chat.jpg) diff --git "a/src/app/_shared/api/articles/310.GDD\345\244\247\344\274\232Angular2\344\274\230\347\247\200\351\241\271\347\233\256\346\241\210\344\276\213-\344\273\273\346\204\217\351\227\250/chat.jpg" "b/src/app/_shared/api/articles/310.GDD\345\244\247\344\274\232Angular2\344\274\230\347\247\200\351\241\271\347\233\256\346\241\210\344\276\213-\344\273\273\346\204\217\351\227\250/chat.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..4aa67f538b64c0391200925c378da646270f7b58 GIT binary patch literal 15976 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

      qNLQ1ZaC(f;^*TF= zp9mp(yyfz>+)zIk#uz@)h+XqnqP%Z3#=ceRqT8hL1syb$Te^@Kb8oOD!3c*-@Xs{V zx8}sm8Z(f6M)7tUrq%9nCB*AK-fQ}-%|hqNA~DAw_i$lRL1Q8ocDHUAH05RM(CTQ& zT0frtIg8yjFgUk^lDK-xvq@_~LXYx$7tLZjnSqsVrKSrOYjwDvn*1w*^|~JvJ3QtHHu_!!Pbw=(f zoyy$Tbvq|0#f#75Rsg?;oTz?H8%rDr*R!EX3S2z1JrZOb{=7)_cf?i2O8sj1qPw0~ zD$(k*8Rxb=@M2E%lWd%b^g0(u$&BxZK|J;fO*CMJ`!xxvUtpblhhGY1OEH`Btj5Ey zF8>_F;R$49cGrTEye(zeI%KHh9SFmHJFt8(y|dF`PJ~cO0pNx>pn$Qe5mdHD!P6P< zK%oTLM_0Ek%{~h?(n{k=OYm%z?HwP;+s?^}|3#{ywp7;Yj0_Gxb1`0UEEKVB6k$`e zl%8(&L&SpR)p_2b0l&vgeG#9JTa0$Gx3YnqhNu0fLZTNE zBaYwx{vrQa;6&3F6xv6c)0VK(_1v813Iq?9(ZRvviBt^v9%1EoE2hd@5{q^+{>mm> zuboVo^X6xifoOy#ojEmti1A8ynYoeee;b(&5{X_w^>v+Y2`aWb%ec~oZA7Z+*h89uNa??@4|I6-Fo)_8bP7=q)Z!SMhZ2;zq=J*p`-wRn zPt&*sFX^+kFB2-hdF-X}aM2z@^Mgc6=3_yi4!6?}3f7DFn%;1;kPBIq=<&85u9x)O zQkzNU6(IsNLzc23^=%=+zG-jXr1FC+82=_5*46_=g_(t0mVk9Pm!I&P`v+$EId5g3 zC8%71CKA}nZp0*p=Ch&7b8YWCfZ7fg&;#w~FB!CEd$6Fa;ctxn-bD$!dAwg7eLoC{ zJ$c}1pF0|9Av3Vrt<-3}0P6d64oJANL337E(&!`WwtKR{>CZxxpU!V%;z%#_C>bFF zd6x`j#S0kdK0!qJ7n7W2ebZ&o1W?oV{&ZVzEjzBlZpTGf@GCXmz?>l~NZ*X2l5W2F z+1SkIk$G^^9&C^_+lw_xwKCtauKyjA)_RF}l!)bE%COF_T#s7{Aj(O$6~vgKnel;) z(>b{no(Od{>awb56;>ez&XU#Ra- z5W?4>INysIV6-ct+8y}V1^Y~M^cFcd>GeOF_BSCTuy)F#a~iK?Z1jT?o8G&mW8C8= zKk3sKrpW7JL{`HteSVaQ15xK%D^scESBy(Cf0T$%X%fuzGxYFrcOJG3@w?qJ*hjg0uBf2ug_buo$25f2E6P zzKFHSYEntDz7yzA9MB)(Ucmd5e=A2#zSFF)?t5&9#{x>fHbRrr-0+aH4pYoBZaR28 z4)7CBtF+OX-7UOKySXtJN#xPj)k}sY*XT#G`q?kmugw;G*=~$u(q~PQbPRBU_$2V9 zqnYATI{WIZSjw#DW%jX>9Yg)fzCBn97}s|=?pK!7(ox&~(0hcO%U{gf(mF{|Kz13| zg{)a3A+asz=FfHsNXuf4{Ot@tdSt^i8je^m0k&xiB7--e{|7Yzw&qbX+7+EeBVd@X z3Fj}%S82Y`xu7 zSRiEPZ!{xR`m%=4rne`Dn1`FSdD~?1B=%6-9O7 zrBl9Oy=I}}d*8W3G*J8&twU#G%b>L;>lWo=eEe;BnH3-Vam%)%S=Kh+1;Q_>v0l8s zWw-8^maSFA@bMjxj~9)SK5gLk5q|MyzTA~SKCvuW@hklZAZT{lHuj&gcwbN~Iyuq2 z1Ij2N>@fz^@$s9k=NkG~SjJ6Evg5EunFkDGmGdXt0orj*?{Z1j82?ju{yPp1t;m~1 zU1z&bZ#baD`cfz5G(ULqNQA&nZvD>b?eC;jApFU`ro zbZee*0hzg4qF?il3gnT^Cx{gCtbo(k86-wK=MrKjU9VdbM{2v@q;K1UiKTPx;*6xD zo=vp}As_Misogt?x(~cR-T6%@088iM4D@G3z?e0@Js2M!*KQz!`gVaBR>!Kck%09q zc-b7^Z;jOzAypNHY+ywAQa{XmLE4>j3I4j6J5ta310K~L%)DcnZS~zAOa$-BxX8WX z*L$!f9~^}T0*l<1%e%&y$|X8muc*MyxjblF5vWoMOnijHMXJw`!9s(OzSRgKqkJO+ zs&CLXH?8Za$__F3T;L6Zc64p%Q~QL%7O+$4ImJHuyLgK&&N8lcVVlkbQi!Rv@(I+X zM{e?86d-6XmHToJb=~3JL-{usc3Plsxt~n+J6o9873v^L^~=6X*gyII1iTl7)I;MD z$UD5o9nDR`yimT302VfMQc-bc^|2a3S(Pq4O^U!4%H5y>P|5dwr1@z=ZJA|P=Bbou zoBPNYtXP|vCY7)?o%;nGs@&qolUDg_O>ZJgbl$u{1`UGoRwI`u0djQ&=LuNPfjTxn z7Sw1E*E6V}P#6b3esT#hk9{HAo~&X^={ix_8mIJ%@qxpa>+S(wc?~a&Hsh#-0q=um z1bTnKt$3fTz8NUif3yZ>bk0G;Nb4&Sqah0nYkcM*JK0=_IQCZaX5}B-BvX6ai}q3+ zo#BE!C|kpLKD6+_nP&%f;n21IHolO;fOl^$G1}DC6<%Q!3V+$o7v0+}u0(4@VGMcX zzYMPEfkPpL97=9_>iNG%0(@SM9wq_IR4C@?Z#}=dC>ZtFPRXoR0kX0Giraq~_dmO< ztl>$h^t_H%HAw!edT%m;kxCl1UxQ5j$G;rOZ@L)D=khw#L6j_1r@Hg`_R~#MslWa&N4($jK;HLLC`7pA*qh|cuZ9(zB9%#5O zOSKl!LVaDZSo&~#*`0sE+xVU8ghm{t{yeT31I9Diwm(FVbr*0|`TFC_qi| zp+im>|91J>Fwedc?wgszL%`>+opMu@^mYfihLV5y^H1Jo?;V&Fx!g7n=8@$WkYJDi z!Ds@4LF0V>xA_SF`J$p^N3z^VVh{Gx_gsu~)yOyyuJsbPC{bf5=Q53@&$Y#Ji&Vu@ zxx8r9yF@G^?f#n&{*TrP>hF1!KpTiT1hI0>+-;m$|Lrny9WKrw?C(h|%|cJ8fn$lc z_rm~QKcJrfrD+D~3QbzHSKQ=%;JxVwb`0V(|AU1XLC{=dEP4O!ppJtEY@wS9$Eb&U zCI_H_3e>cRu`mi^xs|{8jPdtY&HvbmppXhUYTgnsN{R=WYfy7wTLx!1VAfFO$;KRP zmmna_V0B%{@xcm3*X@HEfukSnVGK)=r-O^GK;QwqT2a!TjBoqfs6vg+!Ra_y{%)QA z7fyj1Zx9e?yUhmn|INyRjS#RmkicGXeb?fi{zSg#Wm6&kQZVt!PtbhhAY8@Q{6uU> z8ajT%8cac*0W=SA;6>;+AT`L3q7fE!=6bvpRmwaSdoVVTXC4&~;{h|DjO5_Q3xkJV z2tabb#jiNntJvQh!%;tIJV85*f_5srE`g3@5B5kA^`ZAl`<|z$mUw0F7 zZkhw@TYr9Egfclwxu9*h3jF`pO);s++r^36f1*UvGO!s#R2;)6IJ;{;MtO@<9c;KE zw-As!3CYiCE_s%K54IVW?x?#W#9Oa2kRB=`G~4W*4zRz-2YoDyj}JbW1)t2~_8{R@ zqOfDSl$i6bQBM}p{vuyX8s)owS|5HeD|c)U_R4y)@M5%>kDT}VP}mm_`B6i1({GnK zxJ$3~bEq=WeHm)94U93EJXlbI1PdO%}9ZhPlaZ_uUz_xf! zMd>(~yLj^iRKk%K@4pyfCa{Tm^9k2bWY@j<{7Pt!S%iJLp*q?p1f~SX6gofEp=Y<{ zAM_2_IKw6p`micVUdR3NY+JnB>qrr|Ew;HQO5KT?LQdL=4oI38Ko_kW=B!0 zy7&u0{iBF24MS02}I*_}zz$7=Gq(_^cbXk3Cq4G>D#yBXT@a?=z znhQUH;C1n+7?V?uQJJJ6^H;}8RgP;HzKVBy72x7nRTI*BG{t92XwE+y-+z}xT`$&X z#2bo=st&lxpe|0{I5@IMZI@&;k9smnL)6u2`c19dgB*t8+UyPCfU3G!d2>R)Jh7)k zVlPff%kD3nyx{Ob*!i6ol9`JRZ>ntdNzKi?nHR2(RTFT0UGI0+{m4wqs?z@Y2j#hp z@%oynVX@0!R|vVfo>&fzqaG)1H_nHw^p8>4_SdXaZ1hKTqT_pSdgBqg8D-yW%+9J8 z@ybxBm3d3<*bFW({nE!DaVD?lrR}$uXZ#V>{NUi(nWehwJ=k>*y6969<@ox?04hF` zDT!i6`yD-4I;EJ6;|miR*td+X-=K@WC2@ncCd+dCxI*dtAhXL&=AFTz=G&}D^ZSKS z@!VVeC%bb<{KS|oYE^VKx^EqzrtsT5Kj+b;LH}owX)fXif&B||;o2QDATS~mq|7zM zCWGXv4f)S2-XxPNfvYCcp|&osv3hmp((l<`JemWj# z$kooCU^Di)H`sHENk_QWQ+v@0X&f&Qay~TFc^`@?0*BzKtqJ*Yoc-W>ZjR8?qhV*j z1fwz+#j6jJ;QJQCY`9hLvIh&hxr0aKZ4}YTe!th#<3V!&eGp}(TRZqf-amHb!mM}dxHGRo z$YCZlHgon@Ke$N$g&Qo3Qgjy$o|n<$`)3aoK=tlJ9RjU(<7h|~g@qU&+1f#wNz6bQ z0ML}Uzcw%!(+CbzGT@kwzlSPYY1eo7 zsL`B^9G=hlEPBZ08w;kTLu~w8^Vwb~e+(zTYdcw}98F8yymiG%Z4{c=3Dr^D5~#%J zrsNuL)7hAp^4=2?tbd0q&jPldk)VPYOAu2w)0&MPJVI{(EN)ceq>Lym-I5h=!x ztKp6lobU!?A&VfT5uRS#l|_Lq8?>9J93#_`!(_ly{}vGGK!w1TO#nJj?BzEb-+MYP6YQ7tbS?i| z&C_-Mcck;0e^8yBuB~~il}Ef{@@$vZtB&>IksrIh@~^Di=PX5daa>|)CI89-3!b|9 z#slT$isRiC3BOj7OzmXN^lvxpm$7;!jPWx8m?o(v|!*^FW{Q=T{DZ zWAob{-UuDAbp#4xYaTjh*|Qzjc#tOiMcbh|&e3ap6S8hCIVT4za;AAh2)Jv70jEM4 zOj1FC8H&oEk_I_e2)M@AChiOqU?D5(#8BENL~D4isLIlM zlMcfJ`tYc5wSrAtUehw2xO_~$hXIIyU)nC+(l37_D!v`I83PVS)2P=jLi}Isr1co!o(|_u7-6 zU)pXD>`SWHK6QFGuA~#cQKa*4W(^)2=J=(zRR1#BXRgW zoz&K>aThjfe>~HdOI>1X!Esl86slHwG+KNMqyjL-b3T(nV)&st7oFQBnSjdjVod9% zNu1EseYEufN!Gtws9UQatpkwMg}bohYu6qJm^`e>S|C08wB(xqFezXybmujva!>6g zBW|~?M^gsKphV)8RB(|JArsoy4D=(02m1d6(sMPa+=EE`Dd}#|J})~O<-b9^FV7Td z81fLH#Q6+ln_S)ueQq-%7IE4jp@8gcuKKpqc-BoISF;#36bvA+0Yt&05` zaNnBWkNuegILWcqZOzKPxc4!f>;RGPo_S~#glmNXuK+6gBV+*}rK=)0K?TM*P`*{0y%uWKKV+dba#H#&O&J$@-~(INK#*BKpDts&dzF;K)-bx;^ddxNjF zh*K87=zYJEi#JMo*JkG>cjl50(%bz%Uho3=K>-GVY~=P`@tz4>`AS?~y4HUTbBa0c zqCrj8QUAc-9`YvekVXXEIsBAjrgQ^C&9;xppxlT9jju~0ijl+n;RCn4AkT4>N3CTzMCq)+4>&nH<6nUd)*cg z$CUInCN^aAmW!t9#MJ5lFs?dUWF9A7O*mrAN7T^*^74kOESL<{37k*T(zLiMG!o#lMjT?J5FaPA$nFi=0lH0N1R?JrClam z2;Y!;4IX#ET+YEBKM%Uz%(&da$f3+bNi2?kUjPj0c`xFR5rL6PHEN$;YJ{OXHIhs*CbF3=qnl>L#B zk@s+SRWLv&{&VjIIMD^y;y^c6Q1&4>IXN2YfA>cS=stANAwdlioaz`1bDmOk@h4i> z)xYbjNMqC!9qW?c{Smltqp4(9S>nRBWd3)drs#9WVtkJXlzymNn5yY;E>E5uC{?o+ zb2k295sJ8jkLvC4`h`62Y<%Ji3Dk+5GrS&e)5;auTKDj9wCCGvv&NigM#(2H5>I|P z2S-M#)+#;|xl~CH?qEmSj<^aS=rQbju(9rTfzm;l`~LC>L?Rq-HRUVk$?M5A^hAUK zN_kA}CAQHGXv>6Z=9IR7^@nq+S zlN7UigBsGWu`b$8dsuT|bz<&iirY}!R#6A-ld8{J+T+x}uC~>XkKE;Pc4D||q4GWS z+TiNIjSaHbUNd3uqt=Gguj-vHX#TYLFy+3p-53jl{Ncw z{*zs5Wg^Qhn-<>U5Q+Ywos+lb)}DivstMfFoB=Dfj`Xu0tXZzl%okjF&JkY8i!LQ% zDBM|?;wSOGQf#%lIWhG8Mb>P8&GYseX9nA74Une*Y9`5?%N9F|?-$zX;hG5-EBnqo z`l7B+K|vlA$=SeoGXFF&49(d>$WZ7Wk+n`8`+7&QWuaY?NR!sW`g}he$>k?stKc?z z5WrtY=Cbj%Dv8j=AS_*MU3;*Y8?3$e?<=ZOTazC7;p_~ByRK9%MgRCrur-36h*h$% zX1S?q&X->KD%<#p4fWN2pPLo3MHw$^-(Fgbn+fHZt5y7%b+h!$=Z~6gD))nJYLneq z>hP}(IG^1u>YyL5ow>j9ZkM{&)z-TrCn@&53_-`+12;(-d1bPL8Eta&WJ10Q|&Wq3jkJcGpNP zeipl^1cc*aXk%cMWA{4g;7U zAw8Pr7i2qFBfSUXEEJrP3-IHCsSz=&^|EcAygX-o0J_>sr)~&PMz)qKWT8@As4>89w<4Qs5u0ER{zBS?B47#@y&n(SMjW<w~^XOB-@V4hq_EVEPQ-9hle7)<}LI?f#@|m=`MZJg34qxX*g|mK& zk6<^KzIfDL+k=5JFewy>c(F>OmpChT8}+sJhjQlqJ($y?-o5Wmq7(1SJmkWIc!)$4 zlxD&%Ox3=5BDTE2gBKYa730}jH)c#I5TNwq(yG_QP=~3{n63L{C_3vEPrnt2&-aSK z57%Z*I6*>--e?SOXIS5hy0?vvg4hG9sTJ`{YrYe45$*uL@-RP2@&1e9=8xvN`~q4y zEdiriSpt-J=aWj0qW%2PmoI6rL)VOX(c9x?Q_oo>xZCH8gz3PdsrgrFPSy(;BPGwL z*vH_LR}%6H;2~#n<(97Y4A$$4$t=AO&{tx>IF0ei**#mN!PI96igKTrec|x*XN0ZV zNtmx=M*mL#MBh6nE5~bCKQ8~W$g~E;j-O9VIbthV1cgD3J2dnZ;;9Ot$Yux}gRMD> zLA@5Qx7JWNv4ABSA3GM~@PlIeQP~>6I#*;sgY|H|?g_7@CO`d)OobBrh5h<a~o&fqIm zx6(d}lLxAXPc`P!G9ABARj9b1wIU~34~Xx6ouqJ0+~)F@As>NPUOic8$rZBZ+T;(o z&q4nTiD$#>LOeo3JS2ojYD&^0Mm`=Zad&Hd*lj%~Nnqmb0?CJ=ulB9aT9C~<1#vs5 zuTtmAhj=9DD9@?F?ME-yx`sJ=Q7cq-IYbCXjw437Cq+)8Z6<=@=)f$yV?E*teh3&d z-n+Y)bCOZtFGq6xG@A2Jwls;>`k}zA_O@hkIO9v_Z&i}^t><2lEq@LHtEuESuzck{ z0=Se|(|)?=m~{qZ@w1BWpKyBbhcoX4fDxgp?PoLY5lRt_HhagI)x{9i;cN>#A`by- zDnzKE<~m*rOi|3SqGm~bX{50iN);zN5q;18fjQe9R{_`^3`a-d_Rp(FhO5jTbWHMB zkF{($>q_uGeht;wP(KM2REz%aAv#~?pu!uyDibynQwcb+rt8*c7J|l#2Ht4UvuIq> z;rH%E61PcHj39ZP944atTgkK%1jhRGxrCz)eXcoaty+dX+QDO4-UTBtUZkU!q8Eexv} zn@wFrvA9rEqeYywy+syzV3Bxe>wf9x*PapAF@NxpdLnhmH`++{ch&u_1giavG(H|P zA%sfg&=nMz;M@p?{iF5UiaW?epC77BFscB;hYjM2F0DexKMB~_*po8$UvSd7jawb(!?WDK+^vQ+zpQ5d+pb_X&yC24MJe zo{f)3jbW68%+l;(R$Uv#@_zE=MEPb8w{<&}TV5CCGT=^<@KqUW1pm>oH_rG}rO5E} zYn^?qr@oyz^6{!E$xj-NdLCnVmWgd|irh$#2kVF>@$_x`WosF8>XEK;=x2W40Eb3g(x65TL-R-9r5tP=tB6 zupWU@hYzw4w(qn*6FX$VFfI)c9`L^<{f%$Z!c^guB937fzSb&FrWG!c`Kp^{en zhe3TB&2u|jnv|;BE94(CYlfOW@O{7wp)Yg)HZUXd*o&_HNG`~ozcBgp-nUs-{j<#x zk;bG)Hd;BO-BlptdstDu{`buhv=4zFCr&&lvO&ko`DD_goRIqbXMR!})+e-278ICfz6mK2Yzz0_HC@B)Xj&^UE1eAFFqxk%K-6bjPJQo z@4Yz&DipX&V!gq(O1TH;rfPVzyl^S=9Nj%3cc*aGZrBpy#9=ijmP2!~y;3~zJhyJ? z>Uu6HcH?6(e}}`)rEnYPy#*j?Q&0pBuv%_Oy}9;E43rR+s>6gJeb@mwk08V!oczpo zi|f4e=v)$TZj>-If_NJk^EOGs%Z$z`2V?f_BSF~9A@QL@!T9+5QIDDC?`8%#%ThIK zN@0uM^=PBo{%;`NI;Hp;3f$#0;k$o%fe}rwq6N?%b!%LL8aKddGaq&z6|WV2)Ck{x zZXMgD^us;^Y#0GM;qaG9sKuFr`VfxdXZt{|za#9VuLT8Y1Zy!d4+2(XLEzl*pXV2g&)x5W3%bVvU`fx^n+?nA@={w+|I6395KQ}h+!JHqf8LvN0JPK3= z>iIkte1Qb?k8!K`=oI5?l(sewj;X;3K{S)xAwT_GY9=5W@&OR0{9+KCmisLXjqp0n q$s&PIT;j(r7nuP6*IW+t6vsHfOnP>p?kS_{-#6KV&C&brefmG07ghQI literal 0 HcmV?d00001 From 8c9a607acbb1544c8e193a93ce179bb39d08b3b3 Mon Sep 17 00:00:00 2001 From: Zhicheng Wang Date: Thu, 22 Dec 2016 16:31:10 +0800 Subject: [PATCH 148/177] add license --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e9c7791 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2016 angular.cn. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. From c10e99ff16a291b7eed7b65a4f60c1ee52f9de7a Mon Sep 17 00:00:00 2001 From: Trotyl Date: Fri, 23 Dec 2016 13:40:03 +0800 Subject: [PATCH 149/177] Adjust wording. --- .../api/articles/310.ng-container introduction/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/_shared/api/articles/310.ng-container introduction/_index.md b/src/app/_shared/api/articles/310.ng-container introduction/_index.md index d811b80..8fcf258 100644 --- a/src/app/_shared/api/articles/310.ng-container introduction/_index.md +++ b/src/app/_shared/api/articles/310.ng-container introduction/_index.md @@ -101,7 +101,7 @@ ``` -虽然从实现上而言这种做法是完全不必要的,但是由于书写上的简便性仍然受到大量使用。 +虽然从实现上而言这种做法是完全不必要的,但是由于书写上的简便性仍然被大量使用。 而在 Angular 2+ 中,正如我们在 [Structural Directive](https://wx.angular.cn/library/article/Angular2%E4%B8%AD%E7%9A%84StructuralDirective) 中所介绍的那样,从翻译规则上就可以确定一个元素上绝不可能同时使用多个星号语法糖。 From e3dc8771abe79f3f5a4964446e8399bce5a93a7c Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Fri, 23 Dec 2016 17:23:38 +0800 Subject: [PATCH 150/177] [article] adds simple-hmr --- src/app/_shared/api/articles/index.ts | 9 ++ .../api/articles/timliu/simple-hmr/_index.md | 130 ++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 src/app/_shared/api/articles/timliu/simple-hmr/_index.md diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index f08976a..500bbb5 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -3,6 +3,15 @@ import {Article} from '../../models/article'; import {Observable} from 'rxjs/Observable'; const items: Article[] = [ + { + id: '在 Angular-CLI 中启用 HMR', + title: '在 Angular-CLI 中启用 HMR', + summary: '本文简单介绍如何在 Angular-CLI 搭建的 app 里启用 HMR。', + content: require('./timliu/simple-hmr/_index.md'), + first: true, + tags: ['Angular', 'HMR'], + authors: ['timliu'], + }, { id: 'GDD大会Angular2优秀项目案例-任意门', title: 'GDD大会Angular2优秀项目案例-任意门', diff --git a/src/app/_shared/api/articles/timliu/simple-hmr/_index.md b/src/app/_shared/api/articles/timliu/simple-hmr/_index.md new file mode 100644 index 0000000..0c92f07 --- /dev/null +++ b/src/app/_shared/api/articles/timliu/simple-hmr/_index.md @@ -0,0 +1,130 @@ +# 在 Angular-CLI 中启用 HMR + +## 写作原因 +关于 HMR 的功能,[Webpack wiki][] 上是这样介绍的: +> Hot Module Replacement (HMR) exchanges, adds, or removes modules while an application is running without a page reload. + +可以说,HMR 就是 “不刷新”。 +大家用 Angular-CLI 写代码的时候,每次保存,都会触发 live-reload,即代码重新编译(添删改模块),然后浏览器中页面自动刷新(相当于按了一下 F5),整个过程大概 10 秒左右。 +启用 HMR 后,这个“页面刷新”的过程(大概每次 3 至 5 秒)就被节省下来了,即相比 live-reload 节省了大概一半的时间。 +看似微不足道的时间节省,对某些如我的强迫症患者来说,真的是天上地下。 + +那么,该怎么在 Angular-CLI 在中启用 HMR 呢?本文将根据 [angularcli-hmr-example][] 来介绍 HMR 配置过程。 + +## 读者指引 +- Angular-CLI 从 1.0.0-beta.22 (2016-12-02) 开始支持 HMR 开关,参见 [CHANGELOG.md](https://github.com/angular/angular-cli/blob/master/CHANGELOG.md)。CLI 版本低的需要先升级。 +- 本篇写作思路是简单搬运,没有分析,没有解释。大家可以将本文当成一篇“一句话技巧”,说一声“朕直道了”,而后自行根据 [angularcli-hmr-example][] 来操作。 +- 非要看解释可以参考 [Webpack wiki][]。看不懂不影响使用(我是没看懂)。 +- 如果在启用 HMR 之后,你并没有感觉时间变短,可能是因为你的电脑硬件太强大,刷新页面不用思考。 + +## 搬运过程 + +### 拷贝参考代码 +``` +> git clone https://github.com/jschwarty/angularcli-hmr-example.git +``` +后面用到的代码,都在这个 repo 里。 +其实你也可以直接将这个 repo 当成 starter 来用。 + +### 安装 Angular-CLI、新建 app、添加依赖 @angularclass/hmr +``` +> npm i -g angular-cli@latest +> ng new hmr-demo +> cd hmr-demo +> npm i -D @angularclass/hmr +``` + +### 添加、修改 environments 文件并在 angular-cli.json 里注册 +在 `hmr-demo\src` 文件夹下: +- 新建 `environments\environment.dev-hmr.ts` 文件(文件名随意,在 angular-cli.json 里注册时一致即可),内容如下: + ``` + export const environment = { + production: false, + hmr: true + }; + ``` +- 更改 `environments\environment.ts` 和 `environments\environment.prod.ts`,添加 `hmr: false`。 +- 在 `angular-cli.json` 里注册 `environment.dev-hmr.ts`: + ```json + "environments": { + "dev-hmr": "environments/environment.dev-hmr.ts", + ``` + +### 添加 hmr.ts +新建 `hmr-demo\src\hmr.ts`,内容如下: + +```ts +import { NgModuleRef, ApplicationRef } from '@angular/core'; +import { createNewHosts } from '@angularclass/hmr'; + +export const hmrBootstrap = (module: any, bootstrap: () => Promise>) => { + let ngModule: NgModuleRef; + module.hot.accept(); + bootstrap().then(mod => ngModule = mod); + module.hot.dispose(() => { + let appRef: ApplicationRef = ngModule.injector.get(ApplicationRef); + let elements = appRef.components.map(c => c.location.nativeElement); + let makeVisible = createNewHosts(elements); + ngModule.destroy(); + makeVisible(); + }); +}; +``` + +### 重置 main.ts +重置 `hmr-demo\src\main.ts` 文件夹下,内容如下: + +```ts +import './polyfills.ts'; + +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { enableProdMode } from '@angular/core'; +import { environment } from './environments/environment'; +import { AppModule } from './app/'; +import { hmrBootstrap } from './hmr'; + +if (environment.production) { + enableProdMode(); +} + +const bootstrap = () => { + return platformBrowserDynamic().bootstrapModule(AppModule); +}; + +if (environment.hmr) { + if (module['hot']) { + hmrBootstrap(module, bootstrap); + } else { + console.error('HMR is not enabled for webpack-dev-server!'); + console.info('Are you using the --hmr flag for ng serve?'); + } +} else { + bootstrap(); +} +``` + +### 添加新的 npm script +修改 `hmr-demo\package.json`,添加: + +```json +"scripts": { + "hmr": "ng serve --hmr -e=dev-hmr" +``` + +### serve 起来 +``` +> npm run hmr +``` +浏览器 console 里看到:`[HMR] Waiting for update signal from WDS...`、`[WDS] Hot Module Replacement enabled.`。 +修改 app 代码,比如在 `app.component.html` 里改个字符,保存。几秒过后,浏览器里看到页面变化(没有刷新),同时 console 说:`[HMR] Updated modules: ...`。 +注意这里的 `updated modules`有7、8个,我们不是只改了一个 hmtl 吗?如果只更新一个 module 是不是会更快?该怎么做呢?再看看 [wiki][Webpack wiki]。 + + +## 总结 +估计在不久的将来,我们可以 `ng new xyz --hmr` 来完成以上操作。 + +**Happy coding!** + + +[Webpack wiki]: https://github.com/webpack/docs/wiki/hot-module-replacement-with-webpack +[angularcli-hmr-example]: https://github.com/jschwarty/angularcli-hmr-example From 75c87c6a03f24a635c487d6cc2882e42d7ec5159 Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Fri, 23 Dec 2016 17:35:10 +0800 Subject: [PATCH 151/177] minor fixes --- .../_shared/api/articles/timliu/simple-hmr/_index.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-hmr/_index.md b/src/app/_shared/api/articles/timliu/simple-hmr/_index.md index 0c92f07..5bc1dc0 100644 --- a/src/app/_shared/api/articles/timliu/simple-hmr/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-hmr/_index.md @@ -4,9 +4,9 @@ 关于 HMR 的功能,[Webpack wiki][] 上是这样介绍的: > Hot Module Replacement (HMR) exchanges, adds, or removes modules while an application is running without a page reload. -可以说,HMR 就是 “不刷新”。 -大家用 Angular-CLI 写代码的时候,每次保存,都会触发 live-reload,即代码重新编译(添删改模块),然后浏览器中页面自动刷新(相当于按了一下 F5),整个过程大概 10 秒左右。 -启用 HMR 后,这个“页面刷新”的过程(大概每次 3 至 5 秒)就被节省下来了,即相比 live-reload 节省了大概一半的时间。 +可以说,HMR 就是 “不重载”。 +大家用 Angular-CLI 写代码的时候,每次保存,都会触发 live-reload,即代码重新编译(添删改模块),然后浏览器中页面自动重载(相当于按了一下 F5),整个过程大概 10 秒左右。 +启用 HMR 后,这个“页面重载”的过程(大概每次 3 至 5 秒)就被节省下来了,即相比 live-reload 节省了大概一半的时间。 看似微不足道的时间节省,对某些如我的强迫症患者来说,真的是天上地下。 那么,该怎么在 Angular-CLI 在中启用 HMR 呢?本文将根据 [angularcli-hmr-example][] 来介绍 HMR 配置过程。 @@ -15,7 +15,7 @@ - Angular-CLI 从 1.0.0-beta.22 (2016-12-02) 开始支持 HMR 开关,参见 [CHANGELOG.md](https://github.com/angular/angular-cli/blob/master/CHANGELOG.md)。CLI 版本低的需要先升级。 - 本篇写作思路是简单搬运,没有分析,没有解释。大家可以将本文当成一篇“一句话技巧”,说一声“朕直道了”,而后自行根据 [angularcli-hmr-example][] 来操作。 - 非要看解释可以参考 [Webpack wiki][]。看不懂不影响使用(我是没看懂)。 -- 如果在启用 HMR 之后,你并没有感觉时间变短,可能是因为你的电脑硬件太强大,刷新页面不用思考。 +- 如果在启用 HMR 之后,你并没有感觉时间变短,可能是因为你的电脑硬件太强大,重载页面不用思考。 ## 搬运过程 @@ -116,12 +116,12 @@ if (environment.hmr) { > npm run hmr ``` 浏览器 console 里看到:`[HMR] Waiting for update signal from WDS...`、`[WDS] Hot Module Replacement enabled.`。 -修改 app 代码,比如在 `app.component.html` 里改个字符,保存。几秒过后,浏览器里看到页面变化(没有刷新),同时 console 说:`[HMR] Updated modules: ...`。 +修改 app 代码,比如在 `app.component.html` 里改个字符,保存。几秒过后,浏览器里看到页面变化(网页标签尚没有出现“载入中”,即 “without a page reload”),同时 console 说:`[HMR] Updated modules: ...`。 注意这里的 `updated modules`有7、8个,我们不是只改了一个 hmtl 吗?如果只更新一个 module 是不是会更快?该怎么做呢?再看看 [wiki][Webpack wiki]。 ## 总结 -估计在不久的将来,我们可以 `ng new xyz --hmr` 来完成以上操作。 +估计在不久的将来,我们可以 `ng new xyz --hmr` 来完成以上操作,或者 `ng new` 默认 hmr。 **Happy coding!** From 5db0249388baa93cc3efb70b5e3a5f6b3a8710f8 Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Fri, 23 Dec 2016 20:49:05 +0800 Subject: [PATCH 152/177] minor fixes --- src/app/_shared/api/articles/timliu/simple-hmr/_index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-hmr/_index.md b/src/app/_shared/api/articles/timliu/simple-hmr/_index.md index 5bc1dc0..063165c 100644 --- a/src/app/_shared/api/articles/timliu/simple-hmr/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-hmr/_index.md @@ -116,8 +116,8 @@ if (environment.hmr) { > npm run hmr ``` 浏览器 console 里看到:`[HMR] Waiting for update signal from WDS...`、`[WDS] Hot Module Replacement enabled.`。 -修改 app 代码,比如在 `app.component.html` 里改个字符,保存。几秒过后,浏览器里看到页面变化(网页标签尚没有出现“载入中”,即 “without a page reload”),同时 console 说:`[HMR] Updated modules: ...`。 -注意这里的 `updated modules`有7、8个,我们不是只改了一个 hmtl 吗?如果只更新一个 module 是不是会更快?该怎么做呢?再看看 [wiki][Webpack wiki]。 +修改 app 代码,比如在 `app.component.html` 里改个字符,保存。几秒过后,浏览器里看到页面变化(网页标签上没有出现“载入中”,即 “without a page reload”),同时 console 说:`[HMR] Updated modules: ...`。 +在 `updated modules`下面列出了7、8个项目,我们不是只改了一个 hmtl 吗?如果只 reload 一个 module 是不是会更快?该怎么做呢?再看看 [wiki][Webpack wiki]。 ## 总结 From 02073e8f981a5139fd172b27676b46316d4a7e2f Mon Sep 17 00:00:00 2001 From: xiedapao <846432362@qq.com> Date: Sat, 24 Dec 2016 16:47:42 +0800 Subject: [PATCH 153/177] =?UTF-8?q?=E5=AE=8C=E6=88=90web=E5=AE=89=E5=85=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git "a/src/app/_shared/api/articles/231.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256\357\274\210\344\270\212\347\257\207\347\273\255\357\274\211/_index.md" "b/src/app/_shared/api/articles/231.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256\357\274\210\344\270\212\347\257\207\347\273\255\357\274\211/_index.md" index 528fa9a..fec5458 100644 --- "a/src/app/_shared/api/articles/231.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256\357\274\210\344\270\212\347\257\207\347\273\255\357\274\211/_index.md" +++ "b/src/app/_shared/api/articles/231.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256\357\274\210\344\270\212\347\257\207\347\273\255\357\274\211/_index.md" @@ -93,9 +93,43 @@ import { a, b, c, d } from '../shared/index'; ```typescript export * from './a.model'; ``` - +这其实就是所谓的封装桶[barrel](https://www.angular.cn/docs/ts/latest/guide/glossary.html),封装桶是把多个模块的导出结果汇总到单一的 ES2015 模块的一种方式。 封装桶本身是一个 ES2015 模块文件,它重新导出选中的导出,这些导入来自其它 ES2015 模块。 ## Web安全 先上图: ![事例](./pic.png) -对于运营商的劫持注入,大家应该都见过。这种方法最快的解决方案是把网站升级为https,还是http的朋友建议尽快升级为https,chrome对http默认视为不安全网站 +对于运营商的劫持注入,大家应该都见过。这种方法最快的解决方案是把网站升级为https,还是http的朋友建议尽快升级为https,chrome对http默认视为不安全网站。 +运营商的劫持,无非放放广告,插入一些莫名其妙的广告,恶心你的用户。把网站升级为https基本解决问题了。 + +但是最可怕的是那些掌握你网站脚本漏洞的黑客,往你网站插入恶意代码,你却浑然不知。尤其是那些涉及金融的网站如比特币交易网站或者支付金融相关的。最为著名的莫过于前段时间的“抢月饼”事件,其实算不上恶意代码注入,只不过是利用脚本做了自动化的事情。但在web安全上,轰动整个圈子。 + +防范跨站脚本(XSS)攻击 +>XSS攻击 + XSS攻击类似于SQL注入攻击,攻击之前,我们先找到一个存在XSS漏洞的网站,XSS漏洞分为两种,一种是DOM Based XSS漏洞,另一种是Stored XSS漏洞。理论上,所有可输入的地方没有对输入数据进行处理的话,都会存在XSS漏洞,漏洞的危害取决于攻击代码的威力,攻击代码也不局限于script。 + -- [引用](http://blog.csdn.net/ghsau/article/details/17027893) + + +如果你想知道如何利用xss攻击,你可以看看这篇文章简单了解下[xss的原理分析与解剖](http://www.freebuf.com/articles/web/40520.html)。 + +其实xss攻击就是想方设法在你的dom里执行我想要的脚本,如下面的实现 +```html +当找不到图片名为1的文件时,执行alert('xss') +s 点击s时运行alert('xss') +

    ;L@MkU64dzg+*1^{E`y?~Wk?k^LLz@xhfm-b`99vYN(4*>==K hc(?!WucoB-;MqmvCf<(rs}kPaX_~YB1-s>;{|ke(5=j66 literal 0 HcmV?d00001 diff --git a/src/app/_shared/api/articles/timliu/angular-versioning/angular4-tentativeschedule.png b/src/app/_shared/api/articles/timliu/angular-versioning/angular4-tentativeschedule.png new file mode 100644 index 0000000000000000000000000000000000000000..e76025ac0f0c778011af6a191011410c6893ea82 GIT binary patch literal 69789 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 JSInIQ{}-$DLiYdw literal 0 HcmV?d00001 diff --git a/src/app/_shared/api/articles/timliu/angular-versioning/semver.png b/src/app/_shared/api/articles/timliu/angular-versioning/semver.png new file mode 100644 index 0000000000000000000000000000000000000000..dff9f3ee4d79dc6826beafb1374b256427aa725d GIT binary patch literal 32299 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ⅆtq@+R*$Nyt2Oyv{N_Rd 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 b`v*_GW)Wky`o=mT=W~ha?~5)ia0>oELi5F2 literal 0 HcmV?d00001 From 889979cddc3c7f0e77b62c37beb5d5dacaa5246e Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Fri, 16 Dec 2016 19:46:58 +0800 Subject: [PATCH 121/177] fixes typo --- .../_shared/api/articles/timliu/angular-versioning/_index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/angular-versioning/_index.md b/src/app/_shared/api/articles/timliu/angular-versioning/_index.md index 2f3c66c..ec216ce 100644 --- a/src/app/_shared/api/articles/timliu/angular-versioning/_index.md +++ b/src/app/_shared/api/articles/timliu/angular-versioning/_index.md @@ -9,14 +9,14 @@ 听说 Angular 要出 version 4 了。 如果你一直关注 Angular 的官方博客,一定知道 Angular 从 v2.0.0 开始已经在使用 semver 了,所以不会觉得出个 MAJOR version 有什么值得大惊小怪的。可是,version 3 哪去了? 如果你最近很忙,9月份开始就没看过 Angular 的博客,而且你正在将自己的 Angular 1 项目迁移到 Angular 2,深知迁移过程是一个...额...过程,当你听到 Angular 要出 version 4 的时候,笑 cry 吧。 -其实,大家大可不必担心 Angular 版本跟新过快。要了解 Angular 的 version 4 是怎么来的,你可以翻阅 Angular 的博客(相关文章列表在文末参考列表),或者继续阅读本文。 +其实,大家大可不必担心 Angular 版本更新过快。要了解 Angular 的 version 4 是怎么来的,你可以翻阅 Angular 的博客(相关文章列表在文末参考列表),或者继续阅读本文。 本文主要是摘译 Angular 官方博客中关于 Angular 使用 semver 以及发布计划的内容。 ## Angular 发布计划 先来看两个表: 表1,Angular 发布计划 weekly: ![angular4-tentativeschedule](./angular4-tentativeschedule.png) -大概意思就是:在2016年12月14日,我们可以拿到 v2.3.1 以及 v4.0.0-beta0。 +大概意思就是:在2016年12月14日,会发布 v2.3.1 以及 v4.0.0-beta0。 用 `npm show` 来验证一下: ``` > npm show @angular/core time From a57612806b29c98c709879542b2a04183fcabd29 Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Sat, 17 Dec 2016 15:39:30 +0800 Subject: [PATCH 122/177] fixes links --- .../api/articles/timliu/angular-versioning/_index.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/angular-versioning/_index.md b/src/app/_shared/api/articles/timliu/angular-versioning/_index.md index ec216ce..475e19a 100644 --- a/src/app/_shared/api/articles/timliu/angular-versioning/_index.md +++ b/src/app/_shared/api/articles/timliu/angular-versioning/_index.md @@ -81,9 +81,9 @@ MAJOR 版本更新时怎么办?这方面大家也不必担心,Angular Team - [Supported Public API Surface of Angular][] - [如何优雅升级ng2小版本][] -[semver]: (http://semver.org/lang/zh-CN/) -[Angular, version 2: proprioception-reinforcement]: (angularjs.blogspot.com/2016/09/angular2-final.html) -[Versioning and Releasing Angular]: (http://angularjs.blogspot.com/2016/10/versioning-and-releasing-angular.html) -[Ok... let me explain: it's going to be Angular 4.0, or just Angular]: (http://angularjs.blogspot.com/2016/12/ok-let-me-explain-its-going-to-be.html) -[Supported Public API Surface of Angular]: (https://github.com/angular/angular/blob/master/docs/PUBLIC_API.md) -[如何优雅升级ng2小版本]: (https://wx.angular.cn/library/article/%E5%A6%82%E4%BD%95%E4%BC%98%E9%9B%85%E5%8D%87%E7%BA%A7ng2%E5%B0%8F%E7%89%88%E6%9C%AC) +[semver]: http://semver.org/lang/zh-CN/ +[Angular, version 2: proprioception-reinforcement]: http://angularjs.blogspot.com/2016/09/angular2-final.html +[Versioning and Releasing Angular]: http://angularjs.blogspot.com/2016/10/versioning-and-releasing-angular.html +[Ok... let me explain: it's going to be Angular 4.0, or just Angular]: http://angularjs.blogspot.com/2016/12/ok-let-me-explain-its-going-to-be.html +[Supported Public API Surface of Angular]: https://github.com/angular/angular/blob/master/docs/PUBLIC_API.md +[如何优雅升级ng2小版本]: https://wx.angular.cn/library/article/%E5%A6%82%E4%BD%95%E4%BC%98%E9%9B%85%E5%8D%87%E7%BA%A7ng2%E5%B0%8F%E7%89%88%E6%9C%AC From f603ad7b03078de8ac40066133fff3d6135f6f91 Mon Sep 17 00:00:00 2001 From: xiedapao <846432362@qq.com> Date: Sat, 17 Dec 2016 22:52:23 +0800 Subject: [PATCH 123/177] =?UTF-8?q?=E7=BC=96=E5=86=99=E5=85=B3=E4=BA=8E?= =?UTF-8?q?=E7=9B=AE=E5=BD=95=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_index.md" | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 "src/app/_shared/api/articles/231.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256\357\274\210\344\270\212\347\257\207\347\273\255\357\274\211/_index.md" diff --git "a/src/app/_shared/api/articles/231.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256\357\274\210\344\270\212\347\257\207\347\273\255\357\274\211/_index.md" "b/src/app/_shared/api/articles/231.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256\357\274\210\344\270\212\347\257\207\347\273\255\357\274\211/_index.md" new file mode 100644 index 0000000..8ea126c --- /dev/null +++ "b/src/app/_shared/api/articles/231.\345\246\202\344\275\225\345\267\245\347\250\213\345\214\226\345\274\200\345\217\221\345\244\247\345\236\213angular2\351\241\271\347\233\256\357\274\210\344\270\212\347\257\207\347\273\255\357\274\211/_index.md" @@ -0,0 +1,68 @@ +# 如何工程化开发大型angular2项目(上篇续) +## 项目目录管理 +说到一个大的项目,随着项目越做越大。会发现目录越来越多,层级越来越深。万一哪天临时来的新同事梳理目录,够他喝一壶的了。不仅梳理困难,而且平时debug,也是够呛 +我在devtool里找我想要调试的脚本,简直是‘翻衣倒柜’。就这些花的功夫够写好几行代码了。 + +目录管理算不上啥技术活,但是管理不甚,真的会浪费大量时间效率,导致产能低下。凡是要花你超过3分钟的事情,一定要留个心眼。要不为什么说日本一些大型工程做得好,主要他们流程细节讲究精确。 + +不扯这么多,其实每个团队都会有属于适合自己的一套规则规范,别人不一定适合你,你的不一定适合别人的。我简略说说我们在协同协作的一些约定吧。 +在根目录无外乎:包依赖配置文件、代码缩进、css代码风格、ts代码风格等等一些配置文件,虽然有些零碎,但很大程度上自动得去维护我们项目一些基础规范。 +当然包括代码规范的README.MD.下面简单罗列下: +```bash +├── dist //打包输出目录 +├── .editorconfig //这个大家应该熟悉吧,具体可以访问 http://editorconfig.org +├── .gitignore +├── gulpfile.ts +├── .jshintrc +├── karma.conf.js +├── node_modules +├── package.json +├── protractor.conf.js +├── README.md +├── src // 项目主入口 +├── .stylelintrc +├── tools // 共用工具类,里面主要管理gulp不同任务脚本,以及依赖的一些第三方库管理,还包括自己写一些.d.ts声明文件 +├── tsconfig.json +├── tslint.json +├── yarn.lock +├── 代码规范V2 +└── 测试修改方法.MD + +``` +看完上面罗列的只是一级目录(ps:大家可以自己用tree -L 1等命令,查看自己的项目目录结构),其中一些大家都是可以通用的。 +其实最核心还是我们主程序这一块,我们首先按照业务来划分譬如主页、登录、关于,进一步针对面向不同角色用户的划分会员、员工、管理。如果和角色关联性再进一步把业务抽象化划分:商品、门店等等抽象化概念。当然具体到某一功能时我们依据代码模式去 +划分:例如数据模型、资源层、组件层等等。其实这些划分标准应该是自己团队同一讨论协商出来的,而且不是死的,阶段性去调整。当然大家要同一去执行,不然真的是如同虚设。 + +下面跟着我的逻辑来简单看看目录的划分: +```bash +└── client + ├── app + ├── assets + ├── css + ├── favicon.ico + ├── index.html + +``` +这里划分很简单,前端客户端目录存放资源目录,样式管理目录,业务应用目录。就不做详述了。 +```bash +├── app +│   ├── about +│   ├── app.component.e2e-spec.ts +│   ├── app.component.html +│   ├── app.component.spec.ts +│   ├── app.component.ts +│   ├── app.module.ts +│   ├── app.resolver.ts +│   ├── app.routes.ts +│   ├── home +│   ├── login +│   ├── main +│   ├── main-prod.ts +│   ├── main.ts +│   ├── rxjs-extensions.ts +│   ├── shared +│   ├── system-config.ts +│   + +``` +app.component作为组件树,首当其冲放在应用根目录下。项目里默认在app.component放置路由插座,也包括一些 From ae2dc1c2e051d31d5009c5d4cb2b6e504fd1837d Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Sun, 18 Dec 2016 18:48:22 +0800 Subject: [PATCH 124/177] [article] adds simple-accordion --- src/app/_shared/api/articles/index.ts | 9 + .../timliu/simple-accordion/_index.md | 216 ++++++++++++++++++ .../timliu/simple-accordion/screen-shot.png | Bin 0 -> 3174 bytes 3 files changed, 225 insertions(+) create mode 100644 src/app/_shared/api/articles/timliu/simple-accordion/_index.md create mode 100644 src/app/_shared/api/articles/timliu/simple-accordion/screen-shot.png diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 4f1480e..136c94a 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -3,6 +3,15 @@ import {Article} from '../../models/article'; import {Observable} from 'rxjs/Observable'; const items: Article[] = [ + { + id: '使用 Angular 2、RxJS 制作简单的 Accordion 组件', + title: '使用 Angular 2、RxJS 制作简单的 Accordion 组件', + summary: '受 ng-bootstrap/accordion 启发,制作一个 Accordion 组件 。', + content: require('./timliu/simple-accordion/_index.md'), + first: true, + tags: ['Angular', 'RxJS'], + authors: ['timliu'], + }, { id: 'Angular 的版本号与发布周期', title: 'Angular 的版本号与发布周期', diff --git a/src/app/_shared/api/articles/timliu/simple-accordion/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md new file mode 100644 index 0000000..b078e73 --- /dev/null +++ b/src/app/_shared/api/articles/timliu/simple-accordion/_index.md @@ -0,0 +1,216 @@ +# 使用 Angular 2、RxJS 制作简单的 Accordion 组件 + +## 写作原因 +练习使用 Angular 2、RxJS 制作一个简单的 Accordion 组件。 + +## 读者指引 +- 本文内容很大程度上受到下列的文章、代码的启发,有兴趣的同学可以先翻阅一下: + - [Angular 2 Transclusion using ng-content][](NG1 的 Transclusion 在 NG2 里改名为 content projection) + - [ng-bootstrap/accordion api][]、[源码][ng-bootstrap/accordion src] + +- 本文涉及到的知识点(没有链接的项目大家可以在相应的官方文档里找到): + - NG2 - 内容投影(content projection):使用 ng-content 标签,配合 select 属性(参看上面那个 《...using ng-content》)。 + - NG2 - 生命周期钩子(lifecycle hooks):ngAfterContentInit、ngOnDestroy。 + - NG2 - ContentChildren 装饰器。 + - ES6 - [展开运算符(spread operator)][展开运算符]。 + - RxJS - Subject + - RxJS - Observable.merge + - RxJS - Observable.prototpye.filter + +- 文章使用 angular-cli 的 [generate 指令][](简写为 `ng g`)来生成基础代码。 + +- 相应代码可以在[这个 Repo](https://github.com/rxjs-space/try-out-u/tree/master/src/app/tl-ui/tl-accordion) 找到。 + +## 小目标 +我们希望有一个 accordion component,可以在 template 里这样使用: + +```html + + + + + title0 + content0 + + + + title1 + content1 + + + +``` +即 accordion 下面有若干 panel,每个 panel 有一个 title 和一个 content。 +几点不那么重要的旁注: +- tl 是前缀,前缀可以是随便什么。 +- expandedOneOnly 和 expanded 这两个属性写在 template 里是用来初始化的,后面具体说明其功能。 +- title 和 content 可以是 html 代码,比如 `

    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 QC Date: Mon, 5 Dec 2016 15:52:58 +0800 Subject: [PATCH 113/177] Make original link a real link. --- .../_index.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/src/app/_shared/api/articles/290.Angular 2 \344\270\255\347\232\204 Structural Directive/_index.md" "b/src/app/_shared/api/articles/290.Angular 2 \344\270\255\347\232\204 Structural Directive/_index.md" index af55c6e..3d6bb50 100644 --- "a/src/app/_shared/api/articles/290.Angular 2 \344\270\255\347\232\204 Structural Directive/_index.md" +++ "b/src/app/_shared/api/articles/290.Angular 2 \344\270\255\347\232\204 Structural Directive/_index.md" @@ -1,6 +1,6 @@ # Angular 2 中的 Structural Directive(结构型指令) -原文发布于:https://zhuanlan.zhihu.com/p/22404947 +原文发布于:[https://zhuanlan.zhihu.com/p/22404947](https://zhuanlan.zhihu.com/p/22404947) 友情提示: From 0d2b0a166454fd3dd4564670166c3bc299caadcc Mon Sep 17 00:00:00 2001 From: lhtin Date: Tue, 6 Dec 2016 12:49:23 +0800 Subject: [PATCH 114/177] modify readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8c4dd80..0437345 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ Angular中文社区热烈欢迎各位投稿。延续程序员的光荣传统, ## 总结 ``` 4. 代码尽量添加编程语言标识,例如:```` ```js ````(表示代码由js写成) -5. 每段文字上下都空一行,首行不需要留空格 +5. 每段文字上下都空一行,行首不需要留空格 6. 不要给标题添加序号 示例(不好的): @@ -65,11 +65,11 @@ Angular中文社区热烈欢迎各位投稿。延续程序员的光荣传统, ## 写文章参考方向 -大方向:**只要是对用Angular 2做开发有用的,不一定局限在ng2** +大方向:**只要是对用ng2做开发有用的,不一定局限在ng2** 具体方向: -- Angular2基本概念的介绍(各个功能的解析、组件、依赖注入、模块化、及其相关的历史、小demo展示某个概念) +- ng2基本概念的介绍(各个功能的解析、组件、依赖注入、模块化、及其相关的历史、小demo展示某个概念) - RxJS基本概念的介绍(异步、处理异步的方式、及其相关历史、小demo展示某个概念) - TypeScript/JavaScript语言相关内容(TS语言的基础知识、TS编译器的使用、浏览器相关、小demo展示等) - 面向对象/函数式编程相关(模式、优缺点分析、最佳实践) From 675c0f980b252701f00744bf74106e2350ffd344 Mon Sep 17 00:00:00 2001 From: lhtin Date: Tue, 6 Dec 2016 12:54:32 +0800 Subject: [PATCH 115/177] add --- src/app/_shared/api/articles/index.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 7cbe697..ea1b0b2 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -344,15 +344,6 @@ const items: Article[] = [ tags: ['ng2升级', 'npm 常用命令'], authors: ['木丁糖'], }, - // { - // id: '一个简单的RxJS Test Spec', - // title: '一个简单的RxJS Test Spec', - // summary: '简要介绍如何编写并运行RxJS Unit Test Spec', - // content: require('./timliu/a-simple-rxjs-test-spec/_index.md'), - // first: true, - // tags: ['RxJS'], - // authors: ['timliu'], - // }, { id: 'Angular2中的通信方式', title: 'Angular2中的通信方式', @@ -362,6 +353,15 @@ const items: Article[] = [ tags: ['ng2'], authors: ['trotyl'], }, + { + id: '一个简单的RxJS Test Spec', + title: '一个简单的RxJS Test Spec', + summary: '简要介绍如何编写并运行RxJS Unit Test Spec', + content: require('./timliu/a-simple-rxjs-test-spec/_index.md'), + first: true, + tags: ['RxJS'], + authors: ['timliu'], + }, ]; @Injectable() From b98e8866b2463774b3502f433b1bf48c5335e4b4 Mon Sep 17 00:00:00 2001 From: Trotyl Date: Mon, 5 Dec 2016 15:50:10 +0800 Subject: [PATCH 116/177] Add article: Structural Directive in Angular 2. --- .../_index.md" | 362 ++++++++++++++++++ .../ng_probe.png" | Bin 0 -> 57374 bytes src/app/_shared/api/articles/index.ts | 9 + 3 files changed, 371 insertions(+) create mode 100644 "src/app/_shared/api/articles/290.Angular 2 \344\270\255\347\232\204 Structural Directive/_index.md" create mode 100644 "src/app/_shared/api/articles/290.Angular 2 \344\270\255\347\232\204 Structural Directive/ng_probe.png" diff --git "a/src/app/_shared/api/articles/290.Angular 2 \344\270\255\347\232\204 Structural Directive/_index.md" "b/src/app/_shared/api/articles/290.Angular 2 \344\270\255\347\232\204 Structural Directive/_index.md" new file mode 100644 index 0000000..af55c6e --- /dev/null +++ "b/src/app/_shared/api/articles/290.Angular 2 \344\270\255\347\232\204 Structural Directive/_index.md" @@ -0,0 +1,362 @@ +# Angular 2 中的 Structural Directive(结构型指令) + +原文发布于:https://zhuanlan.zhihu.com/p/22404947 + +友情提示: + ++ 这篇文章由于本身的内容取向,需要尽可能地保持严谨和全面,因此,可能对初学者并不十分友好。如果阅读本文的过程中觉得难度过大,可以考虑先把原文放入收藏夹中,过一段时间再来阅读; ++ 原文为双语版本,此处由于受众主要为中文用户所以仅摘录了中文部分,需要英文版本的读者可以进入上面的原文链接进行阅读。 + +Directive 一直是 Angular 中的一个重要组成部分,职能为扩展 HTML 语义。在 Angular 2 中,__Directive 被明确划分成三种类型:Component,Attribute Directive 以及 Structural Directive__(其中 Angular 1.x 也有这个划分,只是官方文档中没有明确提及)。其中,Structural Directive 虽然数量最少,却有着极高的重要性。 + +Angular 2 中,在 common 模块里内置了 3 个 Structural Directive:[NgIf](https://angular.io/docs/ts/latest/api/common/index/NgIf-directive.html),[NgFor](https://angular.io/docs/ts/latest/api/common/index/NgFor-directive.html) 和 [NgSwitch](https://angular.io/docs/ts/latest/api/common/index/NgSwitch-directive.html)。和 Angular 1.x 有很大不同的是,__Angular 2 提供了通用的星号 DSL(类似于 *prop="something")来实现自定义表达式语法__,而 Angular 1.x 只能自己靠正则匹配。其中,在 [Structural Directives](https://angular.io/docs/ts/latest/guide/structural-directives.html) 和 [Template Syntax](https://angular.io/docs/ts/latest/guide/template-syntax.html) 部分对这些 Directives 做了一些简单的介绍。但由于实在介绍的过于简单,既没有解释 DSL 的详细规则,也没有说明其运作原理。 + +本文中,将会解决这些,对 Structural Directive 的概念及原理进行介绍,同时剖析 NgFor 的实现方式以方便读者理解。 + + +## DSL 语法规则 + +为了解释语法规则,我们首先从 DSL 的翻译过程入手。__星号 DSL 会被翻译两次__,其中的第一次非常特别极其简单,也就是: + +```html +Content + + + +Content +``` + +接下来才是重要的部分,也就是第二次翻译,在第一次翻译后,才是 Angular 的解析器真正工作的开始(第一次翻译连正则都不用靠字符串拼接都能完成)。简单的说,__template 属性的值必须是一系列分号分隔的语句__,每个语句可以是: __1)赋值,2)冒号分隔的键值对__。类似于: + +```html + +``` + +由于第一次翻译的缘故,第一个语句必然是键值对,也就是星号 DSL 的第一项内容必然是表达式,后面的语句可以自己任意排列。但是,稍微有点常识的人都能够看出,__我们天天在用的 NgFor 显然就不满足这个规则,那么为什么会是这个规则呢__?我们的 NgFor 第一次翻译后明明是: + +```html + +``` + +这里并没有那些分隔符号的痕迹,不是么?是,也不是。事实上,和很多现代语言一样,当你不主动提供分隔符时,__Angular 的模版解析器会自动尝试添加分隔符__,也就是帮你断句。此外,由于这个 DSL 几乎完全没有任何的二义性,因此添加或不添加(或部分添加部分不添加)分隔符几乎永远都能得到相同的结果。因此,上面的代码完全等价于: + +```html + +``` + +这样看着和我们上面的规则接近了很多,但还是有些不同,也就是:1)第一个 key(也就是 ngFor)并没有对应任何的 value,2)赋值部分没有赋任何值。实际上,这里仅仅是一丢丢的简简单单的语法糖的语法糖,也就是规则的附加规则,即:__1)如果后一语句是赋值,则当前的键值对可以只有键没有值,2)如果赋值只有变量声明部分没有赋值部分,相当于赋上 $implicit 这个变量的值__。另外,不知道是 Bug 还是 Feature,第一条额外规则所述的情况中键值对和赋值之间不能手动加分号,当然,对于从星号 DSL 翻译过来的情况,第一个键值对和第一个赋值(如果是赋值的话)之间本来就不会有分号。因此,上面的代码又可以继续等价为: + +```html + +``` + +接着,现在开始就可以真的进行第二次翻译了。又一次简单的说,__1)对于键值对,第一个键值对的键会被当作基,添加到其后所有键值对的键之前,然后变成属性绑定(如果键值对没有值之后也就是一个没有值的属性);2)对于赋值,会被翻译成一个 `let-` 开头的字面值属性绑定__。至此,我们就能够很清晰的理解第二次翻译的结果了,也就是: + +```html + +``` + +友情提示,在 Angular 2 中,__有方括号(或 bind- 前缀)的属性和没有方括号(或 bind- 前缀)的属性都是属性绑定__。对于有方括号(或 bind- 前缀)的属性而言,例如 `[prop]="1 + 1"`,其数据绑定的内容是 `1 + 1` 的求值结果,也就是 2 这个数值(number);而对于没有方括号(或 bind- 前缀)的属性而言,例如 `prop="1 + 1"`,其数据绑定的内容是 `1 + 1` 这个字面值本身,也就是 "1 + 1" 这个字符串(如果有插值的话绑定的是插值后的结果)。一些文章或视频中为了和事件绑定押韵而把属性绑定说成是有方括号(或 bind- 前缀)的属性是不严谨的。 + +最后补充一点,__`$implicit` 其实只是语义上的表现__,并不直接存在于翻译结果中,所以直接的翻译结果是: + +```html + +``` + +综上,这就(应该)是星号 DSL 的规则了,因此我们现在也终于能理解 NgFor 的翻译过程了。 + +现在,如果我们愿意,我们可以用任何喜欢的方式来写 NgFor: + +```html + + + + + +``` + +## NgFor 的内部实现 + +从上一小节中我们知道,星号语法糖会被编译为普通的属性绑定。也就是说,__Structural Directive 在形式上并不会和 Attribute Directive 有任何不同__,只是它在内部所做的事情和 Attribute Directive 所做的事情的侧重点有些差异。 + +与其他 Directives 一样(对于 Entry Component 而言可能不是必须的),__NgFor 需要有一个 selector 来指定其应用的范围__。从上面的翻译结果我们知道,NgFor 需要作用在一个有 ngFor 属性和 ngForOf 属性的(template)元素上,因此对应的选择器就是 `[ngFor][ngForOf]`。在 CSS 中,属性选择器使用方括号的语法,并且多个选择器的组合仍然为选择器。于是我们得到 NgFor 的骨架: + +```typescript +@Directive({ + selector: '[ngFor][ngForOf]' +}) +class NgFor { + // 类名叫什么并不重要 +} +``` + +Angular 2 中,所有的 Directive(当然也包括 Component)都是 ES Class(当然实际上也可以用 Angular 2 的 ES5 API 来模拟 class 的方式),通过 Decorator 来实现额外的配置内容。 + +从上面我们已经知道,NgFor 会有两个 @Input() 属性(即属性绑定):ngForOf 和 ngForTrackBy。这里我们会发现一个问题,NgFor 的选择器和其属性绑定并不对应,这是正常的情况。对于选择器而言,我们需要应用在一个所有场景里都能满足的选择器上,而 trackBy 是可选的部分,所以并不会出现在 Directive 的 selector 中,否则我们不写 trackBy 的时候它就不是 NgFor 了;对于属性绑定而言,我们只需要有值的属性,ngFor 属性虽然始终存在但是并没有任何内容,所以每次去拿到一个 undefined 也没有任何意义,而输入属性需要考虑所有的可选内容,比如这里的 trackBy。(实际上可能还有另外的属性绑定,但此处不作深入讨论) + +所以现在我们可以增加属性绑定的声明: + +```typescript +@Directive({ + selector: '[ngFor][ngForOf]' +}) +class NgFor { + @Input() ngForOf: any + @Input() ngForTrackBy: TrackByFn +} + +// interface TrackByFn { (index: number, item: any): any } +``` + +这里我们增加一个 ngForOf 属性,为 any 类型(其实这里本应该是 Iterable 类型,即实现了 Symbol.iterator 属性的对象);另一个是 ngForTrackBy,是一个满足特定签名的函数类型(接收当前的 index 和集合中的当前 item 作为参数,返回任意值作为唯一性标识),这和我们在 Angular 1.x 中的用法稍有不同,我们无法继续使用内联表达式来作为标识,必须抽取成一个类方法。 + +有了参数,接下来我们就可以来进行操作了。这里我们需要做的事情很简单,__就是把 Template 变成一个 View,然后放进 ViewContainer 里__。 + +听上去可能有些陌生,Template 是什么呢?在 Component 中,我们会提供一个 template(或 templateUrl)属性,会自动进行 Template -> View 的转换,因为这里要做的操作非常简单,__一个 Component 有且只有一个 Template,并且也只会对应的一个 View__。而在 Structural Directive 中,就未必能有这么简单了,__比如这里我们需要根据循环项把同一个 Template 变成多个 View__。 + +我们知道 Angular 1.x 中有一个 $compile,其工作过程是: + +```text + compile + scope +template(raw/element) ---------> linkFn ---------> instance element +``` + +类似的,在 Angular 2 中,也有一个模版(Template)到视图(View)的过程: + +```text +For component template: + + compile +template(raw) ---------> view factory -----------> view + + +For template tag template: + + compile + context +template(raw) ---------> template(compiled) -----------> view +``` + +看到这里,读者可能会有若干的疑问: + ++ 为什么 Angular 2.0 中生成的结果是一个 View,这个抽象实体的存在目的是什么? ++ 为什么 Angular 2.0 中的 Template 在 Compile 之后还是 Template,那么 Template 到底指什么? ++ 为什么 Component 的 Template 就不需要 Context 就能实例化,而其他的 Template 就需要 Context 才能实例化呢? ++ Angular 2.0 中的 Context 和 Angular 1.x 中的 Scope 是什么关系?是不是像 Filter -> Pipe 那样的简单改名? + +接下来,我们就会对这些问题一一解答。 + +众所周知,__Angular 2.0 的一个重大改进就是能够跨平台,因此,不再像 Angular 1.x 中一样使用基于 DOM 的模版,也不能像服务器端模版那样直接使用基于字符串的模版。为此,必须引入一个中间抽象(但并没有使用 Virtual-DOM)__。所以,Angular 2.0 中不再是直接生成 DOM 元素的实例,而是一个更为高层的抽象视图的实例,这里叫做 View。 + +其实目前已有在 Web 平台中直接生成 DOM 元素的改进计划 [Perf: Direct Dom Rendering · Issue #11394 · angular/angular · GitHub](https://github.com/angular/angular/issues/11394),但这个属于性能上的透明优化,并不会影响到这里的概念解释。 + +另外,由于不是基于 DOM 的模版,__并不像 Angular 1.x 那样先将 Template 丢给浏览器渲染然后再对 DOM 对象进行操作,而是自行对原始字符串进行解析,然后根据分析结果直接操纵 DOM API 来按照需要构建元素,整个过程中都没有浏览器对 HTML 字符串的渲染行为发生__。当然,由于 Compiler 的功能过于强大,其本身的文件大小和工作时间都是不小的成本。 + +不过另一方面,由于 __Angular 2.0 中引入了一套通用的模版语法(对 HTML 的扩展),而不再像 Angular 1.x 中那样由每个 Directive 自行定义其 Compile 函数和自行正则匹配复杂表达式,因此,Angular 2.0 的模版编译并不需要发生在运行时,可以直接在编译时完成模版的编译__(类似于 jsx 的构建方式,但稍略复杂)。所以我们在运行时永远拿到的都是编译后的模版,而不会用到原始的字符串模版。 + +_一些 Demo 中可能会使用在运行时编译模版的方式,但这只是为了方便演示,实际生产环境为了性能基本并不会这么做。另外,一些极其特殊的项目可能也会需要对组件的动态模版来实时构建,这里会需要用到 Compiler API,但在一般项目中基本不会遇到,这里不做过多讨论。_ + +然后,我们还有一个新的实体叫 Context,但严格地说,它并不是一个实体。就像很多库中(比如 lodash)会有最后一个叫做 context 的参数一样,__仅仅是一个环境绑定,没有任何固定的类型也没有任何职能所在,除了作为 this 指针(变量)的指向__。或者说,这里的 Context 概念上就是一个纯粹的 ViewModel。反观 Scope,除了作为 ViewModel 外,还承担了 Watcher、Evaluator、ChangeDetector、Differ、EventEmitter、EventListener 的作用,严重破坏了单一职责的基本要求。所以,__Context 完全不是 Scope,但反过来,Scope 确实是 Context__。不过,由于 Context 本身只是一个抽象职责,所以很多时候并不是一个独立的实体。比如在组件模版中,Context 就是组件实例自身;而在 NgFor 的模版中,Context 就是一个 NgForRow 的实例。这也就是为什么 Component 的 Template(看似)不需要提供 Context。 + +在浏览器中,我们可以在控制台内使用: + +```javascript +ng.probe($0 /* a DOM element reference */) +``` + +得到的 [DebugElement](https://angular.io/docs/ts/latest/api/core/index/DebugElement-class.html) 来快速查看某个位置对应的 Context 信息。(如下图所示) + +![ng.probe demo](./ng_probe.png) + +回到正题,由于有依赖注入,我们这里可以很方便地获取我们所需的服务: + +```typescript +//... +class NgFor { + //... + constructor( + private _viewContainer: ViewContainerRef, + private _template: TemplateRef, + private _differs: IterableDiffers, + private _cdr: ChangeDetectorRef + ) { } + //... +} + +class NgForRow { + constructor(public $implicit: any, public index: number, public count: number) { } + + get first(): boolean { return this.index === 0; } + get last(): boolean { return this.index === this.count - 1; } + get even(): boolean { return this.index % 2 === 0; } + get odd(): boolean { return !this.even; } +} +``` + +首先解释下这里用到的 TypeScript 语法。TypeScript 中,通过在构造函数的参数前加上 public/private 修饰符,可以将其自动绑定为实例的属性。即: + +```typescript +class SomeClass { + constructor(private name: Type) { } +} +``` + +等价于: + +```typescript +class SomeClass { + private name: Type + constructor(name: Type) { this.name = name } +} +``` + +另外,这里还用到了泛型,这也是面向对象语言中很常用的特性。其中,TemplateRef 是一个开类型,可接受一个类型参数;这里的 NgForRow 其实就是这里的 Context 的类型,在这里作为 TemplateRef 的类型参数,之后即可通过 TemplateRef 这样得到对应的闭类型。在类型定义中,我们可以充分利用泛型语法,来构造通用的 API: + +```typescript +function identity(self: T): T { return self } +const sth = identity(5) +``` + +例如上面的示例中,我们定义了一个没什么用的函数,永远返回参数本身。但通过泛型,我们可以让返回值的类型永远等同于参数的类型,而不需要对所有的类型都定义一个函数,或者使用 any 造成无法进行类型检查。 + +此外,class、getter/setter 等都是 JavaScript 的基本概念,这里不多介绍。 + +这里我们需要 4 个依赖,分别是 [ViewContainer](https://angular.io/docs/ts/latest/api/core/index/ViewContainerRef-class.html)、[Template](https://angular.io/docs/ts/latest/api/core/index/TemplateRef-class.html)、[Differ](https://angular.io/docs/ts/latest/api/core/index/IterableDiffer-interface.html) 和 [ChangeDetector](https://angular.io/docs/ts/latest/api/core/index/ChangeDetectorRef-class.html),其中,ViewContainer、Template 和 ChangeDetector 是直接通过 Ref 的方式获得,而 Differ 是通过 Factory 的方式来主动创建的。 + +__Angular 2.0 默认采用了脏检测作为变化检测的策略__。脏检测是一种广泛使用的变化检测方式,通过事后比较的方式来寻找变化部分,Angular 1.x、Angular 2.0 和 React 等主流库/框架都使用了脏检测的方式来检测变化。(虽然 React 自己很少这么说) + +因此,为了能够检测变化,我们需要回答两个问题:什么时候进行检测?怎样进行检测?Angular 1.x 采用了较为落后的方式,在每一次可能引起变化的事件中都进行全量的比较。而在 Angular 2.0 和 React 中采用了一定的优化方案,基于组件化和单项数据流的特性,我们可以很大程度上缩小需要检测的范围,提高性能。 + +而在 Angular 2.0 中,__我们可以通过 ChangeDetectorRef 类型来实现对 ChangeDetection 的过程的控制__,虽然在一般的程序中可能不大会用得到。实际上,这里的 ChangeDetectorRef 仅仅是一个 Role,并不是真的有这个 ChangeDetectorRef 类型单独的实例,由于 TypeScript 中 interface 是运行时不可见的而 class 又是 structural 的,这么做并没有什么实现上的问题。由于 Angular 2.0 的应用是一个组件树,我们可以动态调整当前组件子树的状态,从其类型签名就可以了解: + +```typescript +class ChangeDetectorRef { + markForCheck() : void + detach() : void + detectChanges() : void + checkNoChanges() : void + reattach() : void +} +``` + +另外还有一个 Differ 类型,相比之下,Differ 并不是 Angular 2.0 的什么重要组成部分,只是一系列工具库,用来对不同类型的对象进行比较得出变化情况。实际上,如果我们愿意的话,我们也可以完全不使用脏检测,自行定义别的检测方式,不过鉴于 Angular 2.0 本身的优化情况,使用脏检测并没有什么性能问题。 + +对于 IterableDiffer(同样适用于其他的 Differ 类型),这里涉及到了几个类型分别是:[IterableDiffer](https://angular.io/docs/ts/latest/api/core/index/IterableDiffer-interface.html)、[IterableDiffers](https://angular.io/docs/ts/latest/api/core/index/IterableDiffers-class.html)、[IterableDifferFactory](https://angular.io/docs/ts/latest/api/core/index/IterableDifferFactory-interface.html) 和 [DefaultIterableDiffer](https://angular.io/docs/ts/latest/api/core/index/DefaultIterableDiffer-class.html)。其中 IterableDiffer 是一个接口,DefaultIterableDiffer 是 IterableDiffer 的一个实现类,IterableDifferFactory 是 IterableDiffer 对应工厂类型的接口,IterableDiffers 是 IterableDiffer 的工具类。当然,事实上也是有 DefaultIterableDifferFactory 这个类型的,只是并没有归入文档中,因此不做介绍。其中,IterableDifferFactory 有一个 supports 方法,用来确定是否支持某个具体的 Iterable 对象(有很多类型都实现了 Iterable,比如常见的数组,不常见的生成器函数的返回值等)。为此,IterableDiffers 也提供了一个 find 方法,用来自动查找可用于这个对象的 IterableDifferFactory,类似于: + +```typescript +this._differ = this._differs.find(value).create(this._cdr, this.ngForTrackBy) +``` + +当然,作为工厂类型,有一个 create 方法是无序过多介绍的,其接受两个参数,分别是 ChangeDetectorRef 和 TrackBy 函数,之后返回一个 IterableDiffer 实例。当然,因为这里的 find 是可能会失败的,因为可能支持某个对象实例的 Differ 并不存在。换句话说,__我们也可以提供自定义的 IterableDifferFactory 来扩展 NgFor 能够支持的类型范围__(通过 IterableDiffers.extend ),这也是单一职责或者说低耦合性带来的一个巨大便利。 + +Angular 2.0 也和其他组件化的实现一样,__具有生命周期(Life-Cycle Hook)这个概念__。这里我们需要用到两个 Hooks:OnChanges 和 DoCheck。 + +OnChanges 正如其名,就在每次发生变化时调用。然而,我们干的事情并不是每次变化都起作用,而是只需要第一次执行就能完成: + +```typescript +//... +class NgFor implements OnChanges { + //... + + private _differ: IterableDiffer = null; + + ngOnChanges(changes: SimpleChanges): void { + if ('ngForOf' in changes) { + const value = changes['ngForOf'].currentValue; + if (!this._differ && value) { + try { + this._differ = this._differs.find(value).create(this._cdr, this.ngForTrackBy); + } catch (e) { throw new Error(`...`); } + } + } + } +} +``` + +这里又接触到了一个新的类型,SimpleChanges,就是一个简单的当字典用的对象,每个 key 是属性名称(实际上是 input 的名称),value 是一个 SimpleChange 类型的对象。那么 SimpleChange 又是什么呢?看一看结构就很清楚了: + +```typescript +class SimpleChange { + constructor(previousValue: any, currentValue: any) + previousValue : any + currentValue : any + isFirstChange() : boolean +} +``` + +这个我们在熟悉不过了,和 Scope.$watch 的回调参数非常相似,这里我们可以得到每个变化了的属性的旧值和新值,以及一个能确定是否为首次变化的函数。 + +不过上面并不是重点,只是为了让我们能够继续读代码。仔细进行分支检查我们可以发现,真正的内容只可能会被执行一次,__而且所谓的真正的内容唯一的作用就是初始化 Differ,之后的变动也不会造成任何影响__。那么,为什么一定要这么做呢?而不是在 OnInit 的时候就把 Differ 给初始化好呢? + +这里就有一个逻辑问题,上面我们已经知道,具体使用的 Differ 是需要根据对应 Iterable 的实际类型来确定的,而 ngForOf 却不一定是在组件初始化时就已经存在的(比如使用 async 这个 Pipe),所以在组件初始化的时候我们还未必能确定 ngForOf 这个 Iterable 的类型,因此也就无法获取对应类型的 IterableDiffer。(不过话说真的有必要搞得这么复杂么?)所以说,虽然这里是 OnChanges 这个接口,但只是进行初始化这个操作,理解了这点,我们就能够继续往下了。 + +当然,我们也能够发现这里用到了两个假设: + ++ ngForOf 的类型是不会发生变化的。即不会现在循环一个 Array,过一会又变成一个 Set,当然实现上可能并不会发生问题,但原理上并不应当出现这种情况; ++ ngForTrackBy 始终不会发生变化。即不能在初始化以后修改 ngForTrackBy 的绑定,正常情况下也当然不会这么做。 + +除了 OnChanges 这个接口外,我们还实现了另一个接口:DoChecks。并且这里是真真正正的来 DoCheck,并不像上面的 OnChanges 那样挂羊头卖狗肉,而是真正的实现了检测变化的功能: + +```typescript +//... +class NgFor implements OnChanges, OnChanges { + //... + + ngDoCheck() { + if (this._differ) { + const changes = this._differ.diff(this.ngForOf); + if (changes) this._applyChanges(changes); + } + } +} +``` + +这里的功能很简单,如果有 Differ 的情况下(上面说到由于 ngForOf 指不定什么时候才有因此 Differ 也是指不定什么时候才有的),会调用 Differ 的 diff 方法来检测变化,如果有变化则进行后续操作。这里略有一点 Tricky,甚至可以说可能有潜在错误隐患,直接假定了当前的 Differ 就是 DefaultIterableDiffer(实际上上面也说道用户可以提供另外的 DifferFactory),从而可以写出下面的变化应用代码: + +```typescript +private _applyChanges(changes: DefaultIterableDiffer) { + const insertTuples: RecordViewTuple[] = []; + changes.forEachOperation( + (item: CollectionChangeRecord, adjustedPreviousIndex: number, currentIndex: number) => { + if (item.previousIndex == null) { + const view = this._viewContainer.createEmbeddedView( + this._template, new NgForRow(null, null, null), currentIndex); + const tuple = new RecordViewTuple(item, view); + insertTuples.push(tuple); + } else if (currentIndex == null) { + this._viewContainer.remove(adjustedPreviousIndex); + } else { + const view = this._viewContainer.get(adjustedPreviousIndex); + this._viewContainer.move(view, currentIndex); + const tuple = new RecordViewTuple(item, >view); + insertTuples.push(tuple); + } + }); + + //... +} +``` + +这里用到了 DefaultIterableDiffer 的一个重要特性,其 diff 方法中,如果没有变化内容,则返回 null,如果有变化内容,则返回其自身,因此这里的 changes 参数仍然是一个 DefaultIterableDiffer。之后的代码就很简单,对于每一个元素变化,如果是新增的元素,就在自己的 ViewContainer 中为其新建一个 View,其中,Template 就是拿到的 TemplateRef,Context 为新建的一个 NgForRow 类型的实例,Index 为当前 Iterable 元素的 Index,并将其单独添加到一个数组中以供某后续操作(其实就是设一下 $implicit 的值);如果是被删除的元素,则直接将其 View 从 ViewContainer 中删除即可;如果是内容有变化的元素(可能是顺序变化也可能是元素本身变化),则将其 View 在 ViewContainer 的位置也进行对应调整,也同样将其加入到某待后续操作的数组中。 + +```typescript +private _applyChanges(changes: DefaultIterableDiffer) { + //... + for (let i = 0; i < insertTuples.length; i++) { + this._perViewChange(insertTuples[i].view, insertTuples[i].record); + } + //... +} + +private _perViewChange(view: EmbeddedViewRef, record: CollectionChangeRecord) { + view.context.$implicit = record.item; +} +``` + +紧接着就是刚刚我们提到的某后续操作,真的就只是设置一下 Context 的 $implicit 属性。如果不记得这个是什么了的,可以往上翻翻看,其实就是 `let item of items` 中 `item` 的值。 + +至此,我们可以知道,NgFor 没有使用 DOM 操作,仍然保持着 Angular 2 的平台无关性。同时,也并没有使用什么黑魔法,只是用到了一些平常不太会用到的 API。所以,NgFor 并没有任何的实现上的特殊性,我们完全可以自行实现一个 NgFor 或者类似功能的 Structural Directive。 diff --git "a/src/app/_shared/api/articles/290.Angular 2 \344\270\255\347\232\204 Structural Directive/ng_probe.png" "b/src/app/_shared/api/articles/290.Angular 2 \344\270\255\347\232\204 Structural Directive/ng_probe.png" new file mode 100644 index 0000000000000000000000000000000000000000..bb92f44ef5cb3587f2c20ce6717c7464b84d728b GIT binary patch literal 57374 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