简介

Generator 自动管理流程学习笔记。

Generator 使用

1、执行 g.next(): 会将上一步 yield 后面语句的执行结果设置为 undefined, 此时执行器状态为 { value: '当前 yiled 结果', done }

2、执行g.next(value): 会将上一步 yield 后面语句的执行结果设置为 value, 此时执行器状态为 { value: '当前 yiled 结果', done }

3、执行g.return(value): 会忽略所有的 yield 语句, 直接设置执行器状态为 { value, done: true }


4、Generator 函数是遍历器函数,执行 Generator 函数会生成遍历器对象;遍历器对象具有遍历器接口如下;
例: function* numbers() { yield 1; yield 2; return 3; yield 4; }

4.1. 扩展运算符: [...numbers()] // [1, 2]

4.2. Array.form 方法: Array.from(numbers()) // [1, 2]

4.3. 解构赋值(不需要调用next方法): let [x, y] = numbers(); // 1 2

4.4. for...of 不需要调用next方法): for (let n of numbers()) { console.log(n); } // 1 2


5、某对象的 Symbol.iterator 属性为遍历器函数,则 该对象 变为遍历器对象,具有遍历器接口。例:
function* gen() {}
let g = gen(); // g 为遍历器对象
g[Symbol.iterator] === gen
g[Symbol.iterator]() === g


6、yield*: 在一个 Generator 函数执行另一个 Generator 函数,yield* 后面跟遍历器对象。

Thunk函数自动执行

Thunk函数定义

1、编译器的"传名调用"实现,往往是将参数放到一个临时函数之中,
再将这个临时函数传入函数体。这个临时函数就叫做 Thunk 函数。

2、在 JavaScript 语言中,Thunk 函数替换的不是表达式,
而是多参数函数,将其替换成单参数的版本。

Thunk函数实现

var Thunk = function(fn) {
    return function(...args) {
        return function(callback) {
            return fn.call(this, ...args, callback);
        };
    };
};

Thunk函数案例

let fs = require('fs');
let readFile = Thunk(fs.readFile);

let genFuc = function* () {
    let f1 = yield readFile('file1');
    let fn = yield readFile('fileN');
};

执行流程分析

let g = genFuc();
let r1 = g.next();

// == r1.value 是一个函数: Thunk 函数的最后一层
// == Thunk(fs.readFile)('file1')(callback) 等价于 fs.readFile('file1', callback)
// == 即 r1.value(callback) 等价于 fs.readFile('file1', callback)
// == 通过 r2 = g.next(data) 设置 r1.value(callback) 【即第一个 yield 表达式】的值
r1.value(function(err, data) {
    if (err) throw err;
    let r2 = g.next(data);
    r2.value(function(err, data) {
        if (err) throw err;
        g.next(data);
    });
});

自动执行流程

function run(genFuc) {
    let gen = genFuc();
    function callback(err, data) {
        let result = gen.next(data);
        if (result.done) return;
        /** 递归调用 */
        result.value(callback);
    }
    callback();
}
run(genFuc);

Promise对象自动执行

Promise对象案例

let fs = require('fs');
let readFile = function(fileName) {
  return new Promise(function(resolve, reject) {
    fs.readFile(fileName, function(error, data) {
      if (error) reject(error);
      resolve(data);
    });
  });
};

let genFuc = function* () {
    let f1 = yield readFile('file1');
    let fn = yield readFile('fileN');
};

执行流程分析

let g = genFuc();
let r1 = g.next();

// == r1.value 是一个 Promise
// == readFile('file1') 等价于 Promise.resolve(fs.readFile('file1'))
// == 则 r1.value.then(resolve) 等价于 Promise.resolve(fs.readFile('file1')).then(resolve)
// == 通过 r2 = g.next(data) 设置 r1.value 【即第一个 yield 表达式】的值
r1.value.then(function(data) {
    let r2 = g.next(data);
    r2.value.then(function(data) {
        g.next(data);
    });
});

自动执行流程

const run = function (genFuc) {
    let gen = genFuc();
    const resolve = function (data) {
        const r = gen.next(data);
        if (r.done) return r.value;
        else r.value.then(data => resolve(data))
    }
    resolve();
}
run(genFuc);

斐波那契数列

generator函数实现

function* dycFib() {
    let prev = 1
    let curr = 1
    // == 每次遍历返回的是yield后面的值:即prev的值
    while (true) {
        yield prev; 
        // == 变量结构赋值
        [prev, curr] = [curr, prev + curr];
    }
}

动态规划实现

function dycFib(n) {
    var arr = [];
    arr[0] = 1;
    arr[1] = 1;
    for (var i = 2; i < n; i++) {
        arr[i] = arr[i - 1] + arr[i - 2];
    }
    return arr[n - 1];
}

递归实现

function fib(n) {
    if (n === 1 || n === 2) {
        return 1;
    }
    return fib(n - 1) + fib(n - 2);
}

参考资料

powered by Gitbook该文件修订时间: 2023-05-16 18:08:03

results matching ""

    No results matching ""