Предварительные требования: было бы полезно знакомство с библиотеками FRP, такими как RxJS.

Обычно у наблюдателя есть три метода - следующий, ошибка, завершено. Простой наблюдатель может выглядеть так -

const observer = {
  next(value) { console.log(`next -> ${value}`) },
  error(err) { console.log('error') },
  complete() { console.log('completed') }
}

Наблюдаемое могло бы выглядеть примерно так -

function observable(observer) {
  for(var i = 0; i <= 10; i++) {
    observer.next(i)
  }
  observer.error()
  observer.complete()
}

Этот наблюдаемый испускает последовательность чисел от 0 до 10, затем выдает ошибку и, наконец, выдает полное. Это нереальная реализация. В реальном мире у нас есть концепция SafeObservers, в которой наблюдаемое перестает наблюдаться в момент выдачи либо ошибки, либо завершения. Но цель этой статьи не в том, чтобы углубиться в реальных наблюдателей и наблюдаемых, а в том, чтобы показать вам, как генератор ES6 можно использовать в качестве наблюдателя.

Недостаточно наличия наблюдаемого и наблюдателя - наблюдатель должен наблюдать наблюдаемое. Это так просто, как -

observable(observer)

В результате -

"next -> 0" 
"next -> 1" 
"next -> 2" 
"next -> 3" 
"next -> 4" 
"next -> 5" 
"next -> 6" 
"next -> 7" 
"next -> 8" 
"next -> 9" 
"next -> 10" 
"error" 
"completed"

Как я уже упоминал выше, у наблюдателя есть три метода - next, error и close. Если вы посмотрите на итератор ES6 (который обычно создается путем вызова генератора), он также имеет три метода - next, throw и return. Итак, вы можете создать генератор, который возвращает итератор, подобный этому -

function* observerGenerator() {
  try {
    while(true) {
      let value = yield
      console.log(`next -> ${value}`)
    }   
  } catch (err) {
    console.log('error')
  }
  
  console.log('completed')
}

Затем мы создаем служебную функцию, которая преобразует наш итератор в наблюдателя -

function createObserver(iterator) {
  return {
    next(value) { iterator.next(value) },
    error(err) { iterator.throw(err) },
    complete() { iterator.return() }
  }
}

Обратите внимание на соответствие между методами наблюдателя и методами итератора -

|    Observer    |    Iterator    |
-----------------------------------
|    next        |    next        |
|    error       |    throw       |
|    complete    |    return      |

Чтобы начать наблюдать наблюдаемое -

observable(createObserver(observerGenerator()))

И результат такой же, как и раньше. Фрагменты кода доступны в виде здесь.