Skip to content

Instantly share code, notes, and snippets.

@itacirgabral
Last active February 27, 2022 21:52
Show Gist options
  • Save itacirgabral/211f24629e9bb3d1a724def568bfb5ed to your computer and use it in GitHub Desktop.
Save itacirgabral/211f24629e9bb3d1a724def568bfb5ed to your computer and use it in GitHub Desktop.
typescript async generator operator
import Yallist from 'yallist'
import { setTimeout } from 'timers/promises'
type Bread = {
[key: string]: string;
}
const mkStepwand = ({ delay = 1000, delta = 200, breads = [] }: { delay?: number; delta?: number; breads?: Array<Bread> }) => {
const indians = new Yallist<{ goodFor: number; bread: Bread}>()
let dontStop = true
for (const bread of breads) {
indians.push({
bread,
goodFor: delay + Math.trunc(delta * (Math.random() - 0.5))
})
}
const steps = () => indians.toArray().map(el => el.bread)
const dates = () => indians.toArray().map(el => el.goodFor)
let blockerResolve: (value: unknown) => void
let blockerReject: (value: unknown) => void
let blocker = new Promise((resolve, reject) => {
blockerResolve = resolve
blockerReject = reject
})
const close = () => {
dontStop = false
blockerReject(null)
}
const pub = (bread: Bread) => {
indians.push({
bread,
goodFor: delay + Math.trunc(delta * (Math.random() - 0.5))
})
if (indians.length === 1) {
blockerResolve(null)
}
}
const pubOver = (bread: Bread) => {
indians.unshift({
bread,
goodFor: delay + Math.trunc(delta * (Math.random() - 0.5))
})
if (indians.length === 1) {
blockerResolve(null)
}
}
const gen = async function * gen () {
while (dontStop) {
if (indians.head) {
const sleepms = indians.head?.value.goodFor ?? 0
await setTimeout(sleepms > delta ? sleepms : delta)
const bread = indians.shift()?.bread
if (bread && dontStop) {
yield bread
} else {
dontStop = false
console.log(`dontStop=${dontStop}`)
}
} else {
await blocker
blocker = new Promise((resolve, reject) => {
blockerResolve = resolve
blockerReject = reject
})
}
}
}
return {
pub,
pubOver,
gen,
steps,
dates,
close
}
}
export default mkStepwand
@itacirgabral
Copy link
Author

itacirgabral commented Feb 27, 2022

import { mkStepwand } from './';

const stepwandSlow = mkStepwand({ breads: [{ el: 'a' }, { el: 'e' }, { el: 'i' }, { el: 'o' }, { el: 'u' }] });
const stepwandFast = mkStepwand({ delay: 100, delta: 20, breads: [{ el: 'a' }, { el: 'e' }, { el: 'i' }, { el: 'o' }, { el: 'u' }] });

const stepwand = stepwandFast

// inicia o processamento do gerador iniciado com 5 elementos
;(async () => {
  for await (const bread of stepwand.gen()) {
    console.dir(bread)
  }
})();

// gera mais 20 elementos, 1 a cada quase 600 milissegundos
let n = 0;
const intervalId = setInterval(async () => {
  if (n++ < 20) {
    const bread = { rdm: String(Math.random()), n };
    stepwand.pub(bread);
  } else {
    console.log('clearInterval')
    clearInterval(intervalId);
  }
}, 543);

setTimeout(() => {
  stepwand.close()
  console.log('stepwand.close()')
}, 15_000)

setTimeout(() => {
  console.log('10s')
}, 10_000)

setTimeout(() => {
  console.log('5s')
}, 5_000)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment