In my app, I need to run my app offline because drivers have to use that app and in remote areas, they might not find internet for that purpose I need to download all data in advance through Axios request at the time they have internet. so that request can get data from the cache instead of server.
At the moment i tried this but this doesn't seems to be good practice
tryOffileWorkSheet: async function () {
Network.addListener("networkStatusChange", (status) => {
if (status.connected) {
setInterval(function () {
let worksheet = JSON.parse(localStorage.getItem("worksheet"));
if (worksheet == null) {
worksheet = [];
}
// localStorage.removeItem('worksheet')
for (let i = 0; i <= worksheet.length; i++) {
if(worksheet.length > 0){
setTimeout(function () {
if(worksheet[i]?.work_order_id){
ApiService.get(
`/api/gangBoss/work-sheet/${worksheet[i].work_order_id}/${worksheet[i].column_name}/${worksheet[i].value}`
).then((response) => {
if(response.data.status){
worksheet.splice(i,1)
localStorage.setItem("worksheet", JSON.stringify(worksheet));
}
console.log('After', worksheet)
// this.closeModal();
});
}
},i* 3000);
}
}
}, 3000);
}
});
},
also for this, it is necessary for the user to behave on this page when the internet available it means that we need to download a lot of data.
Can you please tell me the best practice to do that or plugin for vue which can help for that
The question is sort of unclear and is not maybe the best fit for SO, but I'll try to answer.
The first thing I noticed here is the use of setInterval, not that you are using it, but rather how. There's nothing that stops the interval from running. Here's a scenario that I hope illustrates the problem
networkStatusChange fired: status.connected === true
setInterval creates interval #1
3 seconds later interval #1 fires
... this keeps happening for the next 2 hours
networkStatusChange fired: status.connected === false
... interval#1 keeps firing
networkStatusChange fired: status.connected === true
setInterval creates interval #2
within 3 seconds interval #1 fires
3 seconds later interval #2 fires
... intervals #1 and #2 keep firing (twice within 3 seconds)
networkStatusChange fired: status.connected === false
networkStatusChange fired: status.connected === true
setInterval creates interval #3
within 3 seconds interval #1 fires
within 3 seconds interval #2 fires
3 seconds later interval #3 fires
... intervals #1, #2 and #3 keep firing (three within 3 seconds)
So there's two problems. The interval keeps firing regardless of whether the system is still connected.
You might be better of just firing every 3 seconds with a single timer, and exiting if the connection is not available. This also allows using window.navigator.onLine, which has much better browser support.
I don't know how long you expect worksheet to be, but if you have the ApiService called through setTimeout 3 seconds apart, and then call the parent function every 3 seconds, you're going to be sending a lot of requests.
tryOffileWorkSheet: function () {
// (need to create `intervalId` in data)
if (this.intervalId) clearInterval(this.intervalId);
this.intervalId = setInterval(() => {
if (window.navigator.onLine) {
this.getWorkSheet();
}
}, 3000);
},
getWorkSheet: function () {
let worksheet = JSON.parse(localStorage.getItem("worksheet"));
if (worksheet == null) {
worksheet = [];
}
for (let i = 0; i <= worksheet.length; i++) {
if (worksheet.length > 0) {
setTimeout(() => {
if (worksheet[i]?.work_order_id) {
ApiService.get(
`/api/gangBoss/work-sheet/${worksheet[i].work_order_id}/${worksheet[i].column_name}/${worksheet[i].value}`
).then((response) => {
if (response.data.status) {
worksheet.splice(i, 1);
localStorage.setItem("worksheet", JSON.stringify(worksheet));
}
console.log("After", worksheet);
});
}
}, i * 300);
}
}
},
Related
I have some websocket that sends around 100's of data per second,I want to limit it to only 1 data per 500 ms.
onMessage(data) {
console.log(data); // This prints around 100 different times within 1 second
}
I tried something like below , Is this the right approach or is there any other better way to do it ? because this code runs 100 times per second.
var lastlog = new Date().getTime();
onMessage(data) {
currenttime = new Date().getTime();
if ( currenttime - lastlog > 500) {
console.log(data);
lastlog = new Date().getTime();
}
}
P.s : I can ignore remaining data and will be able to reduce the 500 ms to 200ms.. that is 5 data per second.
Here is another way of doing it, using the npm package throttle-debounce. This method is not "better". It can result is less code typed but you might not want the dependency on the package.
You can use the throttle function and specify how many milliseconds until it can be called again. Setting the second argument to true prevents the last request from being deffered -https://www.npmjs.com/package/throttle-debounce#notrailing.
The example below uses the library to throttle how often a button is pressed.
const { throttle } = throttleDebounce
const handleRequest = throttle(500, true, () => {
console.log('this request will be handled')
})
<script src='https://cdn.jsdelivr.net/npm/throttle-debounce#3.0.1/umd/index.js'></script>
<button onClick="handleRequest()">Mimick sending message</button>
Your use case might look like this:
import { throttle } from 'throttle-debounce'
const onMessage = throttle(500, true, () => {
console.log(data);
})
Less lines than your example, but that doesn't mean it's "better".
I'm trying to book a vaccine in my country. This code applies the filters and then clicks a slot if vaccines are available.
The first 3 lines select the filters and the last line clicks on an available slot.
document.querySelector('.pin-search-btn.district-search.md.button.button-solid.ion-activatable.ion-focusable.hydrated').click()
setTimeout(() => {
document.querySelector('#c1').click()
}, 1000);
setTimeout(() => {
document.querySelector('#c5').click()
document.querySelectorAll('.vaccine-box').forEach(function(item) {
if (item.getElementsByTagName('a')[0].innerHTML !== ' Booked ' && item.getElementsByTagName('a')[0].innerHTML !== ' NA ') {
item.getElementsByTagName('a')[0].click()
}
})
}, 2000);
<-- html needed -->
I want to run this code in a loop over a 2 second time interval until the final click has been performed. item.getElementsByTagName('a')[0].click()
P.S : I'm running this in Developer Tools on Chrome, I don't know if that info is relevant here or not.
Intuitively, I would suggest keeping a boolean hasClickedSlot = false, which you update once a slot has been clicked. Before calling setTimeout for 2 more seconds, ensure that !hasClickedSlot still holds.
That could look something like:
let hasClickedSlot = false;
function clickButton() {
document.querySelector('.pin-search-btn.district-search.md.button.button-solid.ion-activatable.ion-focusable.hydrated').click();
// after 1 second, click on the C1 button
setTimeout(clickC1, 1000);
}
function clickC1() {
document.querySelector('#c1').click();
// after 2 seconds, try to click on a slot
setTimeout(tryClickSlot, 2000);
}
function tryClickSlot() {
document.querySelector('#c5').click();
document.querySelectorAll('.vaccine-box').forEach(function(item) {
if (item.getElementsByTagName('a')[0].innerHTML !== ' Booked ' && item.getElementsByTagName('a')[0].innerHTML !== ' NA ') {
item.getElementsByTagName('a')[0].click()
hasClickedSlot = true;
}
});
// if no slot was clicked yet, do it again
if (!hasClickedSlot) {
clickButton();
}
}
// start the process
clickButton();
The disadvantage of this code specifically is that a stack of calls is built, as the functions do not return but rather keep stacking.
Edit: Since the functions return after calling setTimeout no stack call is built (as it would during recursion, for instance).
I have this code here:
server:
io.emit('attack-damage', {
damage: damage,
attacker: username,
});
client:
socket.on('attack-damage', (data) => {
setTimeout(() => this.damageVisible = false, 1000);
});
What it does is when user clicks attack it emits and shows damage of the user that fades away after one second. Problem is that let's say if I click attack my damage is being shown but also if another player clicks attack then it's damage is being shown and mine damage fades out faster than after 1 second it just replaces the new damage from another player. How to show multiple damages on the screen and not just one ?
EDIT
socket.on('attack-damage', (data) => {
this.damage = data.damage;
this.aryDamage.push(data.damage, data.attacker);
if (!this.bolDamageRunning) {
if(this.aryDamage.length != 0) {
this.bolDamageRunning = true;
setTimeout(() => {
this.damageVisible = false;
this.aryDamage.splice(0,1);
this.bolDamageRunning = false;
}, 2000);
} else {
}
} else {
}
setTimeout(() => this.damageVisible = true, 2000);
When I use above code it makes appear damage after two seconds after the click. But also if I use two users, then old damage from screen is being replaced with new one
create a global array called aryDamage.
create a global boolean called bolDamageRunning.
client socket.on('attack-damage'), add a new element to the array, e.g.
aryDamage.push(data);
create a timer using setInterval to read the aryDamage every 100 ms.
function thisTimerCalledEvery100MS() {
// run Damage only when last Damage finish
if (!bolDamageRunning) {
// Check whether another damage waiting
if (aryDamage.length != 0) {
// Set running true
bolDamageRunning = true;
// call funDamage after 1 second
setTimeout(funDamage, 1000);
} else {
// No command waiting, do nothing
}
} else {
// Another command running, do nothing
}
}
function funDamage() {
// Your code to show damange, or
// do something with the first element of aryDamage
this.damageVisible = false;
// remove top element from aryDamage
aryDamage.splice(0,1);
// Set running = false
bolDamageRunning = false;
}
This technique makes sure the last 'Command' finishes before executing next 'Command'.
I am working with React and socket.io, every time an event happens there is a socket listening to any changes.
I have this in my actions
socket.on('playerCount', (data) => {
PlayerSlotActions.updatePlayerAmount({
playerAmount : data.cardCount,
position : data.position,
});
})
where the data param returns this
{
playerAmount : 10,
position : 2
}
sometimes from the socket, comes from 4 to 7 events in one shot in order to change the playerAmount key to another value. Every time I receive that event, I should change the number of the playerAmount to the new number sent from the socket.
My issue:
lets say in the view I have something like Player Amount: 10, and then the socket sends the numbers 1, 3 and 5 in one shot, so the new amount would change to 19 which is the sum of the new number, and that is OK, but that change shouldn't happen quick, between the sum of one number and another, there should be 5 seconds of difference, like:
Player Amount: 10
after 5 seconds...
Player Amount: 11
after 5 seconds...
Player Amount: 14
after 5 seconds...
Player Amount: 19
... and so on.
so I am trying to figure out which is the best method to use here. With setTimeout, it does what I want but only the first attempt, the rest of the sums takes around 1 second of difference even if you put a timeout for 5 seconds.
I am using lodash, so I thought maybe _.debounce, _.throttle or _.delay methods could help, but I was wrong. Only delay works the same way as setTimeout
I did it like this
socket.on('playerCount', (data) => {
setTimeout(function() {
PlayerSlotActions.updatePlayerAmount({
playerAmount : data.cardCount,
position : data.position,
});
}, 5000);
});
I am just learning this. Is there a way like to store the new numbers in an array or something like this ?
Tell me your recommendations.
Just in case you want to see my code
the code above is in my actions, from the actions, it goes to the stores
#bind(PlayerSlotActions.updatePlayerAmount)
updatePlayerAmount (data) {
this.state.playerSlots[data.position - 1].playerAmount = data.playerAmount;
}
and from there, it goes directly to the component
componentDidUpdate () {
let playerAmount = this.props.playerAmount;
this.refs.playerAmount.getDOMNode().innerHTML = playerAmount;
}
UPDATE
connect () {
socket = io.connect('localhost:1101/server');
socket.on('playerCount', (data) => {
console.log('1');
queue.push({
playerAmount : data.cardCount,
position : data.position,
});
})
setTimeout(function() {
if (queue.length > 0) {
var data = queue.splice(0, 1)
PlayerSlotActions.updatePlayerAmount(data);
}
}, 5000);
}
So you had problems putting in my code from this question: How to do a queue in order to wait 5 seconds to execute a function
I don't know if you solved it with Will Newton now, but in case you didn't, try this:
// variables for the queue and a boolean to
// indicate whether the queue gets worked on or not
var queue = [];
var notRunning = true;
connect () {
socket = io.connect('localhost:1101/server');
socket.on('playerCount', (data) => {
console.log('1');
queue.push({
playerAmount : data.cardCount,
position : data.position,
});
startQueue();
})
// Initiating function, has to be seperate because else each socket connect
// would trigger a new instance of processQueue, which would result
// in shorter times than 5s between the updates
function startQueue(){
if(notRunning){
notRunning = false;
processQueue();
}
}
// Recursive function, calls itself every 5 seconds as long as there are
// items in the queue
function processQueue(){
if(queue.length > 0){
setTimeOut(function(){
// passes the first item of the queue in your function
PlayerSlotActions.updatePlayerAmount(queue[0]);
// removes first item from the queue
queue.shift();
processQueue();
}, 5000)
}else{
notRunning = true;
}
}
}
Yes, your idea about storing data in an array will work.
We can treat the array like a queue.
However, you are limited to it only updating every 5 seconds.
var queue = [];
socket.on('playerCount', (data) => {
queue.push({
playerAmount : data.cardCount,
position : data.position,
});
});
setInterval(function() {
if (queue.length > 0) {
var data = queue.shift();
PlayerSlotActions.updatePlayerAmount(data);
}
}, 5000);
I am attempting to build a webapp on a Chromebook, I need it to read RFID card serial numbers with an ACR122U NFC. I am using chrome-nfc.
I am reading cards happily, but I do not know how to fire an event when a card is presented.
Are there any events in chrome-nfc I can use to know when a card has been presented to the reader?
EDIT: I have been trying to use chrome.nfc.wait_for_tag, but it does not behave as I would expect.
// With a card on the reader
chrome.nfc.wait_for_tag(device, 10000, function(tag_type, tag_id){
var CSN = new Uint32Array(tag_id)[0];
console.log ( "CSN: " + CSN );
});
[DEBUG] acr122_set_timeout(round up to 1275 secs)
DEBUG: InListPassiveTarget SENS_REQ(ATQA)=0x4, SEL_RES(SAK)=0x8
DEBUG: tag_id: B6CA9B6B
DEBUG: found Mifare Classic 1K (106k type A)
[DEBUG] nfc.wait_for_passive_target: mifare_classic with ID: B6CA9B6B
CSN: 1805372086
// with no card on the reader
chrome.nfc.wait_for_tag(device, 10000, function(tag_type, tag_id){
var CSN = new Uint32Array(tag_id)[0];
console.log ( "CSN: " + CSN );
});
[DEBUG] acr122_set_timeout(round up to 1275 secs)
DEBUG: found 0 target, tg=144
Both return the results as above immediately, it does not seem to matter what number I use for a timeout...
If I call the function with no card on the reader, and then immediately put the card on the reader after function call, I get no output in the console.
I'm not familiar with chrome-nfc, but taking a shot in the dark by reverse engineering the source, it looks like you would want to use the wait_for_tag method, like:
chrome.nfc.wait_for_tag(device, 3000, function(tag_type, tag_id) {
// Do your magic here.
});
...Where device is your reader, 3000 is the maximum time to wait (in ms), and replacing // Do your magic here. with your desired logic. If it times out, both tag_type and tag_id will be null.
If you wanted to wait indefinitely, you could just recursively call a function with the above code. Example:
function waitAllDay(device) {
chrome.nfc.wait_for_tag(device, 1000, function(tag_type, tag_id) {
if(tag_type !== null && tag_id !== null)
{
// Do your magic here.
}
waitAllDay(device);
});
}
That's assuming you want it to continue waiting even after a tag has been presented. Wrap the waitAllDay(device); in an else if you want it to stop once a tag is read.
UPDATE: It seems the wait_for_tag method does not work as intended, so I'm proposing a second solution. I'm leaving the existing solution in place in case the method is fixed by the developers of chrome-nfc.
Another thing to try is to use chrome.nfc.read, passing in a timeout option, inside a window.setInterval.
var timer = window.setInterval(function () {
chrome.nfc.read(device, { timeout: 1000 }, function(type, ndef) {
if(!!type && !!ndef) {
// Do your magic here.
// Uncomment the next line if you want it to stop once found.
// window.clearInterval(timer);
}
});
}, 1000);
Be sure and call window.clearInterval(timer) whenever you want it to stop watching for tags.
While I do not consider this a proper solution; here is a workaround I am using for the time being.
function listen_for_tag(callback, listen_timeout){
var poll_delay = 400; //ms
var listen_loop = null;
if(!listen_timeout){
listen_timeout = 99999999;
}
function check_for_tag(){
if(listen_timeout < 0) {
clearInterval(listen_loop);
console.log("we didnt find a tag. finished");
}
chrome.nfc.wait_for_tag(dev_manager.devs[0].clients[0], 10, function(tag_type, tag_id){
console.log ( "FOUND A TAG!!" );
clearInterval(listen_loop);
// handle the callback (call it now)
var C = callback;
if (C) {
callback = null;
window.setTimeout(function() {
C(tag_type, tag_id);
}, 0);
}
});
listen_timeout -= poll_delay;
}
listen_loop = setInterval(check_for_tag, poll_delay);
}