Skip to content

Instantly share code, notes, and snippets.

@dmitry-vsl
Last active September 1, 2021 13:23
Show Gist options
  • Save dmitry-vsl/85a44ac66d4a266abd5295a6c540f592 to your computer and use it in GitHub Desktop.
Save dmitry-vsl/85a44ac66d4a266abd5295a6c540f592 to your computer and use it in GitHub Desktop.
<script type='module'>
async function* fromEvent(el, event){
let resolve
el.addEventListener(event, e => resolve(e))
while(true){
let promise = new Promise(_resolve => resolve = _resolve)
yield await promise
}
}
async function* startWith(asyncIterator, initialValue){
yield initialValue
yield * asyncIterator
}
async function* reduce(asyncIterator, fn, initial){
let current = initial
for await(let val of asyncIterator){
current = fn(current, val)
yield current
}
}
function timeout(wait){
let timeoutid
const promise = new Promise(resolve => {
timeoutid = setTimeout(resolve, wait)
})
function cancel(){
clearTimeout(timeoutid)
}
return [promise, cancel]
}
async function* debounce(asyncIterator, wait = 0){
let value, next, cancel, timeoutPromise
let result = await asyncIterator.next()
while(true) {
if(result != null && result.done != null){
if(!result.done){
let value = result.value
next = asyncIterator.next()
if(cancel){
cancel()
}
[timeoutPromise, cancel] = timeout(wait)
} else {
break
}
} else {
yield value
timeoutPromise = new Promise(resolve => {})
let cancel = () => {}
}
result = await Promise.race([
next,
timeoutPromise,
])
}
}
async function main(){
const clicks = fromEvent(document.getElementById('test'), 'click')
const debouncedClicks = debounce(clicks, 1000)
const clickCount = startWith(
reduce(debouncedClicks, (count, _) => count + 1, 0),
0,
)
for await(let count of clickCount){
document.getElementById('count').innerText = count
}
}
window.addEventListener('load', main)
</script>
<body>
<button id='test'>Click me</button>
<span id='count'><span>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment