Что такое ключевое слово yield в JavaScript?
Я слышал о ключевом слове "yield" в JavaScript, но я нашел очень плохую документацию об этом. Может кто-нибудь объяснить мне (или порекомендовать сайт, который объясняет) его использование и для чего он используется?
8 ответов:
The документация MDN довольно хорошо, ИМО.
функция, содержащая ключевое слово yield, является генератором. Когда вы вызываете его, его формальные параметры привязаны к фактическим аргументам, но его тело фактически не оценивается. Вместо этого возвращается генератор-итератор. Каждый вызов метода Next () генератора-итератора выполняет еще один проход через итерационный алгоритм. Значение каждого шага-это значение, заданное ключевым словом yield. Думайте о доходности как генератор-итератор версии return, указывающий границу между каждой итерацией алгоритма. Каждый раз, когда вы вызываете next (), код генератора возобновляется из оператора, следующего за yield.
поздний ответ, наверное, все знают о
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') }
и поэтому теперь ваша основная функция будет давать там, где это необходимо, когда он должен ждать переменных и вещей, чтобы загрузить. Но теперь, чтобы запустить это, вам нужно вызвать a нормальный (функция non-coroutine). Простая структура совместной работы может решить эту проблему, так что все, что вам нужно сделать, это запустить это:
start(main())
и старт определен (из ответа Ника Сотиро)
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 ();
пока ты не позвонишь _процесс.далее () это не выполнить первые 2 строки кода, то первый выход будет пауза функции. К резюме функции до следующего пауза точка (ключевое слово yield) вам нужно позвонить _процесс.далее ().
вы можете думать несколько доходность это точки останова в отладчике 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
также может быть использован для устранения обратного вызова hell,с сопрограммой.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