Categrory · Coding

异步 & 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 会给你答案。

1/n- Cycle | 6kyu

Details

Let be n an integer prime with 10 e.g. 7.

1/7 = 0.142857 142857 142857 ....

We see that the decimal part has a cycle: 142857. The length of this cycle is 6. In the same way:

1/11 = 0.09 09 09 .... Cycle length is 2.

Task

Given an integer n (n > 1), the function cycle(n) returns the length of the cycle if n and 10 are coprimes, otherwise returns -1.

Exemples:

cycle(5) = -1
cycle(13) = 6 -> 0.076923 076923 0769
cycle(21) = 6 -> 0.047619 047619 0476
cycle(27) = 3 -> 0.037 037 037 037 0370
cycle(33) = 2 -> 0.03 03 03 03 03 03 03 03
cycle(37) = 3 -> 0.027 027 027 027 027 0
cycle(94) = -1 

cycle(22) = -1 since 1/22 ~ 0.0 45 45 45 45 ...

Note

  • Translators are welcome for all languages.

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 方面,对于数值较小的数字,通常方法很容易计算,一旦涉及到九位十位往上的大数,一般的循环方法就会耗时很久。

@wraps | 6kyu

要点

  • decorator 装饰器用法
  • tryexceptelse control flow
  • getattr()setattr()
  • __dict__.update()

Details

Implement the functools.wraps decorator, which is used to preserve the name and docstring of a decorated function. Your decorator must not modify the behavior of the decorated function. Here’s an example :

def identity(func):
  @wraps(func)
  def wrapper(*args, **kwargs):
    """Wraps func"""
    return func(*args, **kwargs)
  return wrapper

@identity
def return_one():
  """Return one"""
  return 1

return_one.__name__ == 'return_one' # If wraps hadn't been used, __name__ would be equal to 'wrapper'
return_one.__doc__ == 'Return one' # If wraps hadn't been used, __doc__ would be equal to 'Wraps func'

Note: of course, you may not use the functools module for this kata.

题目要求,经过一次二重的装饰器,保留原来函数的 __name____doc__。二重装饰器 decorator,就是用一个 decorator 去 decorate 另一个 decorator。该二重装饰器装饰后的函数, 输出的是一重装饰器装饰过的函数,但是 __name____doc__ 得到保留,及为原函数的值。

依照题目给的例子,就是输出是被 decorator wraps 修饰过的 wrapper 函数,即函数主体和功能还是 wrapper,但因为被 wraps 装饰了,输出的 wrapper 函数的 __name____doc__ 值为原函数 return_one 的值。

Binary Search Trees | 5kyu

要点

  • __str__() 的几种定义方法:如 "%s" % value'{}'.format()
  • A and B and C
  • ifelse 单行语句
  • forin 单行语句
  • join() 函数
  • str() 函数与 __str__() 方法

Details

A Tree consists of a root, which is of type Node, and possibly a left subtree of type Tree and possibly a right subtree of type Tree. If the left subtree is present, then all its nodes are less than the parent tree’s root and if the right tree is present, then all its nodes are greater than the parent tree’s root. In this kata, classes Tree and Node have been provided. However, the methods __eq__, __ne__, and __str__ are missing from the Tree class. Your job is to provide the implementation of these methods. The example test cases should provide enough information to implement these methods correctly.

As an illustrative example, here is the string representation of a tree that has two nodes, ‘B’ at the root and ‘C’ at the root of the right subtree. The left subtree is missing and the right subtree is a leaf, i.e., has no subtrees:

'[_ B [C]]'

This tree is obtained by evaluating the following expression:

Tree(Node('B'), None, Tree(Node('C'))))

Notice in particular that when one subtree, but not both, is missing, an underscore is in its place, a single space separates the root node from the subtrees, and when both subtrees are missing, the root node is enclosed in brackets.

Born to be chained | 4kyu

  • 对于 Object 的遍历;

Details

Function composition is a powerful technique. For example:

function sum(x, y) {
  return x + y;
}

function double(x) {
  return sum(x, x);
}

function minus (x, y) {
  return x - y;
}

function addOne(x) {
  return sum(x, 1);
}

double(sum(2, 3)); // 10

But in complex expressions, composition may be difficult to understand. For example:

double(double(addOne(sum(7, minus(sum(5, sum(4, 5)), 4))))); // 72

In this kata, we will implement a function that allows us to perform this by applying a fluid style:

c.sum(4, 5).sum(5).minus(4).sum(7).addOne().double().double().execute(); // 72

Your job is implement the chain function:

function chain(fns) {
}

var c = chain({sum: sum, minus: minus, double: double, addOne: addOne});

As you can see, this function receives the methods to be chained and returns an object that allows you to call the chained methods. The result is obtained by calling the executemethod.

Chained functions receive an arbitrary number of arguments. The first function in the chain receives all its arguments. In the other functions, the first argument is the result of the previous function and then it only receives the remainder arguments (second, third, etc.). The tests always pass the appropriate arguments and you do not have to worry about checking this.

Note that the chain can be reused (the internal state is not stored):

象棋 (Xiangqi/Chinese Chess) Board Validator | 4kyu

Details

Your friend recently has shown you some chess puzzles he found somewhere. It’s not your ordinary chess: but the mysterious, distinct relative of chess, the legendary 象棋, also known as Xiangqi/Chinese chess! As a Chinese, you know that your friend doesn’t know anything in Chinese besides recognizing a few sigils (for example, he doesn’t know what is 七步擒士 or 雙馬飲泉), so it’s probably likely that the “puzzles” he got is actually bogus, and the pieces are not placed properly. However, you don’t want to actually teach him Xiangqi either (yet), so the best tactic you could come up with is to write a validator program and let your friend use it instead of using you.


You will be given an ASCII board. Xiangqi board is 9 tiles wide and 10 tiles high, with the pieces placed as follows:

Example (the starting Xiangqi board):

車馬象士將士象馬車
   |X|   
 砲 +-+ 砲 
卒 卒 卒 卒 卒
---------
---------
兵 兵 兵 兵 兵
 炮 +-+ 炮 
   |X|   
俥傌相仕帥仕相傌俥

The bottom and top half corresponds to red and black pieces, respectively.
Note that red and black have different characters to distinguish the same piece of both sides.

Your function, chessValidator, should determine whether the pieces in argument board are placed legally. Unlike the chess you’re familiar with, there are restrictions as to where the various chess pieces can be at:

Argument Mapper | 5kyu

Details

As part of a broader functionality you need to develop an argument mapper.

The function receives a function object as first parameter and an unknown number of arguments [zero to many]. You have to return an associative array that maps the name of an argument and its related value.

The usage is:

function func1(arg1, arg2) { ... }

var map = createArgumentMap(func1,'valueOfArg1', 'valueOfArg2');
console.log(map['arg1']);  // writes 'valueOfArg1'
console.log(map['arg2']);  // writes 'valueOfArg2'

The passed values are in the same order as they appear in the function object.

Invalid inputs, e.g. non-function objects, or wrong number of arguments, are not considered.

Hajime!

Default Arguments | 4kyu

Details

Write a function defaultArguments. It takes a function as an argument, along with an object containing default values for that function’s arguments, and returns another function which defaults to the right values.

You cannot assume that the function’s arguments have any particular names.

You should be able to call defaultArguments repeatedly to change the defaults.

function add(a,b) { return a+b;};

var add_ = defaultArguments(add,{b:9});
add_(10); // returns 19
add_(10,7); // returns 17
add_(); // returns NaN

add_ = defaultArguments(add_,{b:3, a:2});
add_(10); // returns 13 now
add_(); // returns 5

add_ = defaultArguments(add_,{c:3}); // doesn't do anything, since c isn't an argument
add_(10); // returns NaN
add_(10,10); // returns 20

HINT: This problem requires using Fuction.prototype.toString() in order to extract a function’s argument list

分类

标签