<!DOCTYPE html>
<html>
<head>
<script data-require="rxjs@5.0.1" data-semver="5.0.1" src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.0.1/Rx.min.js"></script>
<script data-require="axios@0.15.3" data-semver="0.15.3" src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.15.3/axios.min.js"></script>
<script src="script.js"></script>
</head>
<body>
Open the console and go to script.js
</body>
</html>
console.clear();
window.onload = init;
// Vanilla version
function createOnlineEmitter() {
let cbs = []; //array of registered callbacks for the event
let unsub; //function for removing the main event listener
//this is the main event listener that gets registered with window.online/offline event
const mainListener = (isOnline) => {
//call all the subscribed callbacks
cbs.forEach(cb => cb(isOnline));
};
const registerMainListener = () => {
const boundOnline = mainListener.bind(null, true);
const boundOffline = mainListener.bind(null, false);
window.addEventListener('online', boundOnline);
window.addEventListener('offline', boundOffline);
//return unsubcribe functionality in a closure
return function unsubscribe() {
window.removeEventListener('online', boundOnline);
window.removeEventListener('offline', boundOffline);
};
};
const addCb = (cb) => {
cbs.push(cb);
//register main listener only once
//use existence of `unsub` as indicator if main event listener is added or not
if(!unsub) {
unsub = registerMainListener();
}
};
const removeCb = (cb) => {
const index = cbs.indexOf(cb);
if(index > -1) {
cbs.splice(index, 1);
}
//if no callbacks left, remove main event listener
if(cbs.length === 0 && unsub) {
unsub();
unsub = null;
}
};
return function initOnlineEmitter(cb) {
addCb(cb);
//call it async with the initial val
setTimeout(() => {
cb(navigator.onLine);
});
//return unsubscribe function to caller
return removeCb.bind(null, cb);
};
}
// RxJS version
function createOnline$() {
//merge several events into one
return Rx.Observable.merge(
//use .map() to transform the returned Event type into a true/false value
Rx.Observable.fromEvent(window, 'offline').map(() => false),
Rx.Observable.fromEvent(window, 'online').map(() => true),
//start the stream with the current online status
Rx.Observable.create(sub => {
sub.next(navigator.onLine);
sub.complete(); //this one only emits once, so now we end it
})
);
}
function init() {
// implement vanilla
const onlineEmitter = createOnlineEmitter();
let unsub = onlineEmitter(isOnline => console.log(isOnline));
//unsub();
// implement RxJS
const online$ = createOnline$();
const subscription = online$.subscribe(isOnline => console.log(isOnline));
//subscription.unsubscribe();
//compose new observable from RxJS version
//only make the network request when we're online
//the request will simply get queued up until then
function requestWhenOnline(ajaxPromiseFn) {
return online$
.filter(online => online)
//we only reach this point when we're online
.switchMap(ajaxPromiseFn) //instead of emitting true/false, emit the value of this function
.take(1) //this ensures the observable ends after we've gotten a response
.toPromise(); //convert it all to a promise
}
requestWhenOnline(() => axios.get('https://jsonplaceholder.typicode.com/posts/1'))
.then(console.log)
.catch(console.error);
}
/* Styles go here */