Понимание и использование функций генератора

внешний интерфейс API Promise V8

Понимание и использование функций генератора

Функции-генераторы — это решение для асинхронного программирования, предоставляемое ES6.

1. Асинхронное программирование

1. так называемый"асинхронный", проще говоря, задача делится на две части, сначала выполняется первая часть, а затем выполняются остальные задачи.Когда вы будете готовы, вернитесь и выполните вторую часть.

2,Асинхронное программирование:

(1)回调函数

(2)事件监听

(3)发布/订阅者

(4)Promise对象

3. Так называемая функция обратного вызова заключается в том, чтобы написать второй абзац отдельно в функции, и при повторном выполнении задачи функция вызывается напрямую.

Асинхронный метод функций обратного вызова легко формирует несколько вложений, а несколько асинхронных операций образуют сильную связь.Пока необходимо изменить одну операцию, ее функция обратного вызова верхнего уровня и функция обратного вызова нижнего уровня могут быть изменены соответствующим образом. Эта ситуация называется «ад обратных вызовов».

Обещание обратный вызов Ада может решить проблему, объект для обещания позволяет вложенную функцию обратного вызова, измените цепочку вызова.

два,Что такое Генератор?

Синтаксически можно понять, что функция генератора является конечным автоматом, который инкапсулирует несколько внутренних состояний.

Формально функция Генератор является обычной функцией.

Вся функция Generator представляет собой инкапсулированную асинхронную задачу или контейнер асинхронных задач.Там, где асинхронную операцию необходимо приостановить, используется инструкция yield.

Особенности функции генератора:

(1) Существует звездочка (*) между ключевым словом функции и функцией, а экспрессия выхода используется внутри, чтобы определить разные внутренние состояния.

(2) После вызова функции Generator функция не выполняется, и возвращаемый результат не является результатом выполнения функции, а является объектом-указателем, указывающим на внутреннее состояние.

В-третьих, определите функцию генератора

function* fn(){   // 定义一个Generator函数
    yield 'hello';
    yield 'world';
    return 'end';
}
var f1 =fn();           // 调用Generator函数
console.log(f1);        // fn {[[GeneratorStatus]]: "suspended"}
console.log(f1.next()); // {value: "hello", done: false}
console.log(f1.next()); // {value: "world", done: false}
console.log(f1.next()); // {value: "end", done: true}
console.log(f1.next()); // {value: undefined, done: true}

Однако после вызова функции Generator функция не выполняется, а возвращаемый результат является не результатом выполнения функции, а объектом-указателем, указывающим на внутреннее состояние.

Затем необходимо вызвать метод next объекта обхода, чтобы переместить указатель в следующее состояние. То есть: каждый раз, когда вызывается следующий метод, внутренний указатель начинает выполняться с начала функции или с того места, где он остановился последним, до тех пор, пока не встретится следующее выражение yield (или оператор return).

Функция Generator выполняется по частям, выражение yield является маркером для приостановки выполнения, а следующий метод может возобновить выполнение.

Эффект приостановки выполнения функции Generator означает, что асинхронная операция может быть записана в операторе yield, а затем выполнена после вызова следующего метода. Фактически это эквивалентно отсутствию необходимости писать функцию обратного вызова, потому что последующие операции асинхронной операции могут быть помещены в оператор yield, и они все равно не будут выполняться до тех пор, пока не будет вызван следующий метод. Поэтому важным практическим значением функции Generator является обработка асинхронных операций и переписывание функции обратного вызова.

В-четвертых, выражение yield и метод next()

Возвращаемый объект посетителя Function Generator только для вызова следующего метода будет проходить через следующее внутреннее состояние, по сути, предоставляет способ приостановить выполнение функции.

Выражение yield — это флаг паузы.

Выражение, следующее за выражением yield, выполняется только тогда, когда вызывается следующий метод и внутренний указатель указывает на инструкцию.

Обратите внимание при использовании доходности:

(1) Оператор yield может использоваться только в области действия function*.Если другие обычные функции определены внутри функции*, оператор yield не допускается внутри функции.

(2) yield, если оператор участвует в вычислениях, он должен быть заключен в круглые скобки.

Разница между методом возврата и следующим методом:

1)return终结遍历,之后的yield语句都失效;next返回本次yield语句的返回值。

2)return没有参数的时候,返回{ value: undefined, done: true };next没有参数的时候返回本次yield语句的返回值。

3)return有参数的时候,覆盖本次yield语句的返回值,也就是说,返回{ value: 参数, done: true };next有参数的时候,覆盖上次yield语句的返回值,返回值可能跟参数有关(参数参与计算的话),也可能跟参数无关(参数不参与计算)。

Текущая логика следующего метода объекта traverser:

(1)遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。

(2)下一次调用next方法时,再继续往下执行,直到遇到下一个yield表达式。

(3)如果没有再遇到新的yield表达式,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。

(4)如果该函数没有return语句,则返回的对象的value属性值为undefined。

параметры метода next()
Указывает возвращаемое значение предыдущего выражения yield, поэтому при первом использовании следующего метода передача параметров недопустима. Движок V8 напрямую игнорирует параметры, когда метод next используется в первый раз, и параметры действительны только после второго использования метода next. Семантически первый метод next используется для запуска объекта обходчика, поэтому никаких параметров не требуется.

