Last active
September 8, 2017 09:32
-
-
Save bodia-uz/d9a3be296819875fb6958c4ef9d03667 to your computer and use it in GitHub Desktop.
js http polling
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Backoff from 'backo2'; | |
import { isFunction } from 'lodash'; | |
import makeCancelable from './makeCancelable'; | |
function createPolling(fn, pollInterval, { shouldKeepPolling } = {}) { | |
let intervalId; | |
let keepPolling = false; | |
let fnPromise; | |
// use backoff when connection lost | |
const backoff = new Backoff({ | |
min: pollInterval, | |
jitter: 0.5 | |
}); | |
function fnWithInterval(fnArguments) { | |
if (keepPolling && isFunction(shouldKeepPolling)) { | |
keepPolling = shouldKeepPolling(...fnArguments); | |
} | |
if (!keepPolling) { | |
return; | |
} | |
let fnResult = fn(...fnArguments); | |
// if type of fn result is not promise, wrap it in promise | |
if (!fnResult || (fnResult && !isFunction(fnResult.then))) { | |
fnResult = Promise.resolve(fnResult); | |
} | |
fnPromise = makeCancelable(fnResult); | |
fnPromise.promise | |
.then(() => { | |
// reset backoff if connection successful | |
backoff.reset(); | |
intervalId = setTimeout(fnWithInterval, pollInterval, fnArguments); | |
}) | |
.catch(error => { | |
if (error && error.isCanceled) { | |
// promise is canceled, stop fn polling | |
return; | |
} | |
// use incremental (backoff) polling interval if connection lost | |
intervalId = setTimeout( | |
fnWithInterval, | |
backoff.duration(), | |
fnArguments | |
); | |
}); | |
} | |
function start(...fnArguments) { | |
stop(); | |
keepPolling = true; | |
fnWithInterval(fnArguments); | |
} | |
function stop() { | |
keepPolling = false; | |
if (intervalId) { | |
clearTimeout(intervalId); | |
intervalId = null; | |
} | |
if (fnPromise) { | |
fnPromise.cancel(); | |
fnPromise = null; | |
} | |
} | |
return { | |
start: start, | |
restart: start, | |
stop: stop, | |
isStarted() { | |
return keepPolling; | |
}, | |
setInterval(interval) { | |
pollInterval = interval; | |
backoff.setMin(interval); | |
} | |
}; | |
} | |
export default createPolling; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import isEqual from 'lodash/isEqual'; | |
import ItemsList from './ItemsList'; | |
import createPolling from './createPolling'; | |
class Items extends Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
query: '', | |
items: [] | |
}; | |
} | |
fetchItems(query) { | |
return fetch('/data.json') | |
.then(response => response.json()) | |
.then(items => { | |
const visibleItems = ( | |
query ? | |
items.filter(item => item.name.indexOf(query) !== -1) : | |
items | |
); | |
console.log(items.length, visibleItems.length); | |
this.setState({items: visibleItems}) | |
}) | |
} | |
componentDidMount() { | |
this.polling = createPolling(this.fetchItems.bind(this), 1000); | |
this.polling.start(this.state.query); | |
} | |
shouldComponentUpdate(nextProps, nextState) { | |
return ( | |
!isEqual(this.props, nextProps) || | |
!isEqual(this.state, nextState) | |
); | |
} | |
componentWillUnmount() { | |
this.polling.stop(); | |
} | |
render() { | |
return ( | |
<div> | |
<input type="text" value={this.state.query} onChange={e => { | |
this.setState({query: e.target.value}); | |
this.polling.restart(e.target.value); | |
}}/> | |
<ItemsList items={this.state.items}/> | |
</div> | |
); | |
} | |
} | |
export default Items; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment