Tag · JavaScript

多个项目共享 Webpack

最近在看 @keyframer 的一系列视频,需要用到 webpack 来配置 scss 环境,这就导致了每一个项目都要重复下载一遍 webpack 和相关的所有 node modules,这样很浪费空间。

因此要想办法把 webpack 独立出来,让每一个项目都可以访问到 webpack,一个方法是全局安装 webpack。这里提供另一种方法,想到我们通常使用 webpack 的情景是,在 package.json 里预先定义好

"scripts": {
    "dev": "webpack-dev-server",
    "build": "webpack"
}

然后 npm run dev。我们需要把这里修改一下,让每个项目都统一调用同一个 webpack。

Lazy Evaluation, foldr | 5kyu

关于 lazy evaluation,首先要明白两个概念:call by name 和 call by value:

// Evaluates with call-by-name strategy
1 function callByName (a, b) {
2  if (a === 1) {
3    return 10
4  }
5  return a + b
6 }
// Evaluates with call-by-value strategy
1 function callByValue (a, b) {
2  if (a === 1) {
3    return 10
4  }
5  return a + b
6 }

两个函数在形式上没有什么区别,只是在运行时采取了不同的策略或态度,前者是 lazy,后者是 eager;

> callByName (1, 2 + 3)
> a === 1
> return 10

> callByValue(1, 2 + 3)
> callByValue(1, 5)
> a === 1
> return 10

使用 lazy evaluation,只用当真正需要读取这个变量或 expression 的时候,才会对其进行运算或 evaluate,也就是字面意义上的 call by need。

实现 lazy evaluation 有很多方法,但其核心概念则是 functional programming。即我们把所有的 variable 写成函数的形式,这样的函数通常被称为 thunk:

JavaScript: Semicolon 二三事

由于 JavaScript 拥有 Automatic Semicolon Insertion 这样的机制,我已经很长时间在写 js 的时候不加分号了。但今天碰到了这样的一个情况:

let i = 0

(function test () {
  console.log('hello')
})()

这里会提示报错:

TypeError: 0 is not a function

观察了一会儿,才发现,JavaScript 引擎一定是把第一行和第三行看成一行代码,按道理,第一行末尾应该是要自动加一个分号的。这里如果我们手动加上分号,程序就不会报错了。

let i = 0;

(function test () {
  console.log('hello')
})()

关于 JavaScript 的 Automatic Semicolon Insertion,规则是这样的:

JSON Web Token 的产生和认证

有两种认证方式,一种是基于 cookie 的认证,另一种是基于 token 的认证。后者实现往往是通过 JSON Web Token (以下简称 JWT)实现的。首先要说明一下两种认证方式的区别:

cookie-based authentication 的认证流程是:

  1. 用户填写 credentials,包括用户名,邮箱,密码这些内容;
  2. Server 服务器验证这些 credentials 是否正确,如果正确,则认证成功,创建一个 session 存储在数据库中;
  3. 将这个 session 的 session id 存储在浏览器端的 cookie 里;
  4. 接下来的每一个请求,都会带着这个 session id,Server 在接收请求后也会验证 session id 与 session 是否匹配;
  5. 一旦用户登出,client 端和 server 端的 session 均被摧毁;

token-based authentication:

  1. 用户填写 credentials,包括用户名,邮箱,密码;
  2. Server 服务器验证这些 credentials 是否正确,如果认证成功,则返回一个 signed token;
  3. 这个 token 会被存储在 client 端,大部分是在 localStorage,但也会存储在 session storage 或是 cookie 里;
  4. 接下来的每一个请求,都会带着 token 作为额外的 authentication 信息。
  5. Server 收到请求后,首先 decode 这个 token 并对 token 里的 signature 进行验证;

auto01

为什么会说 token-based 更好:

  1. stateless,也就是不需要再在 server 端保存一份纪录,但 server 端要保存用于签名时用的「secret key」;
  2. cookie 对跨域 CORS 操作不友好,token 则没有这个问题;

JavaScript async and Promise

非常推荐先看一下参考链接里两个 youtube 视频,分别介绍了 event loop 和 setTimeout 的实现原理,这对于理解 JavaScript 里异步操作实现非常有帮助。其次是关于 Promise object 的手动实现,有一些抽象,因为包含了大量的 callback 函数。这里一定要分清楚,哪些是函数的声明,哪些是函数的调用。

Event loop

JavaScript 是一种 single thread 的语言。既然单一线程,那么在某个时间点,只能完成一项任务。于是

$.get('http://twitter.com')
$.get('http://youtube.com')
$.get('http://google.com')

在单线程下,如果某一行执行所需要的时间太久了,那么余下的的 command 也无法执行,程序就在那一行停滞下来了。我们把这个叫做 blocking。然而事实上,当我们在使用 setTimeout() 函数时,程序似乎不会出现 blocking。

console.log('hi')
setTimeout(() => console.log('there'), 0)
console.log('Welcome!')

// output:
// hi
// Welcome
// there

这里哪怕是设置 delay 为 0s, setTimeout() 里的函数也是在最后才执行,是怎么回事呢?

在 JavaScript 的执行环境中,所有的需要运行的函数是单线程的,按照次序会出现在 call stack 里。而通常,JavaScript 要么在 Browser 里运行,要么在 Node 环境运行,在 Browser 里运行时,会有一整套来自 Browser 提供的 web API,同理在 node 环境里也有相应的 API。 setTimeout() 函数就来自这些提供的 API 中。当我们 declare and call 一个 setTimeout() 函数时,Browser 会生成一个 timer 计时器,计时器的时间达到时, setTimeout() 里定义的 callback 函数会进入到一个叫 task queue 的容器中,此时程序会去检测 call stack 是否为空,当 call stack 为空时,会将 task queue 中最上层的函数移入 call stack 中进行执行。因此本质上来讲,由于有 web API 的加持,最终类似 setTimeout() 函数还是使用了多线程。只不过对于 JavaScript 来讲,一直是执行的是 call stack 里的内容,可以认为一直是单线程操作。

「User Authentication with Passport and Koa 」Summary

上周在阅读 Express.js Blueprints 时看到 Authentication 的部分,就想着使用 Koa 去复现一遍。于是在网上看到这篇文章 User Authentication with Passport and Koa 。文章给出了源代码和详细的步骤。其中不乏遇到自己不熟悉的知识领域,比如 knex,postgresql 和 redis 等等。写这篇文章的目的:一是熟悉下在 koa 框架下的程序结构;二是对于自己不熟悉的知识领域的一个总结。

需要通过 brew 安装:

  • postgresql
  • redis

使用 npm 全局安装:

  • knex

初见 Koa.js

去网上检索 Koa,往往会看到诸多 Koa 和 Express 文章。Koa 的确是比 Express 更新的框架,因此也使用到了 ES6 更新的特性,比如 async/await。Koa 的核心 module 仅仅是 middleware kernel,Express 则提供了一套完整的解决方案,功能,routing,template 这些。Koa 要使用这些需要安装额外的 module。这样的对比,容易让人联想到 editor 和 IDE 的区别,前者注重轻量,可定制,后者追求大而全的设计。两种不同的设计哲学,我是偏爱前者,相信 less is more 的力量。当然,毕竟 Koa 和 Express 都是来自于同一个开发团队,很多基础概念是相通的。阅读本文,你需要提前了解以下内容:

  • Node.js 的异步特性及异步是如何实现的
  • 异步实现的几种方式,callback 到 Promise 到 async/await
  • 什么是 middleware?
  • ejs template engine

通过本文,你能了解到。Koa 最基础的 HelloWorld,它 如何渲染一个 template 页面,传递数据。什么是「Routing 路由」,路由在 Koa 中如何实现的。

异步 & callback

最近开始学习 Node.js。主要看两本书:Node.js in PracticeNode.js Design Patterns。前者类似于 o’reilly 的 cookbook 系列,整本书的编排是通过一个个 recipe,一个个具体的 problem&solution 实现的。后者就是 Packt Publishing 出品的一系列 Design Patterns 书籍。包括这两本书在内的许多讲解 Node.js 的书籍,都会不断强调两个关键词, asynchronous 和 non-blocking I/O。在最初开始学习编程的时候,无论是写一些算法题目,或是做一些本地测试,它都是同步的,即时响应的,单线程的,blocking I/O。但如果进入的网络领域,「异步」则会被不断提起。相比 synchronous,「异步」更加接近我们相处的真实世界。

这篇文章以 Node.js Design Patterns 第二章的 Web Spider 例子,探究思考在 Node.js 中是如何通过 callback 来实现异步操作的。

Hexo Theme 开发不完全记录

决定建立一个静态 Blog,已经是 2016 年的事了。在那之前,也就是在 2016 年 4 月 5 日,自己曾经使用 Pelican 进行过短暂的尝试。生活在互联网时代,当你决定将一切电子化,义无反顾地投入比特的世界时,最大的好处便是,这以后发生的每一起事件,都有着清楚的记录。建立 Blog 这件事也不例外。但仅过 1 天,我就删除了 github 上的 repo。当时的自己这样写道:

两天的尝试发现:没有足够的知识积累,挑战就是「摸着石头过河」,到处都是困难,耐心被一点一点消磨,直到像一只无头苍蝇乱撞,而无法再耐心地解决问题。所以,博客平台搭建计划暂停。

那时自己才刚开始学 Python,也才刚开始接触 Github。其他方面更是经验甚少,处处碰壁。一年以后, 2017 年 3 月,自己使用 Hexo 建立了这个 Blog,并在 Godaddy 上购买了域名,采用 Hexo 预置主题 Next 。全面,简洁,美观大方。这个主题足够好用。当时的主题并不多,所以经常看到其他使用 Hexo 搭建的 Blog ,往往都是差不多的样式,我当时也只是改了以下 banner,才显得稍有不同。这也让我想试着自己去写一个主题。

目前看到的这个 theme 所有样式,并非我本人设计。它来自于一款付费的 WordPress theme typology。我是一次偶然的机会看到它。考虑到可能的版权问题。自己可能不会把它发布到 Themes | Hexo 或开源到 Github 上(无法联系到这个 theme 的作者)。以下我所做的大部分工作,不过是以 Hexo 的形式对 typology 的再现。为了方便。我把这个模仿之作命名为 hagoromo(羽衣)。至于为什么会叫这个名字,Google 会给你答案。

Lowest base system | 4kyu

要点

  • 除法,求余,因子
  • Number.MAX_SAFE_INTEGER
  • 二分法求方程根

Details

Your task is determine lowest number base system in which the input n (base 10), expressed in this number base system, is all 1 in its digit. See an example:

‘7’ in base 2 is ‘111’ - fits! answer is 2

‘21’ in base 2 is ‘10101’ - contains ‘0’ does not fit ‘21’ in base 3 is ‘210’ - contains ‘0’ and ‘2’ does not fit ‘21’ in base 4 is ‘111’ - contains only ‘1’ it fits! answer is 4

n is always less than Number.MAX_SAFE_INTEGER.

这个题目的难度主要在于性能 performance 方面,对于数值较小的数字,通常方法很容易计算,一旦涉及到九位十位往上的大数,一般的循环方法就会耗时很久。

分类

标签