聆听群山的怒号


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 站点地图

service worker 缓存原理

发表于 2019-08-24

workbox 的 service worker 缓存实现

正如其名 workbox 是 google 封装的一个工具箱,旨在提供开箱即用的 service worker 相关特性。

precaching 缓存应该其中适用性最广的一个特性。正好最近在项目中使用的到,于是便去研究了一下其原理

service Worker + cache api = precache

我们说 service worker 缓存其实并不正确,service worker 本身并不提供缓存功能,而是配合了 Cache 的 api 才提供完整的缓存功能。

在 workbox 中将这两者封装成一个 workbox-precaching

Service Worker 生命周期

在缓存功能中 Service Worker 的作用主要有两个

  • 提供生命周期的钩子给 PrecacheController 进入执行缓存控制的相关逻辑
  • 提供拦截请求的功能

Service Worker 的生命周期包括

  • installing 每个 service worker 只触发一次,初始化和注册 Service Worker
  • installed Service Worker 已经完成了安装,并且等待其他的 Service Worker 线程被关闭。
  • activetaing 在这个状态下没有被其他的 Service Worker 控制的客户端,允许当前的 worker 完成安装,并且清除了其他的 worker 以及关联缓存的旧缓存资源,等待新的 Service Worker 线程被激活。
  • activate 在这个状态会处理 activate 事件回调 (提供了更新缓存策略的机会)。并可以处理功能性的事件 fetch (请求)、sync (后台同步)、push (推送)。
  • redundant 这个状态表示一个 Service Worker 的生命周期结束。

img

其中 precaching 用到的主要是 installing 和 activate 两个声明周期的钩子,分别对应了静态资源缓存的初始化,更新以及拦截请求

Cache API

precaching 的另一部分则是 Cache Api

Cache 的缓存机制可以直接对 Request / Response 对象对提供存储机制。有意思的是,虽然他定义在 service worker 的标准中,但是它直接暴露在 window 的作用域下,因此你实际上不一定需要配合 service worker 使用

cache 包括这样一些有趣的特性

  • 一个域可以有多个命名 Cache 对象
  • 你需要自定义更新方式,除非明确地更新缓存,否则缓存将不会被更新
  • 你需要自定义清理缓存逻辑,除非删除,否则缓存数据不会过期
  • Cache 的 Cache.put, Cache.add和Cache.addAll只能在GET请求下使用。

可以看到 Cache api 保存的直接就是一个 Request/ Response 的对象,因此可以直接其作为请求的返回。

另外,在写下这篇文章的节点, mdn 中 关于 Cache api 的部分文档和实际的 api 行为有不一致,我估计是没来得及更新。一个比较明显的差异在于 Cache.keys()

根据文档的说明和示例, Cache.keys() 返回应该是一个Promise对象,其 resolve 的结果是Cache对象key值组成的数组

如果用 ts 类型标注出来应该是 Promise<string[]|null> ,但是在 workbox 的源码中其标注的 types 是 Promise<Request[] | null>,两者显然不可相比。

额外的缓存清除机制

虽然说除非主动删除,否则缓存数据不会过期一直缓存下来,但有一种额外的的情况,那就是浏览器上的可控制存储大小实际上受限于硬盘的大小。

而浏览器会根据可控制存储大小,硬性的限制每个域下缓存数据的大小。所以 cache 的容量是有上限。如果某个域配额不够,或者磁盘空间不够的话,浏览还是会根据 LRU 最近最少使用的规则,清除某个域下面的缓存信息。清除的时候会以整个域作为单位进行清除,而不是再深入细分清除。

因此一个 workbox 完整的缓存控制流程如下

  • webpack 中 workbox 根据我们打包出来的 chunk 和相关的过滤配置,生成了 Manifest.js 记录所有要缓存的静态资源
    • manfest 的结构 {revision:string, url:string}
    • revision 保存文件的 md5 hash 作为文件的版本
    • url 则是 Cache 的 key 值和请求地址
  • 在 installing 回调中读取 Manifest.js ,获取所需的静态资源索引,调用 cache api 进行缓存
  • 在 activate 时根据 manifest ,对资源文件进行遍历检查,删除无用资源或者更新资源文件
  • 在 fetch 事件中拦截 cache 中已经存在的静态资源文件请求直接返回缓存数据

对比其他缓存方式

http 缓存

http 主要依赖 304 进行缓存,包括

  • 强缓存:通过 Cache-Control max-age 设定一个过期时间,再这个时间之前都不会再次发请求
  • 协商缓存:强缓存失效之后,则可以通过 last-modified 或者 etag 向服务器请求判断是否需要更新缓存

http 的问题在于用户主动刷新的时候,就会让强缓存失效,直接进行协商缓存。

localstorage 缓存

localstorage 缓存相比 http 缓存可以进一步控制资源,也可以缓存比较大的资源,不过 localstorage 也有其问题

  • 需要自己实现资源的请求管理的机制,管理资源文件的读取和写入。
  • localstorage 只能保存字符串数据,因此也需要自己实现对资源的序列化,反序列化,以及添加的逻辑
  • seo 不友好
  • 版本更新机制

所以相比之下 Cache + Service Worker 的优势就是对 localstorage 缓存方案的进一步改进

  • 不需要自己去维护资源的请求机制
  • service Worker 可以直接拦截请求,cache 直接保存 Request / Response不需要进行序列化
  • seo 优化
  • 可控性更加的高

'vue/TypeScript问题两则'

发表于 2019-04-20 | 分类于 学习

最近尝试为 vue 项目配合 TypeScript 不过发现毕竟 vue 不是原生 TypeScript 开发,在对 TypeScript 支持方面显然还问题多多,这里稍微记录两则

自动注入 h 问题

如果你在 vue 中是用 jsx 你会明显感受到和 react 有明显的一个差异就是 react 中你可以很方便的到处写下 jsx,而 vue 中则限定的比较死,要么写在组建的 render 函数中,要么主动传递 h 函数到你想要写 jsx 的地方比如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 找不到 h 函数
const component = <button />
// ok
export default {
render (h) {
return <button />
}
}
// 主动将 h 传递到需要的地方
const component2 = h => <button />
export default {
render (h) {
return component2(h)
}
}

由于 h 函数是在编译后才会被使用到,而每次都要写 h,但实际少主动用到,所以 vue 官方为了进一步简化使用,开发了一个 babel 插件babel-sugar-inject-h, 检测 jsx 自动插入 h 函数,比如这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// With @vue/babel-sugar-inject-h
const component =()=> <button />
export default {
render () {
return <button />
}
}
// 不需要写h,编译后自动注入 h 函数,等价于
const component =(h)=> <button />
export default {
render (h) {
return <button />
}
}

这让看起来让 vue/jsx 更加接近 react/jsx ,还稍微减轻了开发的工作。但我个人认为这样有些自做主张,并且关键是做的并不完美。如果你用了 vue-cli 那么他是自带且默认启动的,如果你没有用 vue-cli 自己配的环境,那么就有可能就忽略了这的插件,就容易导致同一段代码在两个环境下有不同的表现。而这如果不是用户主动去看文档,是不会被感知到的,一但出了问题就特别令人摸不着头脑,

哦,跑题了,这篇文章应该说的是跟 TypeScript 相关的问题,其实也就是它做得不够好的一个体现,假如你要配合 TypeScript 使用,很有可能遇到以下代码

1
2
3
4
5
import { Component, Vue } from "vue-property-decorator";
@Component
export default class App extends Vue {
test = (h: any) => <div>123</div>;
}

其中 test 是你组件的内部变量,理论上这段代码应该等价于

1
2
3
4
5
6
7
export default {
data(){
return {
test: (h)=><div>123</div>
}
}
}

然而假如你实际在 vue-cli 中跑这段代码,是可以跑起来的,但在浏览器中会报出类似以下错误,

1
Error in data(): "TypeError: Cannot read property '$createElement' of undefined"

有了前面的铺垫,不用说问题的关键显然是出在 babel-sugar-inject-h 自动注入 h 的问题上,为了了解为什么,不妨看一下这段代码编译后的样子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 略去前后无关代码
function (_Vue) {
Object(inherits["a" /* default */])(App, _Vue);
function App() {
var _this;
Object(classCallCheck["a" /* default */])(this, App);
var h = _this.$createElement;
_this = Object(possibleConstructorReturn["a" /* default */])(this, Object(getPrototypeOf["a" /* default */])(App).apply(this, arguments));
_this.test = function (h) {
return h("div", ["123"]);
};
return _this;
}
return App;
}(vue_property_decorator["c" /* Vue */]);

我撇去了无关的代码和不压缩,这里的问题就显而易见了。

尽管在 test 上我主动显式的传入了 h 函数,但是对于构造函数 data() 来说,似乎依然被判断为应当注入 h 的情况,这也其实没有关系,不过它注入 var h = _this.$createElement; 的位置就有些问题了 ,默认情况下,它一般事插入到 this 声明定义之后。

1
2
3
4
5
6
7
8
9
10
11
12
13
function App() {
// 一般情况下编译后 _this 的声明和定义实在同一行的,因此注入后不会报错
var _this = something;
var h = _this.$createElement;
return _this;
}
function App() {
// 在 ts/vue-property-decorato 中的 this 是先声明后定义
var _this;
var h = _this.$createElement;
_this = something;
return _this;
}

然而由于用了ts和vue-property-decorator,_this 的是先声明后定义,导致插入在声明之后的 h 是找不到的 _this.$createElement 的

解决方法

最好的方法当然是这个插件更新并考虑 ts 这种 edge case ,不过在此之前我其实建议直接关掉自动注入 h 的功能,毕竟 vue/jsx 本身就不是可以到处写 jsx ,本来就需要 h 却隐蔽起来并不会解决太多问题,反而会造成一些认知问题。

不过这里牵扯到另一个问题,如何关闭这个插件。

vue/jsx 的文档中写明的修改配置方法是在 babel config 中修改 @vue/babel-preset-jsx 的配置,假如你是自己配置环境那么直接如此就可以了。

1
2
3
4
5
6
7
8
9
10
{
"presets": [
[
"@vue/babel-preset-jsx",
{
"injectH": false
}
]
]
}

但是,假如你用 vue-cli 构建的项目的话,你会发现这样写并没有用,这是因为 vue-cli 非常“聪明”的封装了另一个 @vue/babel-preset-app ,这 preset 内部引入了 @vue/babel-preset-jsx自己包裹了一层配置的传递, 源码在这里

1
2
3
4
5
6
7
if (options.jsx !== false) {
presets
.push([
require('@vue/babel-preset-jsx'),
typeof options.jsx === 'object' ? options.jsx : {}
])
}

可以看到它根本不会去读取 babel config 中 @vue/babel-preset-jsx 的配置参数,因此正确的配置方法是

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"presets": [
[
"@vue/babel-preset-app",
{
// 要扔到 @vue/babel-preset-app 的 jsx 字段上
jsx:{
"injectH": false
}
}
]
]
}

而关于 jsx 可配置 @vue/babel-preset-jsx 参数这一点,官方一开始并没有任何说明(现在有了),在文档中也只提到,jsx 是一个布尔值用于开启关闭 jsx 支持,如果不去看源码谁又知道,它还可以传入 object 来做进一步的配置?

所以说,为了搞清 babel-sugar-inject-h 这一个小问题,不得不跑去看 vue-cli/babel-preset-jsx/babel-preset-app 等一长串的相关源码配置方法才摸索清楚,这说不定就是封装之美?

真有你的啊 vue-cli

tsx 中组件属性类型推断问题

tsx 中无法正确给出自定义 component 的属性类型定义,甚至会报错。相比之下这个问题更加简单也更加恼人,假如你定义了一个组件,比如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import Vue from "vue";
const MyComponent = Vue.extend({
props: {
text: { type: String, required: true },
important: Boolean,
},
computed: {
className() {
return this.important ? "label-important" : "label-normal";
}
},
methods: {
onClick(event) { this.$emit("ok", event); }
},
template: "<span :class='className' @click='onClick'>{{ text }}</span>"
});
// 在别的组件中调用,则会报错
// Compilation error(TS2339): Property `text` does not exist on type '...'
<MyComponent text="foo" />;

这个问题如果是从官方角度来说,几乎除了等待 vue3 重构以后得到 TypeScript 更好的支持以外,看来别无其他折中的办法,详情可参见这个 issue 。

所幸这个 issue 中也给出了一个比较成熟的第三方解决方案 vue-tsx-support,这个库的文档已经非常详细了,这里没有必要赘述。总而言之这个库可以相当好的解决目前的 tsx component prop 缺少类型推导的问题,不过,代价是引入了他自己的一套定义组件的方式。

兼容?升级?

首先这个库虽然得到推荐,但官方对其的态度也停留在可以有的暧昧程度,不如 **vue-property-decorator** 那样得到官方认可并且整合到官方工具链中这个级别的对待。在这个问题上 vue 官方寄希望于 vue3 重构能解决,而没有给出现在的过度方案,显然你不可能寄希望于他们能去兼容现在的第三方过度方案……

因此另外一个不甚优雅的解决方案,那就是通过 d.ts 文件让 component 的参数允许任何属性

1
2
3
4
5
declare module 'vue/types/options' {
interface ComponentOptions<V extends Vue> {
[propName: string]: any
}
}

这样 component 实际上就可以接受任何参数而不报错,然而无法正确推导出对应的 component 有什么属性的问题并没有解决,所以依然的不到任何提示,这某种程度上就损失了 TypeScript 一个大优势。

而好处是,没有引入任何新的东西,也不需要魔改任何旧的代码,在兼容性上和其他的 vue2 代码处于一个级别。

总结

目前来说,ts + vue 当然可用,但是依然相当多的问题,没法如丝般顺滑的相互配合。对于他们完全打算通过 vue3 去彻底(?)解决于 ts 共用的的问题,而不打算优化一下 2.x 当前存在问题的决定……我是比较不赞同的

『JavaScript函数式编程』备忘录(上)

发表于 2019-04-11 | 分类于 学习

iz4o4I.jpg

本文建议结合 https://github.com/Tk-archer/functional-javaScript-code-refactoring 这个项目阅读查看

起

『JavaScript函数式编程』这书其实在几年前我就入手了,但是当时并没能读下去,然后就一直尘封在书柜里面。

直到最近才偶然翻出来,打算好好读一下。本文说是读书笔记的话就过于正式了,所以就只能称之为备忘录了。

阅读全文 »

2018 five总结

发表于 2019-01-09 | 分类于 杂谈

序言

不得不说,我实际上并没有正儿八经的为自己写过一篇年度总结。所以这某种意义上来说也是一种“新年新气象”的行为,尽管这实际上是在回顾过去。

2018 我干了什么

今年是我在我的第一家公司工作的第二年,也是我正式工作的第二年。工作上今年其实并不是很有意思。

不上不下的组件库

年初我完成了公司内部的一套统一的 ui 组件库,现在看来只是马马虎虎,不足之处也数不胜数。但是实现的过程中可以说是对我个人的提升最大的一项工作,这对让我对需对组件的整合设计逻辑,以及这个组件概念本身都有了更多的了解。

但是不得不说,一个要维护一个成熟的 ui 库其实是非常花费精力的,看似一个 ui 组件库的核心是他自己,然而有没有方便的使用方法,明确的文档,能否有一套成熟的管理协作开发流程都对这个 ui 组件最终能发展成怎么样,有着非常大的影响。

ts/rx/react

不得不承认我还是一个相当跟风又懒的人,在周围各种大佬的案例下,我最终可喜可贺的有时间“入门”了一下以上提到的这三个东西,的确可以说是打开了一些新方向

不过,可惜的是这些依然处于一个“入门”的阶段,能看懂使用了这些库的项目的源码,并一定程度理解到其实现思路的特殊之处,甚至自己写一些小玩意也不是什么问题。

然而,实际工作中没还是能有机会使用到,因此在这几项东西中必然还有更多我所没有了解到的,水面下的东西。

再一次,早上好,药丸市

我是一个相对孤僻的人,求学时期虽然也缺钱,但更重要的的是我缺少那些能引领我到处出去玩的朋友,因此即使说我是在广州长大,对于这里的很多地方我也非常陌生。过去的一年里我依然还是蛮孤僻的,但是由于某种我已经忘记了的理由,我决定不再呆在室内孤僻。

因此这一年里我去了许多广州的许多地方,一般开始的目的是为了某一处的食物,最终总是会变成吃完以后漫无目的的到处晃,有很多我之前没有去过的地方,也有那些我很久没有去过的地方,或许对于许多真正意义上的“老广”来说,我去的那些地方或许还是相当的“大众化”,但无论如何工作后以一种新的角度游历这个城市,带给我非常新鲜的感觉。

2018 我没干成什么

emmmm,要说这个,那可就太多了。

比如我现在依然没有减下体重到 70kg 以下,虽然也能维持在 70~71,偶尔因为生病脱水落到 70 以下,但毕竟没有到达目标。

工作上,就像我上一篇文章里面所说的,这个最终走到垃圾堆里的失败项目对我的打击实在不是一点半点,但是那篇也写得够多的了,这里不再赘述。

除了这个,上面提到的 ui 库某种程度上也应该列入到这一 part。虽然根据最初的计划,我确实是完成了一版 ui 可用的ui组件库,但是,完成可用只不过是一个开始。就像上面说的维护和不断的迭代才是决定了它能走多远的核心。

然而就公司而言,业务需求始终是优先,以及这个项目缺少良性的反馈参与,在后期维护上变的越发吃力,现在虽然我还能接着用,却无力在公司内部进一步推广,因为无法适应设计多变的要求,如果明年还是没有时间抽出做专门的维护,最终荒废掉的结局大概是不可避免的。

个人方面,在我的 blog 有两问题,一个是更新,连月更都算不上,每年年初都想着要写多一点,每次是败给自己的惰性。

更加可惜的是另一个,同样在年初定下的自建博客也没有能完成,大概只做到了 1/3 的代码就因为这样那样的借口最终没能坚持下来。再一次让我体会到自己的堕落之处。

尽管我大言不惭的把说我去年一年学了新的东西,但我真的有足够的提升到了自我了吗?

举个例子,在重复的业务开发中,我能有一些比较固定的套路来提升自己的工作效率,然而这这些套路也没有能到达随手捏出一个成型的辅助类库的地步,其中多多少少还是只不过是换种花样的复制粘贴。另一方面,有固定的套路真的好事吗,这某种意义上或者也可以说是一种思路的僵化。尤其是周遭环境缺少有效的参考让我很难意识到自己做的到底行不行,尽管网络如此发达总是能找到解决方法,但是总觉得隔了一层纱,让我难以得到及时的反馈。

8102 年

这一 part 就是纯粹的杂谈了,说不上是完成了什么,也没有搞砸了什么。只是想记录今年里面那些还能让我想起来的片段。

姜维传

游戏方面,下半年印象最深刻的莫过于【姜维传】这部神仙作品。尽管他是一个 mod ,尽管我的战旗水平很差以至于后期全靠修改器。但是这个游戏再一次为我展现了一个不同的三国世界,其中的考究和脑洞实在令人佩服。尤其是今年我还玩了 358 这部贫瘠得可怜的开放世界,相比之下你只会想要问候暗荣那一家子开发人员到底在搞什么飞机。

我怎么都没有想到我人生中屈指可数的通宵居然能有姜维传一席之地。

社交媒体

我其实一直不习惯国内社交媒体,多数时候对我来说他们不过又是另一种通讯工具,而非社交。我这些年流连最多的是 A 岛这样一个“匿名”的地方,他给我一种个人隐藏于话题之后的安心感,可以专注于话题而非多数社交媒体上的角色扮演。

不过从前年开始,telegram 这个im软件走入我的社交圈子中,对我来说它有种当年 qq 的感觉,却更加自由,现在这个时代这个地方,能有一份自由相当难得。今年我花了更多的时间在这里,显然,它让我意识到我并没有我想象中那么不需要社交。如果你厌烦于国内吵杂的社交环境,不如尝试以下 telegram。

最后是 g+ ,嚷嚷了那么久的鬼城鬼城,一旦真到了要倒闭的时候,还是会感到不舍,毕竟是陪伴了我相当一段时间的地方,要关门了,理性上可以接受,情感上依然会感到失落,只能说有缘再见。

“绝症”患者与现代医学

已经不知道是什么时候开始的了,我居然会有耳鸣…我尤为记得,当我第一次在 A 岛看到有人描述他自己是耳鸣,我才突然意识到我也有耳鸣。那种出其不意的感觉,犹如凤雏突然意识到自己所在的地方叫落凤坡一样。从此耳鸣就成为我生活中并不能被舍弃的一环。

我所患上的是神经性耳鸣,这个东西非常简单,简单到谷歌一下可以理解是什么,然而它又非常复杂,复杂到发生的原因?不知道,耳鸣响在哪里?不清楚,耳鸣的感受?只能靠患者描述(无法有客观物理的设备检测到),也没有确实有效的缓解药物,更不要说根治方法方法了。各种意义上都可以说是“绝症”了。

我今年终于鼓起勇气去医院检查了一番。就结果而言,基本上跟我自己查得到的资料是一致的。与其说做了无用功,不如说被医生确认了长久萦绕在心头上的想法,反而落得轻松。毕竟已经相当接受了耳鸣的存在。不过遇上失眠的夜晚加上耳朵吱吱作响依然是令人倍感绝望。

值得一提的是,在我检查我的耳鸣的时候,其中最核心的一项检查是判断我到底是不是有耳鸣,其实就是按顺序播放不同频率的声音,直到有一个频率的声音被你的耳鸣覆盖住,你觉得你听不到了,那么你就是患上了这个频率附近的耳鸣。这个方法异常简单,甚至你自己都可以在家做。

整个过程的主观性质非常的强,到底听没听到都是患者说了算,比如说一个听力正常的人,完全可以故意作假而很难被医生看出来。不像验血结果有就有没有就没有,可以客观的检查到。

最终结果也有些哭笑不得,除了耳鸣这个问题以外,各项检查都表示我的听力水平居然属于相当优秀那一拨,人生真是充满黑色幽默。现代医学已经解决了相当多的问题,然而现代医学也依然有相当多的问题还不能解决。就像知道自己不能做什么和知道自己能做什么同样重要。

所以这个时候,除了微笑还有什么更好的方法吗?

书籍的边界

今年我在学 react/ts/rx 这一堆的东西的时候,也都找了一下相关的书籍来看,结果每一本都有相当程度的过气跟不上版本的部分,其中以 react 的书籍尤其严重,同时 react 相关书籍的复读程度也是最高的,几乎每本书都要把相同的东西复读一边。

所以就像《疯投圈》有一期提到的读书观点,并不是不喜欢读书,而是作为技术类书籍,除非是很学院派的知识内容,否则一般程度的技术资讯类都不值得出书,尤其是各种这个入门那个初见,大多数都很令人失望……因为滞后性实在太强了,这或许本身就是书籍这种载体的局限所在。

报复性消费

根据支付宝记录,我去年花费并不低,可以说是新高了。其实我刚开始工作的时候对消费是很有负罪感的,即便那些钱是我自己的工资。结果在一次次面那些对由不得你的支出的时候,报复性消费的欲望最终盖过了所剩无几的负罪感,从此,消费水平直线上升。

所以 2019 就这样来了

太多的事情让我对新的一年没有更多的好感,虽然还有那么一些期望的东西,整体来说却有些提不起兴致。

姑且也写下了,方便我明年这个时候回来打脸

  1. 更新更多的 blog 文章,至少要比去年多吧,缺少人际交流的时候其实适合发牢骚。
  2. 把去年学到的东西用上,只有学以致用才能学到更多东西,不然这个入门那个尝鲜,和我看不起的那些无聊的书籍又有什么不一样呢?
  3. 旅游,想去日本见识一下,自已一个人去……
  4. 做出一些更加有意义的东西,那么,什么是有意义的东西呢?

完

npm 如何安装私有包

发表于 2018-10-26 | 分类于 javascript

最近在公司负责了一个类似 element-ui 的 vue ui 库的开发,然后在如何合理分发的问题上遇到了麻烦。
因为想要用起来更加方便,那么如何简单的安装使用起来显然也是需要考虑的问题。
最终我们决定通过 npm 包管理的方式来分发使用我们的内部 ui 库。
毕竟 npm install package 几乎是现实的标准了,也是前端最为熟悉的方式了,不过这也引发了额外一个问题。
我们的内部 ui 库是放在公司内部的私有 gitlab 仓库当中,也并没有发包到 npm 上,自然还是需要格外做一些工作。

阅读全文 »

读书笔记 『the undoing project』

发表于 2018-08-19 | 分类于 日常

PLduWt.png

我知道之所以知道这本书,源于去年的在 medium 翻看 javascript 相关技术文章的时候看到相关的介绍,该文章的作者对这本书的评价非常的高,因而引起了我的关注。

先说结论,这本书确实很值得一看。

阅读全文 »

vue 的 jsx 如何动态渲染 component

发表于 2018-08-12 | 分类于 javascript

vue 要在 template 动态调用组件非常简单只需要 <component> 组件配合 is 属性就可以动态渲染组件。

1
2
3
<template>
true<compoment :is='someComponent'></compoment>
</template>

不过在 jsx 中使用 <component> 组件的话会报错,显示该组件不存在无法渲染。因此需要换一个方式。

由于 jsx 本质就是 js 不需要 component 组件做中介,可以通过 js 直接找到对应组件

1
2
3
4
5
6
...
render(){
const Comp = this.someComponent
return (<Comp></Comp>)
}
...

这是由于如果一个变量指向了一个组件,那么这个变量名可以直接被 jsx 解析并渲染。

因此在文档中也会提到到我们可以不将组件加载到父组件当中,直接经由 jsx 渲染出来的原因

1
2
3
4
5
6
import componentA from 'xxx'
...
render(){
return (<componentA></componentA>)
}

完

pixi.js 速记其一

发表于 2018-05-25 | 分类于 javascript

pixi.js 速记其一

CfTiBq.png

最近在研(xue)究(xi)pixi.js 。既然是研(xue)究(xi)既然会有许多一时踩坑的地方,所以想要开一个系列记录一下,当然,希望我不要鸽了

阅读全文 »

vue 与 throttle 的坑

发表于 2018-01-21 | 分类于 学习

vue 与 throttle 的坑

Lodash 一直是我十分喜欢的一个工具库,其中 throttle 节流函数适用于控制类似 scroll 事件回调这种极其频繁场景上。可惜的是在配合 vue 使用上变得不那么好用,让我觉得非常可惜,当然预先说一句,这实际上不是 throttle ,Lodash 设计的问题,更多的是 vue 的问题。

p7ZAtx.md.jpg

阅读全文 »

通往广图的最后500米

发表于 2017-12-17 | 分类于 日常

问:广州图书馆何处最为静谧而有图书馆的气息?

OMV9f.jpg

此处不宜喧哗

自从几年前广州图书馆新馆建成开放,过于嘈杂一直是其深受诟病的一点。由于其靠近少年宫,广州塔,广州历史博物馆,而且空间开阔,成了许多家长带孩子的好去处。为了接纳儿童,甚至专门开辟了一侧楼馆作为儿童读书阅览的空间,在我看来图书馆的人流量显然是远超旁边博物馆的。而人流过大尤其是亲子十分多,导致广图尤其是暑假时相当嘈杂,即便工作人员已经相当努力地在维护环境了。因此从体验上来说这里更像是热闹购书中心,而非充满书香气息的,安静的,符合人们想象中的“图书馆”。

不过,我今天倒不是要花时间去批判广图如何如何过于嘈杂,毕竟这已经在社交媒体上被讲烂了。

我想讲的是文章开头的提问。

广州图书馆何处最为静谧而有图书馆的气息?

阅读全文 »
123
Fszer

Fszer

28 日志
8 分类
51 标签
© 2019 Fszer
由 Hexo 强力驱动
|
主题 — NexT.Mist v5.1.3