수색…


소개

생성자 함수 ( function* 키워드로 정의)는 코 루틴으로 실행되어 반복자를 통해 요청 될 때 일련의 값을 생성합니다.

통사론

  • 함수 * 이름 (매개 변수) {항복 값; 반환 값}
  • 생성자 = 이름 (인수)
  • {값, 완료} = generator.next (값)
  • {값, 완료} = generator.return (값)
  • generator.throw (오류)

비고

생성기 기능은 ES 2015 사양의 일부로 도입 된 기능으로 모든 브라우저에서 사용할 수있는 것은 아닙니다. 또한 v6.0 부터 Node.js에서 완전히 지원됩니다. 자세한 브라우저 호환성 목록은 MDN 설명서를 참조하고 Node는 node.green 웹 사이트를 참조하십시오.

생성기 함수

생성기 함수 는 선언 function* 함수 로 생성됩니다. 그것이 호출 될 때, 그 시체는 즉시 실행 되지 않습니다 . 대신 함수의 실행을 단계적으로 수행하는 데 사용할 수있는 생성기 객체를 반환합니다.

함수 본문 내부의 yield 식은 실행을 일시 중단하고 다시 시작할 수있는 지점을 정의합니다.

function* nums() {
    console.log('starting');  // A
    yield 1;                  // B
    console.log('yielded 1'); // C
    yield 2;                  // D
    console.log('yielded 2'); // E
    yield 3;                  // F
    console.log('yielded 3'); // G
}
var generator = nums(); // Returns the iterator. No code in nums is executed

generator.next();  // Executes lines A,B returning { value: 1, done: false }
// console: "starting"
generator.next();  // Executes lines C,D returning { value: 2, done: false }
// console: "yielded 1"
generator.next();  // Executes lines E,F returning { value: 3, done: false }
// console: "yielded 2"
generator.next();  // Executes line G returning { value: undefined, done: true }
// console: "yielded 3"

초기 반복 종료

generator = nums();
generator.next(); // Executes lines A,B returning { value: 1, done: false }
generator.next(); // Executes lines C,D returning { value: 2, done: false }
generator.return(3); // no code is executed returns { value: 3, done: true }
// any further calls will return done = true 
generator.next(); // no code executed returns { value: undefined, done: true }

생성자 함수에 오류 발생

function* nums() {
    try {
        yield 1;                  // A
        yield 2;                  // B
        yield 3;                  // C
    } catch (e) {
        console.log(e.message);    // D
    }
}

var generator = nums();

generator.next();  // Executes line A returning { value: 1, done: false }
generator.next();  // Executes line B returning { value: 2, done: false }
generator.throw(new Error("Error!!"));  // Executes line D returning { value: undefined, done: true}
// console: "Error!!"
generator.next();  // no code executed. returns { value: undefined, done: true }

되풀이

생성기는 반복 가능 합니다. for...of 문으로 반복 할 수 있으며 반복 프로토콜에 의존하는 다른 구문에 사용됩니다.

function* range(n) {
    for (let i = 0; i < n; ++i) {
        yield i;
    }
}

// looping
for (let n of range(10)) {
    // n takes on the values 0, 1, ... 9
}

// spread operator
let nums = [...range(3)];  // [0, 1, 2]
let max = Math.max(...range(100));  // 99

다음은 ES6에서 생성자 - 사용자 정의 iterable 객체를 사용하는 또 다른 예제입니다. 여기에 익명의 생성기 함수 function * 사용되었습니다.

let user = {
  name: "sam", totalReplies: 17, isBlocked: false
};

user[Symbol.iterator] = function *(){

  let properties = Object.keys(this);
  let count = 0;
  let isDone = false;

  for(let p of properties){
    yield this[p];
  }
};

for(let p of user){
  console.log( p );
} 

생성자에게 값 보내기

next() 메서드에 전달하여 값을 생성기로 보낼 수 있습니다.

function* summer() {
    let sum = 0, value;
    while (true) {
        // receive sent value
        value = yield;
        if (value === null) break;

        // aggregate values
        sum += value;
    }
    return sum;
}
let generator = summer();

// proceed until the first "yield" expression, ignoring the "value" argument
generator.next();

// from this point on, the generator aggregates values until we send "null"
generator.next(1);
generator.next(10);
generator.next(100);

// close the generator and collect the result
let sum = generator.next(null).value;  // 111

다른 생성기로 위임

발전기 기능 내에서, 제어는 yield* 사용하여 다른 발전기 기능으로 위임 될 수 있습니다.

function* g1() {
  yield 2;
  yield 3;
  yield 4;
}

function* g2() {
  yield 1;
  yield* g1();
  yield 5;
}

var it = g2();

console.log(it.next()); // 1
console.log(it.next()); // 2
console.log(it.next()); // 3
console.log(it.next()); // 4
console.log(it.next()); // 5
console.log(it.next()); // undefined

Iterator-Observer 인터페이스

생성기는 IteratorObserver 의 두 가지 조합입니다.

반복자

iterator는 호출 될 때 iterable 반환하는 무언가이다. iterable 은 반복 할 수있는 항목입니다. ES6 / ES2015부터 모든 컬렉션 (Array, Map, Set, WeakMap, WeakSet)은 Iterable 계약을 따릅니다.

생성자 (반복자)는 제작자입니다. 반복에서 소비자는 생산자로부터 가치를 PULL .

예:

function *gen() { yield 5; yield 6; }
let a = gen();

a.next() 를 호출 할 때마다 a.next() Iterator에서 값을 pull 오고 yield 에서 실행을 pause 합니다. 다음에 a.next() 를 호출하면 이전에 일시 중지 된 상태에서 실행이 다시 시작됩니다.

관찰자

생성기는 또한 일부 값을 생성기로 다시 보낼 수있는 옵서버입니다.

function *gen() {
  document.write('<br>observer:', yield 1);
}
var a = gen();
var i = a.next();
while(!i.done) {
  document.write('<br>iterator:', i.value);
  i = a.next(100);
}

여기에서 yield 1 은 어떤 값으로 평가되는 식처럼 사용된다는 것을 알 수 있습니다. 그것이 평가하는 값은 a.next 함수 호출에 인수로 보낸 값입니다.

그래서 처음으로 i.value 가 첫 번째 값 ( 1 )이되고, 다음 상태로 반복 할 때 a.next(100) 사용하여 값을 생성기로 다시 보냅니다.

생성기와 비동기하기

생성기는 spawn (taskJS 또는 co) 함수와 함께 널리 사용되며 함수는 생성기를 사용하며 동기식으로 비동기 코드를 작성할 수 있습니다. 이것은 비동기 코드가 동기 코드로 변환되거나 동 기적으로 실행된다는 의미는 아닙니다. 즉, sync 처럼 보이지만 내부적으로 여전히 async 코드를 작성할 수 있음을 의미합니다.

동기화가 차단 중입니다. 비동기 대기 중입니다. 블록하는 코드를 작성하는 것은 쉽습니다. PULLING 할 때 값이 지정 위치에 나타납니다. PUSHing 할 때 콜백의 인수 위치에 값이 나타납니다.

당신이 반복자를 사용하면 PULL 생산자의 값을. 콜백을 사용하면 생성자는 콜백의 인수 위치에 값을 PUSH 합니다.

var i = a.next() // PULL
dosomething(..., v => {...}) // PUSH

여기에서 a.next() 에서 값을 가져 a.next() 두 번째에는 v => {...} 가 콜백이고 값은 콜백 함수의 인수 위치 vPUSH 됩니다.

이 푸시 푸시 메커니즘을 사용하여 다음과 같은 비동기 프로그래밍을 작성할 수 있습니다.

let delay = t => new Promise(r => setTimeout(r, t));
spawn(function*() {
  // wait for 100 ms and send 1
  let x = yield delay(100).then(() => 1);
  console.log(x); // 1

   // wait for 100 ms and send 2
  let y = yield delay(100).then(() => 2);
  console.log(y); // 2
});

위의 코드를 보면 비 blocking (yield 문이 100ms를 기다린 다음 실행을 계속하는 것처럼 보입니다)하지만 비동기 코드가 작성되어 있지만 실제로 waiting 있습니다. 생성기의 pauseresume 속성을 사용하면이 놀라운 트릭을 수행 할 수 있습니다.

어떻게 작동합니까?

스폰 함수는 yield promise 프로 시저를 사용하여 생성기에서 약속 상태를 가져오고 약속이 해결 될 때까지 기다린 다음 해결 된 값을 생성기로 푸시하여 소비 할 수 있도록합니다.

지금 사용하십시오.

따라서 Generators 및 Spawn 기능을 사용하면 NodeJS의 모든 비동기 코드를 동기식처럼 보이게 정리할 수 있습니다. 이렇게하면 디버깅이 쉬워집니다. 또한 코드가 깔끔하게 보일 것입니다.

이 기능은 async...await as async...await 처럼 JavaScript의 차기 버전에서 제공 될 예정입니다. 그러나 라이브러리 (taskjs, co 또는 bluebird)에 정의 된 스폰 함수를 사용하여 ES2015 / ES6에서 오늘 사용할 수 있습니다

발전기가있는 비동기 흐름

생성기는 일시 중지 한 다음 실행을 재개 할 수있는 기능입니다. 이것은 외부 라이브러리, 주로 q 또는 co를 사용하여 비동기 함수를 에뮬레이션 할 수있게합니다. 기본적으로 비동기 결과를 기다리는 함수를 작성할 수 있습니다.

function someAsyncResult() {
    return Promise.resolve('newValue')
}

q.spawn(function * () {
    var result = yield someAsyncResult()
    console.log(result) // 'newValue'
})

이렇게하면 비동기 코드를 동기식으로 작성하는 것이 가능합니다. 또한 여러 비동기 블록에 대한 작업을 시도해보십시오. 약속이 거부되면 다음 catch가 오류를 포착합니다.

function asyncError() {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            reject(new Error('Something went wrong'))
        }, 100)
    })
}

q.spawn(function * () {
    try {
        var result = yield asyncError()
    } catch (e) {
        console.error(e) // Something went wrong
    }
})

co를 사용하면 q.spawn 대신 co(function * (){...})q.spawn



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow