Skip to content

Instantly share code, notes, and snippets.

@branneman
Last active December 22, 2022 07:57
Show Gist options
  • Save branneman/e23b82dcf6974fb2fc25f72d28994f8e to your computer and use it in GitHub Desktop.
Save branneman/e23b82dcf6974fb2fc25f72d28994f8e to your computer and use it in GitHub Desktop.
Functions, Iterators, Promises, Observables - It's all connected - https://youtu.be/5GCo8AGQ9Ck
// Producer
const range = (min, max, acc = []) => {
if (max < min) throw new Error('not supported!')
if (min >= max) return acc
return range(min + 1, max, acc.concat(min))
}
// Consumer
const lt100 = range(0, 100)
//=> [1, 2, 3, 4, ..., 97, 98, 99]
// Producer
function setTimeoutPromise(ms) {
return new Promise((resolve, _reject) => {
setTimeout(resolve, ms)
})
}
// Consumer
setTimeoutPromise(1000).then(() => console.log('1s passed!'))
import axios from 'axios'
const URL = 'https://localhost/user?ID=12345'
async function itsjustapromise1() {
const response = await axios.get(URL)
console.log(response)
}
// is the same as:
function itsjustapromise2() {
return axios.get(URL).then((response) => {
console.log(response)
})
}
// Producer
function range(start, stop, step) {
return {
next: function () {
let iteration
if (start < stop) {
iteration = { value: start }
start += step
} else {
iteration = { done: true }
}
return iteration
},
}
}
// Consumer
const iterator = range(0, Infinity, 1)
expect(iterator.next().value).toBe(0)
expect(iterator.next().value).toBe(1)
expect(iterator.next().value).toBe(2)
// ...
import Tree from './Tree.js'
const versions = new Tree('1.0.0', [
new Tree('1.1.0', [new Tree('1.1.1'), new Tree('1.1.2')]),
new Tree('1.2.0', [new Tree('1.2.1')]),
new Tree('1.3.0', []),
])
for (const v of versions) {
console.log(`v${v}`)
}
export default class Tree {
constructor(item, children = []) {
this.item = item
this.children = children
}
toString() {
return this.item
}
map(fn) {
const val = fn(this.item)
if (!this.children || !this.children.length) {
return new Tree(val, [])
}
return new Tree(
val,
this.children.map((x) => {
const t = new Tree(x.item, x.children)
return t.map(fn)
})
)
}
[Symbol.iterator]() {
const list = []
this.map((value) => list.push(value))
let pointer = 0
return {
next() {
if (pointer > list.length) {
return { done: true }
}
return {
value: list[pointer++],
done: pointer > list.length,
}
},
}
}
}
import Tree from './Tree'
describe('Tree data structure', () => {
it('can be constructed and stringified', () => {
const x = new Tree('some data')
const r = x.toString()
expect(r).toEqual('some data')
})
it('adheres to Iterable and Iterator protocols', () => {
const tree = new Tree('root')
expect(tree[Symbol.iterator]).toBeInstanceOf(Function)
const iterator = tree[Symbol.iterator]()
expect(iterator.next).toBeInstanceOf(Function)
})
it('adheres to the .map() interface', () => {
const tree = new Tree('1.0.0', [
new Tree('1.1.0', [new Tree('1.1.1'), new Tree('1.1.2')]),
new Tree('1.2.0', [new Tree('1.2.1')]),
new Tree('1.3.0', []),
])
const identity = (id) => id
const array = tree.map(identity)
expect(array).toEqual({
item: '1.0.0',
children: [
{
item: '1.1.0',
children: [
{ item: '1.1.1', children: [] },
{ item: '1.1.2', children: [] },
],
},
{ item: '1.2.0', children: [{ item: '1.2.1', children: [] }] },
{ item: '1.3.0', children: [] },
],
})
})
it('can be flattened to Array', () => {
const tree = new Tree('1.0.0', [
new Tree('1.1.0', [new Tree('1.1.1'), new Tree('1.1.2')]),
new Tree('1.2.0', [new Tree('1.2.1')]),
new Tree('1.3.0', []),
])
const array = [...tree]
expect(array).toEqual([
'1.0.0',
'1.1.0',
'1.1.1',
'1.1.2',
'1.2.0',
'1.2.1',
'1.3.0',
])
})
it('can be used in for...of', () => {
const tree = new Tree('1.0.0', [
new Tree('1.1.0', [new Tree('1.1.1'), new Tree('1.1.2')]),
new Tree('1.2.0', [new Tree('1.2.1')]),
new Tree('1.3.0', []),
])
const array = []
for (const item of tree) array.push(item)
expect(array).toEqual([
'1.0.0',
'1.1.0',
'1.1.1',
'1.1.2',
'1.2.0',
'1.2.1',
'1.3.0',
])
})
})
import { Observable } from 'rxjs';
// Implementation
const observable = new Observable((subscriber) => {
subscriber.next(1)
subscriber.next(2)
subscriber.next(3)
setTimeout(() => {
subscriber.next(4)
subscriber.complete()
}, 1000)
})
// Consumer / Call-site
observable.subscribe({
next(x) {
console.log('received:', x)
},
error(err) { ... },
complete() { ... },
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment