use rIC in pseudo virtual list

This commit is contained in:
Nolan Lawson 2018-01-30 21:17:01 -08:00
parent 03b055ab20
commit d1620c3bca
6 changed files with 73 additions and 7 deletions

5
package-lock.json generated
View file

@ -7244,6 +7244,11 @@
"setimmediate": "1.0.5"
}
},
"tiny-queue": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/tiny-queue/-/tiny-queue-0.2.1.tgz",
"integrity": "sha1-JaZ/LG4lOyypQZd7XvdELvl6YEY="
},
"tmp": {
"version": "0.0.31",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz",

View file

@ -53,6 +53,7 @@
"svelte-loader": "^2.3.3",
"svelte-transitions": "^1.1.1",
"svgo": "^1.0.3",
"tiny-queue": "^0.2.1",
"uglifyjs-webpack-plugin": "^1.1.5",
"url-search-params": "^0.10.0",
"webpack": "^3.10.0",

View file

@ -7,7 +7,8 @@
makeProps="{{makeProps}}"
key="{{wrappedItem.item}}"
intersectionObserver="{{intersectionObserver}}"
hide="{{shouldHide(wrappedItem.item, $intersectionStates)}}"
isIntersecting="{{isIntersecting(wrappedItem.item, $intersectionStates)}}"
isCached="{{isCached(wrappedItem.item, $intersectionStates)}}"
height="{{getHeight(wrappedItem.item, $intersectionStates)}}"
/>
{{/each}}
@ -35,7 +36,7 @@
let intersectionStates = this.store.get('intersectionStates')
let keys = Object.keys(intersectionStates)
for (let key of keys) {
intersectionStates[key].isIntersecting = false
intersectionStates[key].isCached = true
}
this.store.setForRealm({intersectionStates: intersectionStates})
@ -60,8 +61,11 @@
}
},
helpers: {
shouldHide(key, $intersectionStates) {
return !!($intersectionStates[key] && !$intersectionStates[key].isIntersecting)
isIntersecting(key, $intersectionStates) {
return !!($intersectionStates[key] && $intersectionStates[key].isIntersecting)
},
isCached(key, $intersectionStates) {
return !!($intersectionStates[key] && $intersectionStates[key].isCached)
},
getHeight(key, $intersectionStates) {
return $intersectionStates[key] && $intersectionStates[key].rect.height

View file

@ -1,9 +1,9 @@
<div class="pseudo-virtual-list-item"
aria-hidden="{{hide}}"
pseudo-virtual-list-key="{{key}}"
style="height: {{hide ? `${height}px` : ''}};"
style="height: {{shouldHide ? `${height}px` : ''}};"
ref:node>
{{#if !hide}}
{{#if !shouldHide}}
<:Component {component}
virtualProps="{{props}}"
virtualIndex="{{index}}"
@ -13,10 +13,38 @@
</div>
<script>
import { scheduleIdleTask } from '../../_utils/scheduleIdleTask'
import { mark, stop } from '../../_utils/marks'
export default {
oncreate() {
this.observe('isIntersecting', isIntersecting => {
if (isIntersecting) {
mark('render')
this.set({hide: false})
stop('render')
} else {
// unrender lazily; it's not a critical UI task
scheduleIdleTask(() => {
mark('unrender')
if (!this.get('isIntersecting')) {
this.set({hide: true})
}
stop('unrender')
})
}
})
let intersectionObserver = this.get('intersectionObserver')
intersectionObserver.observe(this.refs.node)
},
computed: {
shouldHide: (isIntersecting, isCached, hide) => {
if (isCached) {
return true // if it's cached, always unrender immediately until proven it's intersecting
}
return !isIntersecting && hide
}
}
}
</script>

View file

@ -5,7 +5,8 @@
:index
:scrollToThisItem
:intersectionObserver
:hide
:isIntersecting
:isCached
:height
on:scrollToPosition
/>

View file

@ -0,0 +1,27 @@
// Wrapper to call requestIdleCallback() to schedule low-priority work.
// See https://developer.mozilla.org/en-US/docs/Web/API/Background_Tasks_API
// for a good breakdown of the concepts behind this.
import Queue from 'tiny-queue'
const taskQueue = new Queue()
let runningRequestIdleCallback = false
function runTasks(deadline) {
while (taskQueue.length && deadline.timeRemaining() > 0) {
taskQueue.shift()()
}
if (taskQueue.length) {
requestIdleCallback(runTasks)
} else {
runningRequestIdleCallback = false
}
}
export function scheduleIdleTask(task) {
taskQueue.push(task)
if (!runningRequestIdleCallback) {
runningRequestIdleCallback = true
requestIdleCallback(runTasks)
}
}