Front End

[FE] Yield a Continuation ...

2021-03-12  本文已影响0人  何幻

1. 从 Generator 说起

ecma-262 2015 引入了 yield,它被用在了 function* 中。
用法如下:

function* gen() { 
    yield 1;
    yield 2;

    return 3;
}
const iter = gen();  // iter = generator object = (iterator/iterable)

console.log(iter.next());    // { value: 1, done: false }
console.log(iter.next());    // { value: 2, done: false }
console.log(iter.next());    // { value: 3, done: true }

其中,function* gen() { ... } 称为 generator function,返回值称为 generator object
generator object 既是一个 iterator 又是一个 iterable

2. iterator/iterable

(1)什么是 iterator

An object is an iterator when it implements a next() method that returns an object with at least the following two properties:

即,iterator 是一个实现了 next() 方法的对象,该方法返回一个 {done, value}
上面的例子反映了 generator object 确实是一个 iterator。

function* gen() { 
    yield 1;
    yield 2;

    return 3;
}
const iter = gen();
iter.next()  // {value: 1, done: false}

(2)什么是 iterable

iterable 指的是满足 iterable protocol 的对象。

In order to be iterable, an object must implement the @@iterator method, meaning that the object (or one of the objects up its prototype chain) must have a property with a @@iterator key which is available via constant Symbol.iterator

Property Value
[Symbol.iterator] A zero-argument function that returns an object, conforming to the iterator protocol.

Whenever an object needs to be iterated (such as at the beginning of a for...of loop), its @@iterator method is called with no arguments, and the returned iterator is used to obtain the values to be iterated.

即,iterable 是一个实现了 Symbol.iterator 方法的对象,该方法返回一个 iterator
我们来看 generator object 是不是一个 iterable。

function* gen() { 
    yield 1;
    yield 2;

    return 3;
}
const iter = gen();
const iterator = iter[Symbol.iterator]();
iterator.next();  // {value: 1, done: false}

并且,generator object 当做 iterable 时,Symbol.iterator 方法返回的 iterator 刚好是它自己。

const iter = gen();
const iterator = iter[Symbol.iterator]();
iter === iterator;  // true

(3)小结

generator object 大概是这样的一个对象,

const iter = {
    // iterator protocol
    next: (x) => ({ value: xxx, done: xxx }),
    // iterable protocol
    [Symbol.iterator]: () => iter
};

iter[Symbol.iterator]() === iter

3. yield*

generator function 中除了可以使用 yield 之外,还可以使用 yield*
跟 yield 不同的是,yield* 可以用来 delegate 其它的 iterable。

何为 delegate 呢?

function* gen1() {
  yield 3;
  yield 4;
}

function* gen2() {
  yield* [1, 2];
  yield* "ab";
  yield* gen1();
}

const iter = gen2();
console.log(iter.next());    // { value: 1, done: false }
console.log(iter.next());    // { value: 2, done: false }
console.log(iter.next());    // { value: "a", done: false }
console.log(iter.next());    // { value: "b", done: false }
console.log(iter.next());    // { value: 3, done: false }
console.log(iter.next());    // { value: 4, done: false }
console.log(iter.next());    // { value: undefined, done: true }

即,yield* 可以 “钻” 到 iterable 里面去 yield。

4. koa compose

koa v1.7.0 使用了 co v4.6.0 + koa-compose v2.5.1 来处理 middleware。

$ mkdir test-koa && cd test-koa
$ npm i -S koa
const Koa = require('koa');
const app = new Koa();

// logger

app.use(function *(next){
  const start = new Date;
  yield next;
  const ms = new Date - start;
  console.log('%s %s - %s', this.method, this.url, ms);
});

// response

app.use(function *(){
  this.body = 'Hello World';
});

app.listen(3000);

5. Continuation

(1)什么是 Continuation

Wikipedia: Continuation

(2)什么是 First-class Continuation

Wikipedia: Continuation#first-class_continuation
TSPL 4th Ch3.3

(+ 0 (call/cc
  (lambda (k)
    (k 1))))
=> 1
(+ 0 (call/cc
  (lambda (k)
    2)))
=> 2
(let ([x (call/cc (lambda (k) k))])
  (x (lambda (ignore) “hi”)))
=> “hi”

(3)yield 一个 Continuation

yieldContinuation(function* () {
  const v1 = yield function (cont) {
    setTimeout(function () {
      cont('Hello');
    }, 1000);
  };

  console.warn(v1);

  const v2 = yield function (cont) {
    setTimeout(function () {
      cont('World');
    }, 500);
  };

  console.warn(v2);
});

源码:yield-continuation

6. 阴阳谜题

function* solution() {
    function* yin(_yin) {
        yield '@';

        function* yang(_yang) {
            yield '*';
            yield* _yin(_yang);
        }

        yield* yang(yang);
    }

    yield* yin(yin);
}

const iter = solution();
for(const i of iter) {
  console.log(i);  // @*@**@***@****...
}
(let* [(yin ((lambda (foo) (newline) foo)
             (call/cc (lambda (bar) bar))))
       (yang ((lambda (foo) (display "*") foo)
              (call/cc (lambda (bar) bar))))]
  (yin yang))

7. Delimited Continuation

(1)什么是 Delimited Continuation

Wikipedia: delimited continuation
Continuations, coroutines, fibers, effects

(* 2 
  (reset 
    (+ 1 
      (shift k (k 5))
    )
  )
)
=> 
(* 2 
  (+ 1 5)
)

(2)Yield 一个 Delimited Continuation

Algebraic Effects in JavaScript part 3 - Delimited Continuations

const result = yieldDelimitedContinuation(function* (reset) {
  const a1 = yield 1;

  // 使用 reset 定界
  const a2 = yield reset(function* (shift) {
    const b1 = yield 2;
    const b2 = yield function* () {
      const c1 = yield 3;

      // 使用 shift 返回到 reset 位置
      const c2 = yield shift(function* () {
        const u = yield 4;
        const v = yield 5;

        // 4 + 5
        // 直接return到reset的位置 a2 = 9,然后从a2处开始执行
        return u + v;
      });
      const c3 = yield 6;
      return c1 + c2 + c3;
    };
    const b3 = yield 7;
    return b1 + b2 + b3;
  });
  const a3 = yield 8;

  // 1 + 9 + 8
  return a1 + a2 + a3;
});

console.log(result);  // 18

源码:yield-delimited-continuation

8. Algebraic Effect

至于 Algebraic Effect?恕我智商太低,实在跟不上你们的学习进度。

Algebraic operations are, in the sense we shall make precise, a natural generalisation, from Set to an arbitrary symmetric monoidal V-category C with cotensors, of the usual operations of universal algebra, taking T to be a strong V-monad on C. —— Algebraic Operations and Generic Effects


参考

ecma-262 2015

MDN: yield
MDN: generator function
MDN: generator object
MDN: iterator
MDN: iterable
MDN: yield*

github: koa v1.7.0
github: co v4.6.0
github: koa-compose v2.5.1

Wikipedia: Continuation
Wikipedia: Continuation#first-class_continuation
Wikipedia: delimited continuation

Continuations, coroutines, fibers, effects
Algebraic Effects in JavaScript part 3 - Delimited Continuations
TSPL 4th Ch3.3
Algebraic Operations and Generic Effects

上一篇下一篇

猜你喜欢

热点阅读