JavaScript에서 "yield"키워드에 대해 들었지만 그에 대한 문서가 매우 부족했습니다. 누군가 나에게 사용법과 용도를 설명 할 수 있습니까?
JavaScript에서 "yield"키워드에 대해 들었지만 그에 대한 문서가 매우 부족했습니다. 누군가 나에게 사용법과 용도를 설명 할 수 있습니까?
답변:
MDN 문서는 IMO, 아주 좋은 것입니다.
yield 키워드를 포함하는 함수는 생성기입니다. 호출하면 형식 매개 변수는 실제 인수에 바인딩되지만 본문은 실제로 평가되지 않습니다. 대신 생성기-반복기가 리턴됩니다. generator-iterator의 next () 메소드를 호출 할 때마다 반복 알고리즘을 통해 다른 패스를 수행합니다. 각 단계의 값은 yield 키워드로 지정된 값입니다. yield를 생성기-반복기 버전의 리턴으로 생각하여 알고리즘의 각 반복 사이의 경계를 나타냅니다. next ()를 호출 할 때마다 생성기 코드는 수율에 따라 명령문에서 재개됩니다.
늦게 대답하면 아마 모든 사람들이 yield
지금 알고 있지만 더 나은 문서가 나왔습니다.
공식 하모니 표준을 위해 James Long 의 "Javascript 's Future : Generators" 에서 예를 채택 :
function * foo(x) {
while (true) {
x = x * 2;
yield x;
}
}
"foo를 호출하면 다음 메소드가있는 Generator 객체를 다시 얻게됩니다."
var g = foo(2);
g.next(); // -> 4
g.next(); // -> 8
g.next(); // -> 16
그래서 yield
일종의 같은 것입니다 return
: 당신은 무언가를 되 찾습니다. return x
의 값을 반환 x
하지만 yield x
다음 값으로 반복 할 수있는 메서드를 제공하는 함수를 반환합니다. 반복 중에 중단 할 수 있는 메모리 집약적 인 프로 시저 가있는 경우 유용합니다 .
function* foo(x){
이
*
토큰 을 추가합니다 . 필요 여부는 귀국하는 미래의 종류에 따라 다릅니다. 세부 사항은 길다 : GvR은 파이썬 구현에 대해 설명 하고 자바 스크립트 구현이 모델링된다. 경우에 따라 사용하는 function *
것보다 약간 더 많은 오버 헤드가 있지만 사용하는 것이 항상 옳 function
습니다 yield
.
function *
하고 yield
, 상기 인용 된 에러 ( "수율이나 수율 *식이 아닌 함수 발생기에서 발생하는 경우, 초기 오류가 발생")을 추가했다. 그러나 Firefox의 원래 Javascript 1.7 구현 에는을 요구하지 않았습니다*
. 이에 따라 답변이 업데이트되었습니다. 감사!
정말 간단합니다. 이것이 작동하는 방식입니다
yield
키워드는 단순히 비동기식 으로 언제든지 함수 를 일시 중지 및 재개 하는 데 도움이됩니다. .이 간단한 생성기 함수를 사용하십시오.
function* process() {
console.log('Start process 1');
console.log('Pause process2 until call next()');
yield;
console.log('Resumed process2');
console.log('Pause process3 until call next()');
let parms = yield {age: 12};
console.log("Passed by final process next(90): " + parms);
console.log('Resumed process3');
console.log('End of the process function');
}
let _process = process ();
당신이 호출 할 때까지 () _process.next 가 실 거예요 실행] 처음 2 줄 의 코드를 다음 첫 번째 수율이 됩니다 일시 정지 기능을. 다음 일시 정지 지점 ( yield 키워드 ) 까지 함수 를 재개 하려면 _process.next () 를 호출해야합니다 .
단일 함수 내에서 자바 스크립트 디버거 의 여러 수율 이 중단 점 이라고 생각할 수 있습니다 . 다음 중단 점을 탐색하도록 지시 할 때까지 코드 블록을 실행하지 않습니다. ( 참고 : 전체 응용 프로그램을 차단하지 않고)
그러나 yield는 이러한 일시 정지 및 재개 동작을 수행하지만
이전 함수에 따라 값을 생성하지 않은 결과 를 반환 할 수 있습니다 {value: any, done: boolean}
. 이전 출력을 살펴보면 undefined{ value: undefined, done: false }
값과 동일하게 표시됩니다 .
yield 키워드를 파헤칩니다. 선택적으로 expression 을 추가 하고 기본 선택적 값을 지정하도록 설정할 수 있습니다 . (공식 문서 구문)
[rv] = yield [expression];
expression : 생성기 함수에서 반환 할 값
yield any;
yield {age: 12};
rv : 생성기 next () 메소드에 전달 된 선택적 값을 리턴합니다.
이 메커니즘을 사용하여 process () 함수에 매개 변수를 전달하여 다른 항복 파트를 실행할 수 있습니다.
let val = yield 99;
_process.next(10);
now the val will be 10
사용법
참고 문헌 :
Nick Sotiros의 답변을 단순화 / 정교하게 만드는 방법은 훌륭하다고 생각합니다 yield
.
내 의견으로는, 사용의 가장 큰 장점 yield
코드에서 볼 수있는 모든 중첩 콜백 문제를 제거한다는 것입니다. 처음에는 방법을 알기가 어렵 기 때문에이 답변을 작성하기로 결정했습니다 (나 자신과 다른 사람들을 위해)!
이를 수행하는 방법은 필요한 것을 얻을 때까지 자발적으로 중지 / 일시 정지 할 수있는 기능인 공동 루틴 아이디어를 도입하는 것입니다. 자바 스크립트에서 이는로 표시됩니다 function*
. function*
기능 만 사용할 수 있습니다 yield
.
다음은 일반적인 자바 스크립트입니다.
loadFromDB('query', function (err, result) {
// Do something with the result or handle the error
})
이제 모든 코드 (이 loadFromDB
호출 을 기다려야 함 ) 가보기 흉한 콜백 안에 있어야하기 때문에 이것은 복잡합니다 . 몇 가지 이유로 나쁘다 ...
})
어디서나 추적 해야하는 이 끝 이있다function (err, result)
전문 용어result
반면 에을 사용하면 멋진 공동 루틴 프레임 워크를 사용하여 한 줄yield
로이 모든 작업을 수행 할 수 있습니다 .
function* main() {
var result = yield loadFromDB('query')
}
따라서 이제 주요 함수는 변수와로드 될 때까지 기다려야 할 때 필요한 곳에서 생성됩니다. 그러나 이제 이것을 실행하려면 일반 (비 병렬 함수) 을 호출해야합니다 . 간단한 공동 루틴 프레임 워크로이 문제를 해결할 수 있으므로 다음을 실행하면됩니다.
start(main())
그리고 시작이 정의됩니다 (Nick Sotiro의 답변에서)
function start(routine, data) {
result = routine.next(data);
if(!result.done) {
result.value(function(err, data) {
if(err) routine.throw(err); // continue next iteration of routine with an exception
else start(routine, data); // continue next iteration of routine normally
});
}
}
이제 더 읽기 쉽고 삭제하기 쉽고 들여 쓰기, 함수 등으로 바이올린을 칠 필요가없는 아름다운 코드를 가질 수 있습니다.
이 예제에서는 yield
실제로 콜백이있는 함수 앞에 넣을 수있는 키워드 일뿐입니다.
function* main() {
console.log(yield function(cb) { cb(null, "Hello World") })
}
"Hello World"를 인쇄합니다. 따라서 실제로 yield
동일한 함수 서명 (cb없이)을 만들고을 반환 하여 콜백 함수를 실제로 사용할 수 있습니다 function (cb) {}
.
function yieldAsyncFunc(arg1, arg2) {
return function (cb) {
realAsyncFunc(arg1, arg2, cb)
}
}
이 지식 으로 삭제하기 쉬운 더 읽기 쉽고 깔끔한 코드를 작성할 수 있기를 바랍니다 .
function*
는 수율이없는 정규 함수입니까?
function *
을 포함 하는 함수 라는 것을 의미한다고 생각합니다 . 제너레이터라고하는 특별한 기능입니다.
yield
모든 곳에서 사용하는 사람들에게는 이것이 콜백보다 더 의미가 있다고 확신하지만 콜백보다 더 읽기 쉬운 방법은 알 수 없습니다.
완전한 대답을 제공하려면 : yield
과 비슷 return
하지만 발전기에서 작동합니다 .
일반적으로 주어진 예제와 같이 다음과 같이 작동합니다.
function *squareGen(x) {
var i;
for (i = 0; i < x; i++) {
yield i*i;
}
}
var gen = squareGen(3);
console.log(gen.next().value); // prints 0
console.log(gen.next().value); // prints 1
console.log(gen.next().value); // prints 4
그러나 yield 키워드의 두 번째 목적도 있습니다. 생성기에 값을 보내는 데 사용할 수 있습니다.
명확히하기 위해 작은 예 :
function *sendStuff() {
y = yield (0);
yield y*y;
}
var gen = sendStuff();
console.log(gen.next().value); // prints 0
console.log(gen.next(2).value); // prints 4
이 값 2
은에 할당 된 대로 y
첫 번째 수확량 (으로 반환 된 0
) 에서 중지 된 후 생성기로 전송하여 작동합니다 .
이것은 우리에게 정말 펑키 한 것들을 가능하게합니다. (코 루틴 조회)
반복자 생성기에 사용됩니다. 기본적으로 절차 코드를 사용하여 (잠재적으로 무한한) 시퀀스를 만들 수 있습니다. Mozilla 설명서를 참조하십시오 .
yield
코 루틴 프레임 워크를 사용하여 콜백 지옥을 제거하는 데 사용할 수도 있습니다.
function start(routine, data) {
result = routine.next(data);
if(!result.done) {
result.value(function(err, data) {
if(err) routine.throw(err); // continue next iteration of routine with an exception
else start(routine, data); // continue next iteration of routine normally
});
}
}
// with nodejs as 'node --harmony'
fs = require('fs');
function read(path) {
return function(callback) { fs.readFile(path, {encoding:'utf8'}, callback); };
}
function* routine() {
text = yield read('/path/to/some/file.txt');
console.log(text);
}
// with mdn javascript 1.7
http.get = function(url) {
return function(callback) {
// make xhr request object,
// use callback(null, resonseText) on status 200,
// or callback(responseText) on status 500
};
};
function* routine() {
text = yield http.get('/path/to/some/file.txt');
console.log(text);
}
// invoked as.., on both mdn and nodejs
start(routine());
yield 키워드를 사용하는 피보나치 시퀀스 생성기.
function* fibbonaci(){
var a = -1, b = 1, c;
while(1){
c = a + b;
a = b;
b = c;
yield c;
}
}
var fibonacciGenerator = fibbonaci();
fibonacciGenerator.next().value; // 0
fibonacciGenerator.next().value; // 1
fibonacciGenerator.next().value; // 1
fibonacciGenerator.next().value; // 2
Yeild
자바 스크립트 함수의 키워드는 생성기를 만듭니다.
자바 스크립트에서 제너레이터 란 무엇입니까?
제너레이터는 단일 값 대신 일련의 결과를 생성하는 함수입니다. 즉 일련의 값을 생성합니다.
의미 생성기는 도움말 반복자와 비동기식으로 작업하는 데 도움이됩니다. 이제 해킹 반복자가 무엇입니까? 정말?
반복자는 한 번에 하나의 항목에 액세스 할 수있는 수단입니다.
한 번에 하나씩 항목에 액세스하는 데 반복자가 도움이되는 곳부터? 생성기 함수를 통해 항목에 액세스하는 데 도움이됩니다.
생성기 함수는 yeild
키워드 를 사용하는 함수이며 , 키워드를 생성하면 함수 실행을 일시 중지하고 다시 시작하는 데 도움이됩니다.
여기 빠른 예가 있습니다
function *getMeDrink() {
let question1 = yield 'soda or beer' // execution will pause here because of yield
if (question1 == 'soda') {
return 'here you get your soda'
}
if (question1 == 'beer') {
let question2 = yield 'Whats your age' // execution will pause here because of yield
if (question2 > 18) {
return "ok you are eligible for it"
} else {
return 'Shhhh!!!!'
}
}
}
let _getMeDrink = getMeDrink() // initialize it
_getMeDrink.next().value // "soda or beer"
_getMeDrink.next('beer').value // "Whats your age"
_getMeDrink.next('20').value // "ok you are eligible for it"
_getMeDrink.next().value // undefined
무슨 일인지 설명해 보자
각 yeild
키워드 에서 실행이 일시 중지되었으며 yield
반복자의 도움을 받아 먼저 액세스 할 수 있습니다..next()
이것은 yield
한 번에 하나씩 모든 키워드를 반복 한 다음 yield
간단한 단어로 키워드 가 더 이상 남아 있지 않으면 undefined를 반환합니다. yield
키워드는 중단 될 때마다 함수가 일시 중지되고 반복자를 사용하여 호출 할 때만 다시 시작되는 중단 점 이라고 말할 수 있습니다.
우리의 경우 : _getMeDrink.next()
이것은 함수의 각 중단 점에 액세스하는 데 도움이되는 반복기의 예입니다.
발전기의 예 :
async/await
당신이 당신의 구현을 볼 경우 작동 하는 데 사용 async/await
됩니다 참조generator functions & promises
async/await
어떤 제안도 환영합니다.
비동기 자바 스크립트 호출 간의 종속성
수확량을 사용하는 방법에 대한 또 다른 좋은 예입니다.
function request(url) {
axios.get(url).then((reponse) => {
it.next(response);
})
}
function* main() {
const result1 = yield request('http://some.api.com' );
const result2 = yield request('http://some.otherapi?id=' + result1.id );
console.log('Your response is: ' + result2.value);
}
var it = main();
it.next()
생산량에 대해 배우기 전에 발전기에 대해 알아야합니다. 생성기는 function*
구문을 사용하여 작성됩니다 . 생성기 함수는 코드를 실행하지 않고 생성기라는 반복기 유형을 반환합니다. next
메소드를 사용하여 값을 지정 하면 생성기 함수는 yield 키워드를 발견 할 때까지 계속 실행됩니다. 를 사용 yield
하면 하나는 값이고 다른 하나는 수행됩니다 (부울). 값은 배열, 객체 등이 될 수 있습니다.
간단한 예 :
const strArr = ["red", "green", "blue", "black"];
const strGen = function*() {
for(let str of strArr) {
yield str;
}
};
let gen = strGen();
for (let i = 0; i < 5; i++) {
console.log(gen.next())
}
//prints: {value: "red", done: false} -> 5 times with different colors, if you try it again as below:
console.log(gen.next());
//prints: {value: undefined, done: true}
또한 yield 키워드를 이해하려고합니다. 내 현재 이해를 바탕으로 generator에서 yield 키워드는 CPU 컨텍스트 스위치처럼 작동합니다. yield 문이 실행되면 모든 상태 (예 : 로컬 변수)가 저장됩니다.
이 외에도 직접적인 결과 객체가 {value : 0, done : false}와 같이 호출자에게 반환됩니다. 호출자는이 결과 객체를 사용하여 next ()를 호출하여 생성기를 다시 '깨 울지'여부를 결정할 수 있습니다 (next () 호출은 실행을 반복 함).
또 다른 중요한 점은 값을 로컬 변수로 설정할 수 있다는 것입니다. 이 값은 생성기를 '웨이크 업'할 때 'next ()'호출자가 전달할 수 있습니다. 예를 들어 다음과 같이 it.next ( 'valueToPass') : "resultValue = yield slowQuery (1);" 다음 실행을 깨울 때와 마찬가지로 호출자는 실행에 일부 실행 결과를 로컬 변수에 주입하여 실행할 수 있습니다. 따라서이 실행에는 두 가지 상태가 있습니다.
마지막 실행에서 저장 한 컨텍스트
이 실행 트리거에 의해 주입 된 값.
따라서이 기능을 사용하면 생성기가 여러 비동기 작업을 정렬 할 수 있습니다. 첫 번째 비동기 쿼리의 결과는 로컬 변수 (위의 예에서 resultValue)를 설정하여 두 번째 비동기 쿼리에 전달됩니다. 두 번째 비동기 쿼리는 첫 번째 비동기 쿼리의 응답에 의해서만 트리거 될 수 있습니다. 그런 다음 두 번째 비동기 쿼리는 로컬 변수 값을 확인하여 다음 단계를 결정합니다. 로컬 변수는 첫 번째 쿼리의 응답에서 주입 된 값이기 때문입니다.
비동기 쿼리의 어려움은 다음과 같습니다.
콜백 지옥
콜백에서 매개 변수로 전달하지 않으면 컨텍스트가 손실됩니다.
수율과 생성기는 두 가지 모두에 도움이 될 수 있습니다.
수율과 생성기가 없으면 여러 비동기 쿼리를 정렬하려면 읽기 및 유지 관리가 쉽지 않은 컨텍스트로 매개 변수를 사용하는 중첩 콜백이 필요합니다.
다음은 nodejs로 실행되는 체인 비동기 쿼리 예제입니다.
const axios = require('axios');
function slowQuery(url) {
axios.get(url)
.then(function (response) {
it.next(1);
})
.catch(function (error) {
it.next(0);
})
}
function* myGen(i=0) {
let queryResult = 0;
console.log("query1", queryResult);
queryResult = yield slowQuery('https://google.com');
if(queryResult == 1) {
console.log("query2", queryResult);
//change it to the correct url and run again.
queryResult = yield slowQuery('https://1111111111google.com');
}
if(queryResult == 1) {
console.log("query3", queryResult);
queryResult = yield slowQuery('https://google.com');
} else {
console.log("query4", queryResult);
queryResult = yield slowQuery('https://google.com');
}
}
console.log("+++++++++++start+++++++++++");
let it = myGen();
let result = it.next();
console.log("+++++++++++end+++++++++++");
아래는 실행 결과입니다.
+++++++++++ start +++++++++++
query1 0
+++++++++++ end +++++++++++
query2 1
query4 0
아래 상태 패턴은 위의 예와 비슷한 작업을 수행 할 수 있습니다.
const axios = require('axios');
function slowQuery(url) {
axios.get(url)
.then(function (response) {
sm.next(1);
})
.catch(function (error) {
sm.next(0);
})
}
class StateMachine {
constructor () {
this.handler = handlerA;
this.next = (result = 1) => this.handler(this, result);
}
}
const handlerA = (sm, result) => {
const queryResult = result; //similar with generator injection
console.log("query1", queryResult);
slowQuery('https://google.com');
sm.handler = handlerB; //similar with yield;
};
const handlerB = (sm, result) => {
const queryResult = result; //similar with generator injection
if(queryResult == 1) {
console.log("query2", queryResult);
slowQuery('https://1111111111google.com');
}
sm.handler = handlerC; //similar with yield;
};
const handlerC = (sm, result) => {
const queryResult = result; //similar with generator injection;
if (result == 1 ) {
console.log("query3", queryResult);
slowQuery('https://google.com');
} else {
console.log("query4", queryResult);
slowQuery('https://google.com');
}
sm.handler = handlerEnd; //similar with yield;
};
const handlerEnd = (sm, result) => {};
console.log("+++++++++++start+++++++++++");
const sm = new StateMachine();
sm.next();
console.log("+++++++++++end+++++++++++");
다음은 실행 결과입니다.
+++++++++++ start +++++++++++
query1 0
+++++++++++ end +++++++++++
query2 1
query4 0