I have two .js-files:
main.js
require("./randomEvent.js").start("hey");
require("./randomEvent.js").start("hi");
require("./randomEvent.js").start("hello");
randomEvent.js
var repeat = true;
exports.start = (randomString) => {
while (repeat) {
console.log(randomString);
}
}
exports.stop = (randomString) => {
repeat = false;
}
I want to start randomEvent.js 3 times, each with different randomStrings.
And if I do
require("./randomEvent.js").stop("hi");
it should stop the start("hi") function / it should set repeat to false.
How?
Thanks in advance!
You can implement your randomEvents.js as a class. So every instance has its own repeat flag.
function RandomEvent(str) {
this.repeat = true;
this.randomString = str;
this.start = () => {
setInterval(() => {
if (this.repeat) {
console.log('-->', this.randomString);
}
}, 1000);
}
this.stop = () => {
this.repeat = false;
}
}
module.exports = RandomEvent;
and main.js
let RandomEvent = require('./randomEvent');
let sayHi = new RandomEvent('hi');
let sayHello = new RandomEvent('hello');
let sayHey = new RandomEvent('hey');
sayHi.start();
sayHello.start();
sayHey.start();
setTimeout(() => {
console.log('stop saying hi')
sayHi.stop();
}, 5000);
Or you can store for every string, its own flag:
randomEvents.js
var repeat = {};
exports.start = (randomString) => {
repeat[randomString] = true;
setInterval(() => {
if (repeat[randomString]) {
console.log('-->', randomString);
}
}, 1000);
}
exports.stop = (randomString) => {
repeat[randomString] = false;
}
and in main.js
require("./randomEvent.js").start("hey");
require("./randomEvent.js").start("hi");
require("./randomEvent.js").start("hello");
setTimeout(() => {
console.log('stop saying hi')
require("./randomEvent.js").stop("hi");
}, 5000);
randomEvent.js
var repeatFlags = {};
function repeatLog(str) {
if (repeatFlags[str]) {
console.log(str);
setTimeout(() => {
repeatLog(str);
});
}
}
exports.start = (randomString) => {
repeatFlags[randomString] = true;
repeatLog(randomString);
}
exports.stop = (randomString) => {
repeatFlags[randomString] = false;
}
Related
Hi im working on a Chrome extension that adds badges to users, now the problem is i have to refresh the page everytime so the badges can load because there are client-side changes . How can i watch events change so i run the function on first time page load ?
I read something about input event listener or MutationObserver but im not sure how can i implement that , Any help would be much appreciated .
CODE:
function Foreground() {
let users = null;
let queries = [];
let userIds = [];
document.addEventListener("DOMContentLoaded", function(event) {});
window.addEventListener('load', () => {
fetchUsersAndQueries();
chrome.runtime.onMessage.addListener(async(message, sender, res) => {
if (message.users) {
fetchUsersAndQueries();
if (users) {
return res(users);
} else {
return res([]);
}
}
if (message.refresh) {
try {
assignBadges();
} catch (error) {
console.log(error.message);
}
}
return true;
});
let done = false;
setInterval(() => {
if (done) {
return;
}
if (users) {
done = true;
try {
assignBadges();
} catch (error) {
console.log(error.message);
}
}
}, 500);
});
async function fetchUsersAndQueries() {
userIds = await getAPIUserIds();
let isStop = false;
setInterval(() => {
if (isStop) {
return;
}
const parasiteContainer = document.querySelector('#parasite-container');
if (parasiteContainer) {
if (parasiteContainer.shadowRoot) {
try {
const roster1 = parasiteContainer.shadowRoot.querySelector(`[name="roster1"]`);
const roster2 = parasiteContainer.shadowRoot.querySelector(`[name="roster2"]`);
if (!roster1) {
return
};
if ([...roster1.children].length === 1) {
if (roster1.firstElementChild.children.length === 1) {
if (roster1.firstElementChild.firstElementChild.length === 1) {
const fTeam = [...roster1.firstElementChild.firstElementChild.firstElementChild.children].map(item => getUsername(item));
const sTeam = [...roster2.firstElementChild.firstElementChild.firstElementChild.children].map(item => getUsername(item));
users = fTeam.concat(sTeam).flat();
queries.push([...roster1.firstElementChild.firstElementChild.firstElementChild.children]);
queries.push([...roster2.firstElementChild.firstElementChild.firstElementChild.children]);
isStop = true;
} else {
const fTeam = [...roster1.firstElementChild.firstElementChild.children].map(item => getUsername(item));
const sTeam = [...roster2.firstElementChild.firstElementChild.children].map(item => getUsername(item));
users = fTeam.concat(sTeam).flat();
queries.push([...roster1.firstElementChild.firstElementChild.children]);
queries.push([...roster2.firstElementChild.firstElementChild.children]);
isStop = true;
}
} else {
const fTeam = [...roster1.firstElementChild.children].map(item => getUsername(item));
const sTeam = [...roster2.firstElementChild.children].map(item => getUsername(item));
users = fTeam.concat(sTeam).flat();
queries.push([...roster1.firstElementChild.children]);
queries.push([...roster2.firstElementChild.children]);
isStop = true;
}
}
queries.forEach(query => {
query.map(item => {
if (item.children.length > 1) {
[...item.children].map(child => {
// const container = child.querySelector('.sc-hCQDas'); // Classname might change in the future.
const container = child.firstElementChild ? .firstElementChild ? .firstElementChild ? .firstElementChild ? .children[2];
if (container) {
container.insertAdjacentHTML(
'beforeend',
createBadge(badgesResponse.data.exists, child.dataset.userId)
);
}
});
} else {
// const container = item.querySelector('.sc-hCQDas'); // Classname might change in the future.
const container = item.firstElementChild ? .firstElementChild ? .firstElementChild ? .children[0];
if (container) {
container.insertAdjacentHTML(
'beforeend',
createBadge(badgesResponse.data.exists, item.dataset.userId)
);
}
}
});
});
}
I have a custom Promise2 class that extends Promise class to allow early settling. It uses my custom Timer class to check the progress of a simulated activity through another timer t1. In my example, p1 does an early settling but the problem is with the p1.then( doesn't recognize the onfulfilled callback as a function.
I suspected I have to override then() and call the super.then() but it didn't work. By the way, the timed executor callback inside super() is just a workaround to make this accessible. Any ideas on what's lacking in my Promise2 class?
JavaScript Code
'use strict';
const p1 = new Promise2(
(resolve, reject) => {
const t1 = Timer.create(
() => {
resolve('Promise resolved.');
// reject(new Error('Promise rejected.'));
},
3000,
);
return { timer: t1 };
},
);
Timer.create(
() => {
const { isCompleted } = p1.return.timer;
const { progress } = p1.return.timer;
if (isCompleted === false) {
console.log(`Promise: ${progress} %`);
if (progress > 50) {
p1.resolve('Early resolve.');
// p1.reject(new Error('Early reject.'));
p1.return.timer.stop();
}
}
},
250,
true,
16,
);
// p1.promise.then(
p1.then(
(value) => {
console.log('__resolve__');
console.log(value);
},
)
.catch(
(reason) => {
console.log('__catch__');
console.log(reason);
},
);
Promise2 Class
class Promise2 extends Promise {
constructor(executor = null) {
super(
(resolve, reject) => {
Timer.create(
() => {
this.resolve = resolve;
this.reject = reject;
this.return = executor(resolve, reject);
},
1);
},
);
// this.promise = new Promise(
// (resolve, reject) => {
// this.resolve = resolve;
// this.reject = reject;
// this.return = executor(resolve, reject);
// },
// );
}
static create(executor = null) {
return new Promise2(...arguments);
}
}
Timer Class
class Timer {
constructor(workload = null, milliseconds = 1000, isAutostart = true, repeat = 1, isInterval = false) {
this.workload = workload;
this.milliseconds = milliseconds;
this.isAutostart = isAutostart;
this.repeat = repeat;
this.isInterval = isInterval;
this.startTime = 0;
this.endTime = 0;
this.timeLeft = milliseconds;
this.timeoutId = 0;
this.progress = 0;
this.isCompleted = false;
this.endTimeActual = 0;
this.repeatLeft = repeat;
this.isPaused = false;
this.subTimers = [];
if (isAutostart === true) {
this.start();
}
}
start(thisArg = this) {
thisArg.startTime = Date.now();
thisArg.endTime = thisArg.startTime + thisArg.milliseconds;
const timeoutEndTime = Date.now();
thisArg.watch(thisArg.workload, timeoutEndTime, thisArg);
}
watch(workload = null, timeoutEndTime = 0, thisArg = this) {
if (thisArg.isPaused === true) {
return;
}
const timeoutLag = Date.now() - timeoutEndTime;
thisArg.timeLeft = thisArg.endTime - Date.now() - timeoutLag;
if (thisArg.timeLeft > 0) {
thisArg.progress = 100 - ((thisArg.timeLeft / thisArg.milliseconds) * 100);
const inProgress = 100 - thisArg.progress;
const tick = thisArg.timeLeft / inProgress;
timeoutEndTime = Date.now() + tick;
thisArg.timeoutId = setTimeout(thisArg.watch, tick, thisArg.workload, timeoutEndTime, thisArg);
return;
}
thisArg.stop(thisArg);
workload();
if (thisArg.repeatLeft > 0) {
thisArg.isCompleted = false;
thisArg.start();
}
if (thisArg.isInterval === true) {
thisArg.repeatLeft = 1;
}
if (thisArg.subTimers.length > 0) {
thisArg.subTimers.forEach(
(timer) => {
if (timer.isAutostart === true) {
timer.start();
}
},
);
}
}
stop(thisArg = this) {
clearTimeout(thisArg.timeoutId);
thisArg.isCompleted = true;
thisArg.endTimeActual = Date.now();
thisArg.repeatLeft -= 1;
if (thisArg.isInterval === true) {
thisArg.repeatLeft = 0;
}
}
restart(thisArg = this) {
thisArg.stop();
thisArg.startTime = 0;
thisArg.endTime = 0;
thisArg.timeLeft = thisArg.milliseconds;
thisArg.timeoutId = 0;
thisArg.progress = 0;
thisArg.isCompleted = false;
thisArg.endTimeActual = 0;
thisArg.repeatLeft = thisArg.repeat;
thisArg.start();
}
pause(thisArg = this) {
thisArg.isPaused = true;
}
resume(thisArg = this) {
thisArg.isPaused = false;
const timeoutEndTime = Date.now();
thisArg.watch(thisArg.workload, timeoutEndTime, thisArg);
}
static create(workload = null, milliseconds = 1000, isAutostart = true, repeat = 1, isInterval = false) {
return new Timer(...arguments);
}
static chain(timers = []) {
const timerReferences = Timer.chainWalk(timers);
if (timerReferences[0].isAutostart === true) {
timerReferences[0].start();
}
return timerReferences;
}
static chainWalk(timers = [], timerReferences = [], nextTimer = null) {
if (timers.length === 0) {
return timerReferences;
}
if (timerReferences.length === 0) {
timers = [...timers];
}
const timer = timers.shift();
const {
workload = null,
milliseconds = 1000,
isAutostart = true,
repeat = 1,
isInterval = false,
} = timer;
const newTimer = new Timer(workload, milliseconds, false, repeat, isInterval);
newTimer.isAutostart = isAutostart;
if (timerReferences.length === 0) {
timerReferences.push(newTimer);
[nextTimer] = timerReferences;
} else {
nextTimer.subTimers.push(newTimer);
[nextTimer] = nextTimer.subTimers;
}
timerReferences = Timer.chainWalk(timers, timerReferences, nextTimer);
return timerReferences;
}
static tree(timers = []) {
const timerReferences = Timer.treeWalk(timers);
timerReferences.forEach(
(reference) => {
if (reference.isAutostart === true) {
reference.start();
}
},
);
return timerReferences;
}
static treeWalk(timers = []) {
const timerReferences = [];
timers.forEach(
(timer) => {
const {
workload = null,
milliseconds = 1000,
isAutostart = true,
repeat = 1,
isInterval = false,
subTimers = [],
} = timer;
const newTimer = new Timer(workload, milliseconds, false, repeat, isInterval);
newTimer.isAutostart = isAutostart;
if (Array.isArray(subTimers) === true) {
newTimer.subTimers = Timer.treeWalk(subTimers);
}
timerReferences.push(newTimer);
},
);
return timerReferences;
}
}
Console Output
Promise2 Class (Working Alternative)
class Promise2 {
constructor(executor = null) {
this.promise = new Promise(
(resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
this.return = executor(resolve, reject);
},
);
this.then = function (onfulfilled = null, onrejected = null) {
return this.promise.then(...arguments);
};
this.catch = function (onrejected = null) {
return this.promise.catch(...arguments);
};
this.finally = function (onfinally = null) {
return this.promise.finally(...arguments);
};
}
static create(executor = null) {
return new Promise2(...arguments);
}
}
I've built the following function, which changes the content of a span on mouseover. Everything works fine. The only problem is that I'm not sure how to stop the function on mouseout (initial and mouseout state should be the same).
Here is my current solution.
var squWrd = document.getElementById("squWrd");
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
squWrd.onmouseover = function () {
squWrd.innerHTML = "Design.";
sleep(250).then(() => { squWrd.innerHTML = "UX."; });
sleep(500).then(() => { squWrd.innerHTML = "Marketing."; });
sleep(750).then(() => { squWrd.innerHTML = "Social Media."; });
sleep(1000).then(() => { squWrd.innerHTML = "Education."; });
sleep(1250).then(() => { squWrd.innerHTML = "Branding."; });
sleep(1500).then(() => { squWrd.innerHTML = "Packaging."; });
sleep(1750).then(() => { squWrd.innerHTML = "Design."; });
sleep(2000).then(() => { squWrd.innerHTML = "Processes."; });
sleep(2250).then(() => { squWrd.innerHTML = "E-Commerce."; });
sleep(2500).then(() => { squWrd.innerHTML = "Advertising."; });
sleep(2750).then(() => { squWrd.innerHTML = "Photos."; });
sleep(3000).then(() => { squWrd.innerHTML = "Products."; });
sleep(3250).then(() => { squWrd.innerHTML = "Logos."; });
sleep(3500).then(() => { squWrd.innerHTML = "Emotions."; });
sleep(3750).then(() => { squWrd.innerHTML = "Solutions."; });
}
squWrd.onmouseout = function () {
squWrd.innerHTML = "Solutions.";
}
Do you guys have any suggestions? Thanks in advance!
Timeouts are still running, you need to call clearTimeout. I recommend you to add a second argument to the sleep function, a callback function that pass the timeout reference, this way you can clear only the timeouts related to the texts and not all the timers.
Also instead of call sleep for every text, you can store this texts inside an array an iterate over it:
var squWrd = document.getElementById("squWrd");
function sleep(ms, cb=()=> {}) {
return new Promise(resolve => {
const time = setTimeout(() => {
resolve();
}, ms);
cb(time);
});
}
const texts = ["Design", "UX.", "Marketing.", "Social Media.", "Education.", "Branding.", "Packaging.", "Design.", "Processes.", "E-Commerce.", "Advertising.", "Photos.", "Products.", "Logos.", "Emotions.", "Solutions."];
const textTimeouts = [];
squWrd.onmouseover = function() {
texts.forEach((text, i) => {
sleep(250 * i, (time) => textTimeouts.push(time)).then(res => {
squWrd.innerHTML = text;
});
});
};
squWrd.onmouseout = function() {
squWrd.innerHTML = "Solutions.";
textTimeouts.forEach(time => clearTimeout(time));
};
<h1 id="squWrd">Solutions</h1>
The problem is that even when onmouseout gets triggered, there are still sleep promises pending. You need to save the reference for each setTimeout call and clear it at onmouseout event. See here.
var squWrd = document.getElementById('squWrd');
var timeoutRefs = [];
function sleep(ms) {
return new Promise(resolve => timeoutRefs.push(setTimeout(resolve, ms)));
}
squWrd.onmouseover = function () {
squWrd.innerHTML = "Design.";
sleep(250).then(() => { squWrd.innerHTML = "UX."; });
sleep(500).then(() => { squWrd.innerHTML = "Marketing."; });
sleep(750).then(() => { squWrd.innerHTML = "Social Media."; });
sleep(1000).then(() => { squWrd.innerHTML = "Education."; });
sleep(1250).then(() => { squWrd.innerHTML = "Branding."; });
sleep(1500).then(() => { squWrd.innerHTML = "Packaging."; });
sleep(1750).then(() => { squWrd.innerHTML = "Design."; });
sleep(2000).then(() => { squWrd.innerHTML = "Processes."; });
sleep(2250).then(() => { squWrd.innerHTML = "E-Commerce."; });
sleep(2500).then(() => { squWrd.innerHTML = "Advertising."; });
sleep(2750).then(() => { squWrd.innerHTML = "Photos."; });
sleep(3000).then(() => { squWrd.innerHTML = "Products."; });
sleep(3250).then(() => { squWrd.innerHTML = "Logos."; });
sleep(3500).then(() => { squWrd.innerHTML = "Emotions."; });
sleep(3750).then(() => { squWrd.innerHTML = "Solutions."; });
};
squWrd.onmouseout = function () {
timeoutRefs.forEach(function (timeoutRef) {
clearTimeout(timeoutRef)
});
timeoutRefs = [];
squWrd.innerHTML = 'Solutions.';
};
<div id="squWrd">INITIAL VALUE</div>
I have the following code:
const timers = []
const timer1 = setTimeout(() => {
console.log('Starting timer2')
const timer2 = setTimeout(() => {
console.log('Its works')
}, 10000)
timers.push({key:2, id:timer2})
}, 10000);
timers.push({key:1, id:timer1})
function remove(key) {
for (i = 0; i > timers.length; i++) {
if (timers[i].key === key) {
timers = timers.slice(i, 1)
clearTimeout(timers[i].id)
}
}
}
When I call the remove(key) function the code is not removing the timers as expected
const timers = []
const timer1 = setTimeout(() => {
console.log('Starting timer2')
const timer2 = setTimeout(() => {
console.log('Its works')
}, 10000)
timers.push({key:2, id:timer2})
}, 10000);
timers.push({key:1, id:timer1})
function remove(key) {
const timer = timers.find(f => f.key === key);
if (timer) {
clearTimeout(timer.id);
}
}
EDIT
i was able to get it to work, but one problem now is, before it creates and additional empty item before showing other items.
NB the load on demand function works fine, but i don't know why an additional empty item is created. i guess there's an issue with my code
const viewModel = observableModule.fromObject({
_sourceDataItems: [],
dataItems: new ObservableArray(),
initDataItems: function () {
var url="https://adekunletestprojects.000webhostapp.com/skog/searchResults.php?search=" + encodeURIComponent("Adeyeye") + "&location=" + encodeURIComponent("Lagos");
fetch(url).then((response) => response.json()).then((res) => {
this._sourceDataItems = new ObservableArray(res.items);
this.dataItems.push(this._sourceDataItems);
}).catch((err) => {
var toast = Toast.makeText("Unable to load users");
toast.show();
});
},
addMoreItemsFromSource: function (chunkSize) {
console.log(this._sourceDataItems);
let newItems = this._sourceDataItems.splice(0, chunkSize);
this.dataItems.push(newItems);
},
onLoadMoreItemsRequested: function (args) {
console.log("---load more item---");
const that = new WeakRef(this);
const listView = args.object;
if (this._sourceDataItems.length > 0) {
setTimeout(function () {
that.get().addMoreItemsFromSource(10);
listView.notifyLoadOnDemandFinished();
}, 1500);
args.returnValue = true;
} else {
args.returnValue = false;
listView.notifyLoadOnDemandFinished(true);
}
},
});
Search-view-model.js
_sourceDataItems: new ObservableArray(),
dataItems: new ObservableArray(),
initDataItems: function () {
var url = "https://adekunletestprojects.000webhostapp.com/skog/searchResults.php?search=" + encodeURIComponent("Adeyeye") + "&location=" + encodeURIComponent("Lagos");
fetch(url).then((response) => response.json()).then((res) => {
this._sourceDataItems = res.items;
this.addMoreItemsFromSource(6);
}).catch((err) => {
alert(err.message);
});
},
addMoreItemsFromSource: function (chunkSize) {
console.log(this._sourceDataItems);
let newItems = this._sourceDataItems.splice(0, chunkSize);
this.dataItems.push(newItems);
},
onLoadMoreItemsRequested: function (args) {
console.log("---load more item---");
const that = new WeakRef(this);
const listView = args.object;
if (this._sourceDataItems.length > 0) {
setTimeout(function () {
that.get().addMoreItemsFromSource(10);
listView.notifyLoadOnDemandFinished();
}, 1500);
args.returnValue = true;
} else {
args.returnValue = false;
listView.notifyLoadOnDemandFinished(true);
}
},
Search.js
exports.pageLoaded = function (args) {
const page = args.object;
var searchViewModel = new SearchViewModel();
page.bindingContext = searchViewModel;
searchViewModel.initDataItems();
searchViewModel.addMoreItemsFromSource(5);
}