Что такое ключевое слово yield в JavaScript?
Я слышал о ключевом слове "yield" в JavaScript, но я нашел очень плохую документацию об этом. Может кто-нибудь объяснить мне (или порекомендовать сайт, который объясняет) его использование и для чего он используется?
8 ответов
на документация MDN довольно хорошо, ИМО.
функция, содержащая ключевое слово yield, является генератором. Когда вы вызываете его, его формальные параметры привязаны к фактическим аргументам, но его тело фактически не оценивается. Вместо этого возвращается генератор-итератор. Каждый вызов метода next() генератора-итератора выполняет еще один проход через итерационный алгоритм. Значение каждого шага-это значение, заданное ключевым словом yield. Думайте о доходности как генератор-итератор версии return, указывающий границу между каждой итерацией алгоритма. Каждый раз, когда вы вызываете next (), код генератора возобновляется из оператора после выхода.
поздний ответ, вероятно, все знают о yield
теперь, но появилась лучшая документация.
адаптация примера от "будущее Javascript: генераторы" Джеймс Лонг для официального стандарта гармонии:
function * foo(x) {
while (true) {
x = x * 2;
yield x;
}
}
" когда вы вызываете foo, вы получаете назад объект генератора который имеет следующее метод."
var g = foo(2);
g.next(); // -> 4
g.next(); // -> 8
g.next(); // -> 16
так yield
вроде как return
: вы получаете что-то взамен. return x
возвращает значение x
, а yield x
возвращает функцию, которая дает вам способ, чтобы выполнить итерации к следующему значению. Полезно, если у вас есть потенциально интенсивная процедура памяти что вы можете прервать во время итерации.
упрощение / разработка ответа Ника Сотироса (который я считаю потрясающим), я думаю, что лучше всего описать, как начать кодирование с yield
.
на мой взгляд, самое большое преимущество использования yield
заключается в том, что он устранит все проблемы вложенного обратного вызова мы видим в коде. Трудно понять, как сначала, поэтому я решил написать этот ответ (для себя и, надеюсь, для других!)
путь он делает его путем вводить идею a co-routine, которая является функцией, которая может добровольно останавливать / приостанавливать, пока не получит то, что ей нужно. В javascript это обозначается function*
. Только function*
функции можно использовать yield
.
вот некоторые типичные javascript:
loadFromDB('query', function (err, result) {
// Do something with the result or handle the error
})
это неуклюжий, потому что теперь весь ваш код (который, очевидно, должен ждать этого loadFromDB
call) должен быть внутри этого уродливого обратного вызова. Это плохо по нескольким причинам...
- весь ваш код имеет отступ один уровень в
- у вас есть этот конец
})
который вам нужно отслеживать везде - все это лишний
function (err, result)
жаргон - не совсем ясно, что вы делаете это, чтобы присвоить значение
result
С другой стороны, с yield
, все это можно сделать в одна строка с помощью хорошей структуры совместной работы.
function* main() {
var result = yield loadFromDB('query')
}
и поэтому теперь ваша основная функция даст, где это необходимо, когда он должен ждать переменных и вещей, чтобы загрузить. Но теперь, чтобы запустить это, вам нужно вызвать нормальный (функция non-coroutine). Простая структура совместной работы может исправить эту проблему, так что все, что вам нужно сделать, это запустить это:
start(main())
и старт определен (из Ник Sotiro' answer)
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)
}
}
надеюсь, с этим знанием вы можете написать более чистый, более читаемый код, который легко удалить!
это действительно просто, вот как это работает
-
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()');
yield;
console.log('Resumed process3');
console.log('End of the process function');
}
давайте _process = process ();
пока вы не позвоните _process.next () это не выполнить первые 2 строки кода, то первый выход будет пауза функции. К резюме функции до следующего пауза точка (ключевое слово yield) вам нужно позвонить _process.next ().
вы можете думать несколько доходность это точки останова в отладчике javascript в пределах одной функции. До вы говорите, чтобы перейти к следующей точке останова, она не будет выполнять код блок. (Примечание: без блокировки всего приложения)
но в то время как yield выполняет эту паузу и возобновляет поведение, он может вернуть некоторые результаты а также {value: any, done: boolean}
согласно предыдущей функции, мы не испускаем никаких значений. Если мы исследуем предыдущий вывод, он покажет то же самое { value: undefined, done: false }
со значением undefined.
позволяет окопаться в Ключевое слово yield. При желании вы можете добавить выражение и set назначить необязательное значение по умолчанию. (Официальный синтаксис док)
[rv] = yield [expression];
выражение: значение для возврата из функции генератора
yield any;
yield {age: 12};
rv: возвращает необязательное значение, переданное следующему генератору() метод
просто вы можете передать параметры функции process () с помощью этого механизма, чтобы выполнить различные части выхода.
let val = yield 99;
_process.next(10);
now the val will be 10
обычаи
- ленивый оценке
- бесконечные последовательности
- асинхронным управлением течет
ссылки:
Он используется для итераторов-генераторов. В принципе, это позволяет вам сделать (потенциально бесконечную) последовательность, используя процедурный код. См. документация Mozilla.
чтобы дать полный ответ: 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
).
это позволяет нам к некоторым действительно фанки вещи. (посмотрите на корутина)
yield
также можно использовать для устранения ада обратного вызова с помощью структуры coroutine.
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