Do a better job of managing http requests

This commit is contained in:
Jordan Eldredge 2018-07-25 23:18:19 -07:00
parent a63bfe5915
commit c94ca721b5
2 changed files with 85 additions and 6 deletions

View file

@ -1,6 +1,7 @@
import React from "react";
import skins from "./skins.json";
import "./App.css";
import LoadQueue from "./LoadQueue";
const hashes = Object.keys(skins);
@ -12,14 +13,37 @@ const SKIN_RATIO = SKIN_HEIGHT / SKIN_WIDTH;
class Skin extends React.Component {
constructor(props) {
super(props);
this.state = { loaded: false };
this.state = { loaded: false, load: false };
this._controller = new window.AbortController();
this._handleLoad = this._handleLoad.bind(this);
}
componentDidMount() {
this._dequeue = this.props.queue.enqueue(() => {
const signal = this._controller.signal;
return fetch(this.props.src, { signal })
.then(() => {
this.setState({ load: true });
})
.catch(e => {
console.log("aborted?", e);
});
}, 0);
}
_handleLoad() {
this.setState({ loaded: true });
}
componentWillUnmount() {
if (!this.state.loaded) {
this._controller.abort();
}
if (this._dequeue != null) {
this._dequeue();
}
}
render() {
return (
<div
@ -36,11 +60,13 @@ class Skin extends React.Component {
}}
>
<a href={this.props.href} target="_blank">
<img
src={this.props.src}
className={`screenshot ${this.state.loaded ? "loaded" : ""}`}
onLoad={this._handleLoad}
/>
{this.state.load && (
<img
src={this.props.src}
className={`screenshot ${this.state.loaded ? "loaded" : ""}`}
onLoad={this._handleLoad}
/>
)}
</a>
</div>
);
@ -75,6 +101,7 @@ class App extends React.Component {
scrollDirection: null
};
this._handleScroll();
this._queue = new LoadQueue(10);
this._handleScroll = this._handleScroll.bind(this);
this._handleResize = this._handleResize.bind(this);
}
@ -135,6 +162,7 @@ class App extends React.Component {
const left = column * columnWidth;
skinElements.push(
<Skin
queue={this._queue}
href={`https://webamp.org/?skinUrl=https://s3.amazonaws.com/webamp-uploaded-skins/skins/${hash}.wsz`}
src={`https://s3.amazonaws.com/webamp-uploaded-skins/screenshots/${hash}.png`}
key={hash}

51
src/LoadQueue.js Normal file
View file

@ -0,0 +1,51 @@
export default class LoadQueue {
constructor(size) {
this._free = size;
this._queue = new Array();
}
_remove(priority, cb) {
const priorityQueue = this._queue[priority];
if (priorityQueue == null) {
return;
}
priorityQueue.delete(cb);
if (priorityQueue.size === 0) {
this._queue[priority] = undefined;
}
}
enqueue(cb, priority) {
if (this._queue[priority] == null) {
this._queue[priority] = new Set();
}
this._queue[priority].add(cb);
this._run();
return () => {
this._remove(priority, cb);
};
}
_run() {
if (this._free === 0) {
return;
}
const priority = this._queue.findIndex(value => Boolean(value));
if (priority === -1) {
// The queue is empty
return;
}
this._free--;
const set = this._queue[priority];
const values = set.values();
const cb = values.next().value;
cb().finally(() => {
this._free++;
this._run();
});
this._remove(priority, cb);
}
}