Skip to content

Instantly share code, notes, and snippets.

@fabiancook
Last active October 1, 2019 04:04
Show Gist options
  • Save fabiancook/df267371eabf80faa27605e64b303340 to your computer and use it in GitHub Desktop.
Save fabiancook/df267371eabf80faa27605e64b303340 to your computer and use it in GitHub Desktop.
async function *run(fn) {
console.log("I started running");
fn();
yield 1;
fn();
yield 2;
}
// No error because it is never iterated over, meaning the code will never execute
const a = run();
const b = run(() => console.log("Function ran"));
/*
Logs:
I started running
Function ran
I received: 1
Function ran
I received: 2
*/
for await (const c of b) {
console.log("I received:", c);
}

Okay, so I think I know how to explain vgraph.

We can render a full web page in a sync cycle, but what do we do next? When do we do it? In the future!

In the DOM we know when we next need to do something typically by an event of the UI, we get an event when something is happening, or something is about to happen, like if the user interacted with the page, or the page is about to close

So what we need is to be able to know what do we do next

We could do this by holding some state details, and based on that state changing, or some heuristic, e.g. did my options change So each time I have a non rendered state, render it, which gives us a sync cycle that we know all the details about our state, ready to render The render cycle then tells the DOM in some way this is what I want my visual UI to look like

I believe this is a good way to describe:

  • Static: The web server tells the browser this is what I the browsers state should be, which includes scripts and styles, etc etc, scripts can change what actually is displayed
  • The DOM: A script given by the web server tells the browser perform a DOM change based on anything
  • React

I won’t go to far into sync cycle rendering, because that’s not what vgraph is, I just wanted a reference for the concepts

With vgraph everything has to be observed directly for it to be executed, because of the way generators work, if a value is never requested, no code is ever run, so once a consumer asks for the next value, that’s when things happen, inline to where it is consumed, you can see this happening in this screenshot

Console output of google chrome running https://gist.github.com/fabiancook/df267371eabf80faa27605e64b303340#file-vgraph-iterator-example-js

So for anything that is executed, only the bare minimum happens You can see here, the point in the implementation that allows this: https://github.com/opennetwork/vnode/blob/master/src/create-node.ts#L215

Everything can be thought of as a node with the structure:

  • reference: This tells consumers some meaning, this could be a relation to a previously defined VNode, or it could have a special meaning, or no meaning at all, if no reference was given, then create a new vnode with a unique one
  • children: Optional, this tells the consumers of each update to a list of children that the VNode has, as with reference, this might mean nothing to the consumer, or it could be consumed in some way, in either case children are never executed until they are consumed, meaning no harm to define them

All other concepts just is an extension of this vnode exposes a unique symbol for Fragment, which has a special meaning given as this should be replaced by its children, which for most consumers would be the default for any VNode that it doesn’t know how to consume vnode provides some additional metadata outside of the above two concepts, which are all documented here: https://github.com/opennetwork/vnode/blob/master/src/vnode.ts#L11 vdom is an example of a consumer, it can be given a vnode that represents the vgraph for a given DOM element, it understands how to consume a vnode with a source that is a string, if it has options then it is an Element, if it doesn’t have options it is Text, the exact rules are here: https://github.com/opennetwork/vdom/blob/master/src/native.ts#L100 if vdom is never given a VNode, it never can consume it, meaning it will never be executed by it

I decided by default that the method of consuming a VNode is only going to be async, regardless of what actually is passed, this gives a consistent format for the consumer, but it changes no rules for the producer

The producer can provide vnode with what I think covers every kind of source:

  • A known string, number, boolean, symbol
  • An Iterable, either async or sync, this includes the returned value from a generator function
  • A function, either async or sync, returning any of these sources (including another function)

Each source type is documented here: https://github.com/opennetwork/vnode/blob/master/src/source.ts#L4

An Iterable can be an Array, Map ([key, value]), Set, anything that has a key [Symbol.asyncIterator] or [Symbol.iterator] that returns an object with a next function that returns { value: <source listed above>, done: boolean }

So if you had a class with [Symbol.asyncIterator] on it, that works, or an object with [Symbol.asyncIterator]

If you give vnode undefined, its ignored, which you can see here https://github.com/opennetwork/vnode/blob/master/src/create-node.ts#L157 (it is represented as a fragment with no children, so following the rules this should be replaced by its children, if there are no children, it is ignored)

I think that’s a good wall of information, this is the best way I can describe my thoughts

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