for... цикла
Объект Iterator, сгенерированный функцией Generator, может быть пройден автоматически, и в это время больше не нужно вызывать следующий метод. Как только свойство done возвращаемого объекта следующего метода становится истинным, цикл for...of прерывается без возвращаемого объекта.

Пример для понимания генератора:

// 定义一个Generator函数
function* foo(x) {
  var y = 2 * (yield (x + 1));
  var z = yield (y / 3);
  return (x + y + z);
}

var a = foo(5);
console.log(a.next()); // Object{value:6, done:false} 第二次运行next方法的时候不带参数,导致y的值等于2 * undefined(即NaN),除以3以后还是NaN
console.log(a.next()); // Object{value:NaN, done:false} 第三次运行Next方法的时候不带参数,所以z等于undefined,返回对象的value属性等于5 + NaN + undefined,即NaN。
console.log(a.next()); // Object{value:NaN, done:true}

var b = foo(5);
console.log(b.next());   // {value:6, done:false } 第一次调用b的next方法时,返回x+1的值6
console.log(b.next(12)); // {value:8, done:false } 第二次调用next方法,将上一次yield表达式的值设为12,因此y等于24,返回y / 3的值8;
console.log(b.next(13)); // {value:42, done:true } 第三次调用next方法,将上一次yield表达式的值设为13,因此z等于13,这时x等于5,y等于24,所以return语句的值等于42。

Пять, функция Genarator использует примеры

1. Выведите последовательность Фибоначчи

function *fibonacci(){
    let [pre, cur] = [0,1];
    for(;;){
        [pre, cur] = [cur, pre+cur];
        yield cur;
    }
}
for(let n of fibonacci()){
    if( n>1000 )
        break;
    console.log(n);
}

2. Пройдите по полному бинарному дереву

function* preOrder(root){ // 前序遍历
    if(root){
        yield  root.mid;
        yield* preOrder(root.left);
        yield* preOrder(root.right);
    }
}
function* inOrder(root){  // 中序遍历
    if(root){
        yield* inOrder(root.left);
        yield  root.mid;
        yield* inOrder(root.right);
    }
}
function* postOrder(root){ // 后序遍历
    if(root){
        yield* postOrder(root.left);
        yield* postOrder(root.right);
        yield  root.mid;
    }
}
function Node(left, mid, right){  // 二叉树构造函数
    this.left = left;
    this.mid = mid;
    this.right = right;
}
function binaryTree(arr){         // 生成二叉树
    if(arr.length == 1){
        return new Node(null, arr[0], null);
    }
    return new Node(binaryTree(arr[0]), arr[1], binaryTree(arr[2]));
}

// 完全二叉树节点
let bTree = binaryTree([[['d'], 'b', ['e']], 'a', [['f'], 'c', ['g']]]);

// 遍历结果
var preResult = [];
for(let node of preOrder(bTree)){  // 前序遍历结果
    preResult.push(node);
}
console.log(preResult);            // (7) ["a", "b", "d", "e", "c", "f", "g"]

var inResult = [];
for(let node of inOrder(bTree)){   // 中序遍历结果
    inResult.push(node);
}
console.log(inResult);              // (7) ["d", "b", "e", "a", "f", "c", "g"]

var postResult = [];
for(let node of postOrder(bTree)){  // 后序遍历结果
    postResult.push(node);
}
console.log(postResult);            // (7) ["d", "e", "b", "f", "g", "c", "a"]

3. Генератор читает текстовый файл построчно

function* readFileByLine(){
    let file = new FileReader("a.txt");
    try{
        while(!file.eof){
            yield parseInt(file.readLine(), 10); // 使用yield表达式可以手动逐行读取文件
        }
    }finally{
        file.close();
    }
}

var r = readFileByLine();
r.next();

4. Genarator развертывает операции Ajax

function* main(){ // 通过 Ajax 操作获取数据
    var result = yield request("http://some.url");
    var res = JSON.parse(result);
    console.log(res.value);
}
function request(url){
    makeAjaxCall(url, function(res){
        it.next(res);
    })
}
var it = main();
console.log(it.next());

5. Generator развертывает интерфейс Iterator для любого объекта

function* deployObjectInterface(obj){
    let keys = Object.keys(obj);
    for(let i=0; i<keys.length; i++){
        let key = keys[i];
        yield [key, obj[key]];
    }
}
let obj = {name:"Cynthia", age:21 };
for(let[key, value] of deployObjectInterface(obj)){
    console.log(key, value); 
}
// name Cynthia
// age 21

6. Genarator развертывает интерфейс Iterator в массиве.

function* deployArrayInterface(arr){
    var nextIndex = 0;
    while(nextIndex < arr.length){
        yield arr[nextIndex++];
    }
}
var arr = deployArrayInterface(['name', 'age']);

console.log(arr.next());       // {value: "name", done: false}
console.log(arr.next().value); // name
console.log(arr.next().done);  // false

console.log(arr.next().value); // age
console.log(arr.next().done);  // true

console.log(arr.next().value); // undefined
console.log(arr.next().done);  // true

PS: справочная статья6. Жуань Ифэн голодать .com/#docs/Генерал...

Категории