Skip to content

Instantly share code, notes, and snippets.

@eisisig
Forked from bevacqua/NonBlockingRenderLoop.js
Created December 13, 2016 15:21
Show Gist options
  • Save eisisig/f944673db2405099806ba8ef995e91a3 to your computer and use it in GitHub Desktop.
Save eisisig/f944673db2405099806ba8ef995e91a3 to your computer and use it in GitHub Desktop.
Defer secondary portions of the DOM using `requestAnimationFrame`
import { Component, PropTypes } from 'react'
import { noop } from 'lodash'
import raf from 'raf'
const cache = new Map()
export function createNonBlockingRenderLoop({ key, concurrencyLevel = 1 }) {
if (cache.has(key)) {
return cache.get(key)
}
let slots = 0
const isBusy = () => slots >= concurrencyLevel
const takeSlot = () => slots++
const releaseSlot = () => slots--
class NonBlockingRenderLoop extends Component {
state = {
wait: true
}
componentDidMount() {
this.enqueue()
}
componentWillUnmount() {
this.stop()
}
render() {
return this.state.wait ? null : this.props.children
}
enqueue() {
if (isBusy()) {
this.defer(() => this.enqueue())
} else {
takeSlot()
this.defer(() => this.dequeue())
}
}
dequeue() {
this.setState({ wait: false })
releaseSlot()
}
defer(fn) {
raf(() => {
if (this.defer !== noop) {
fn()
}
})
}
stop() {
this.defer = noop
if (this.state.wait) {
releaseSlot()
}
}
}
NonBlockingRenderLoop.propTypes = {
children: PropTypes.element.isRequired
}
cache.set(key, NonBlockingRenderLoop)
return NonBlockingRenderLoop
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment