yieldとreturn

function* fruitGenerator() {
    yield 'apple'
    yield 'orange'
    return 'watermeron'
}

const newFruitGenerator = fruitGenerator()

// ジェネレータの実行が開始され、先頭のyieldまで実行される
// yieldに到達した時点でジェネレータの実行は停止され、戻り値appleを呼び出し元に返す
console.log(newFruitGenerator.next())

// ジェネレータの実行が再開され、2つ目のyieldまで実行される
// yieldに到達した時点でジェネレータの実行は停止され、戻り値orangeを呼び出し元に返す
console.log(newFruitGenerator.next())

// ジェネレータの実行が再開され、returnまで実行される
// returnに到達した時点でジェネレータの実行は完了し、戻り値watermeronを呼び出し元に返す
// この時、結果オブジェクトのdoneフラグがtrueになる
console.log(newFruitGenerator.next())

console.log(newFruitGenerator.next())

// 結果:
/**
{ value: 'apple', done: false }
{ value: 'orange', done: false }
{ value: 'watermeron', done: true }
{ value: undefined, done: true }
 */

ジェネレータによるイテレータ生成

function* iteratorGenerator(arr) {
    for (let i = 0; i < arr.length; i++) {
        yield arr[i]
    }
}

/* -------------------------------------------------------------------------- */

const iterator = iteratorGenerator(['apple', 'orange', 'watermelon'])
let currentItem = iterator.next()

while (!currentItem.done) {
    console.log(currentItem.value)
    currentItem = iterator.next()
}

// 結果:
/**
apple
orange
watermelon
 */

ジェネレータに値を渡す

function* twoWayGenerator() {
    const what = yield null
    console.log('Hello' + what)
}

/* -------------------------------------------------------------------------- */

const twoWay = twoWayGenerator()

twoWay.next()
twoWay.next('World')

// 結果:
/**
HelloWorld
 */

ジェネレータを使った非同期処理の制御

コールバックを利用するパターン

function asyncFlow(generatorFunction) {
    function callback(err) {
        if (err) {
            return generator.throw(err)
        }
        
        const results = [].slice.call(arguments, 1)
        generator.next(results.length > 1 ? results : results[0])
    }
    
    const generator = generatorFunction(callback)
    generator.next()
}

/* -------------------------------------------------------------------------- */

const fs = require('fs')
const path = require('path')

// 自分自身が記述されたファイルのクローンを作成する
asyncFlow(function* (callback) {
    const fileName = path.basename(__filename)
    const myself = yield fs.readFile(fileName, 'utf8', callback)
    yield fs.writeFile(`clone_of_${fileName}`, myself, callback)
    
    console.log('Clone created')
})

// 結果:
/**
Clone created
 */