choojs / choojs/choo

Asynchronous render

Open
#645 16 comments 3 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
6.8k
Forks
573
PR merge metrics
No merged PRs in 30d

Description

Rendering in Choo is a completely synchronous process, thought this makes things way simpler there are a few downsides from 2 perspectives:

- **CPU** - Rendering complex components might block the main loop affecting the overall experience
- **I/O** - It's not possible to make the render wait for asynchronous I/O events such as data loading

I believe the later is the most relevant when it comes to SSR. One of the biggest issues of sync SSR is related to data loading and code-splitting. There are several workaround strategies to deal with async I/O on a sync rendering process, most of them require a first-pass render to load or collect something you can wait on and signal when the data is available to read synchronously. Besides being a waste of CPU cycles it's also not very elegant and adds unnecessary complexity to the code. One could just not have SSR but being able to have truly isomorphic or universal app is a requirement for most content-driven apps.

When I think of async rendering I think of composing the view using sync or async components and then one of two things can happen:

- Wait until all the components are resolved and then apply node diffing
- Apply node diffing as components resolve

Ideally both scenarios should be allowed, giving that choice to the developer, but I believe the first one is easier to start with given the current Choo architecture. Overall it should look somehow like this:

```js
const h = require('choo/html')

const syncComponent = (state, emit) => h`

${state.label}


`

const asyncComponent = async (state, emit) => {
const data = await asyncDataFetch(state.id)
return h`

${data}


`
}

const view = (state, emit) => h`


${syncComponent(state, emit)}
${asyncComponent(state, emit)}

`
```

Given that there are a few necessary steps:
1. Make `_prerender` function on Choo await for the promise returned by the render to resolve
2. Make `bel`/`nanohtml` also accept promises
3. Make `mount` `start`, `toString` methods on Choo async since they rely on `_prerender`

There are a few open-ended questions at the moment:
1. Error handling in general
2. What should happen when a `render` event is triggered within a render call
3. Possibly others and I would like to open that discussion to the community

Contributor guide

Open the contributing guide

Research direction

Start with Choo's `_prerender` flow and the `mount`, `start`, and `toString` methods that depend on it. Then examine how `bel` and `nanohtml` currently handle rendered values, including the proposed promise inputs. Done requires resolving the async rendering approach and the open questions around errors and render events, not just making the listed methods async.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
frontend, web-dev
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.