I'm learning JS, but I don't know if it's possible to do what I want to achieve.
I have a variable named btcVariationTotal which is in a condition, and I want to retrieve the value of this variable in another variable called tmp, but this variable is not included in the condition.
My problem is that tmp always shows me 0. I don't understand why? And how can I solve this problem, please?
I really want to retrieve the value outside the condition.
console.clear();
let wsBtc = new WebSocket('wss://stream.binance.com:9443/ws/btcusdt#trade');
let btcStockPriceElement1 = document.getElementById('btcValue1');
let btcStockPriceElement2 = document.getElementById('btcValue2');
let btcLastPrice = null;
let btcStockObject = null;
wsBtc.onmessage = (event) => {
btcStockObject = JSON.parse(event.data);
};
let btc1 = 0, btc2 = 0;
let btcVariation_1_2 = 0;
let btcVariationTotal = 0;
let tmp = 0;
let btcRunTimers = setInterval(() => {
let minutes = new Date().getMinutes();
if (minutes === 51) {
let val1 = parseFloat(btcStockObject.p).toFixed(1);
let price = parseFloat(btcStockObject.p).toFixed(1);
btcStockPriceElement1.innerText = price;
btcStockPriceElement1.style.color =
!btcLastPrice || btcLastPrice === price
? 'black'
: price > btcLastPrice
? '#AAFF00'
: 'red';
btcLastPrice = price;
btcStockObject = null;
btc1 = val1;
}
if (minutes === 52) {
let val2 = parseFloat(btcStockObject.p).toFixed(1);
let price = parseFloat(btcStockObject.p).toFixed(1);
btcStockPriceElement2.innerText = price;
btcStockPriceElement2.style.color =
!btcLastPrice || btcLastPrice === price
? 'black'
: price > btcLastPrice
? '#AAFF00'
: 'red';
btcLastPrice = price;
btcStockObject = null;
btc2 = val2;
btcVariation_1_2 = ( (parseFloat(btc2) - parseFloat(btc1)) / btc1 * 100);
document.getElementById("btcResult1").innerHTML = btcVariation_1_2.toFixed(2);
}
btcVariationTotal = (parseFloat(btcVariation_1_2));
console.log("btc variation => " + btcVariationTotal);
document.getElementById("result").innerHTML = btcVariationTotal.toFixed(2);
tmp = btcVariationTotal;
}, 60000);
console.log("tmp => " + tmp);
The good news is that you are in fact doing what you want: you are retrieving
the value of the btcVariationTotal variable, and storing in tmp, which is
defined in the outer scope, outside of your setInterval callback.
The only problem you have is that you can't display a modified tmp, and
that's because you only call console.log before setting tmp, you never
call it after it has been changed. User Ivar has tried to explain that in
the comments, maybe I can detail it a bit more:
At time t=0, you set tmp = 0, you set your timers with setInterval, associating
a callback function (which does NOT run at this point), and then you call
console.log to display tmp (it's 0, because no callback has ever run).
At time t=60s, your callback runs, sets btcVariationTotal to some value, and
assigns that to tmp. No attempt is made to display the tmp value. Then this
gets repeated every 60s.
So what's missing is for you to write some code that displays the tmp value
after it has been changed. One way to do that, is to put that code inside
some other callback and arrange for it to be called. I suggest a simple
button. Add the following somewhere in your html page:
<button id="show-tmp">Show tmp</button>
Add the following lines at the end of your JS code:
let btn = document.getElementById('show-tmp');
btn.onclick = function() {
console.log(`tmp: ${tmp}`);
}
Now clicking on the button will show you the value inside tmp; if you do it
before the first 60 seconds, it will show 0; if you do it afterwards, it will
show whatever value was in btcVariationTotal.
Related
I would like to access variable from inside a function. The variable tip is innerText of different buttons (5, 6, 7...), but they are in %, so I converted them into numbers. However, the numbers are accessible only from inside the percentage function. When I try to call the function and log the variable, it shows NaN. I would like to use the tip for calculation in calc function always after clicking a respective button. How can I do that?
let tip = 0;
const billInput = document.querySelector(".bill__input");
const peopleInput = document.querySelector(".people__input");
const individualTip = document.querySelector(".conclusion__tip-person");
const individualTotal = document.querySelector(".conclusion__total-person");
const reset = document.querySelector(".conclusion__reset");
const buttons = document.querySelectorAll(".select-tip__button");
function percentage() {
tip = parseInt(this.innerText);
}
buttons.forEach((button) => {
button.addEventListener("click", percentage);
});
function calc() {
if (billInput !== "" && peopleInput === "") {
}
individualTip.textContent = (billInput.value / 100) * tip;
individualTotal.textContent =
"$" + (billInput.value / peopleInput.value).toFixed(2);
}
document.addEventListener("input", calc);
To make it little bit smaller:
I cant access numbers from variable tip, which innerText of buttons with different values (5%, 10%...). These numbers are converted from strings to numbers in the percentage function. I can access the correct tip values after clicking on buttons only if I log it directly inside the percentage function. I would like to use it outside the function, however.
let tip = 0;
function percentage() {
tip = parseInt(this.innerText);
}
buttons.forEach((button) => {
button.addEventListener("click", percentage);
});
you need change string to integer before you calculation
parseInt(peopleInput.value)
In the if (billInput !== "" && peopleInput === ""), you should return to not execute the reset of the function, Also the inputs values be as string format, you need to convert to number, you can use + operator.
let tip = 0;
const billInput = document.querySelector(".bill__input");
const peopleInput = document.querySelector(".people__input");
const individualTip = document.querySelector(".conclusion__tip-person");
const individualTotal = document.querySelector(".conclusion__total-person");
const reset = document.querySelector(".conclusion__reset");
const buttons = document.querySelectorAll(".select-tip__button");
function percentage() {
tip = parseInt(this.innerText);
}
buttons.forEach((button) => {
button.addEventListener("click", percentage);
});
function calc() {
if (billInput !== "" && peopleInput === "") {
// if there no value doesn't execute the rest of the function.
return
}
individualTip.textContent = (+billInput.value / 100) * tip;
individualTotal.textContent =
"$" + (+billInput.value / +peopleInput.value).toFixed(2);
}
document.addEventListener("input", calc);
So for anyone who would encounter similar problem, I solved this one. My variables and fucntions works properly. All I had to do was to put function calc() as the last line inside percentage() function. That did the trick. That's it.
Make a find prime number function in javascript. I want to let it display the values to textarea whenever it finds a prime number.
However, it will only show the result when the function is fully executed.
Here is my code:
let start = performance.now()
let textarea = document.querySelector('textarea')
let time = document.getElementById('time')
let texts = document.getElementById('texts')
let amount = document.getElementById('amount')
let status = document.getElementById('status')
let logs = [];
let number = 0
let prime = [];
function check(){
status.textContent = 'processing'
amount.textContent = 'processing'
time.textContent = 'processing'
textarea.textContent =logs
setTimeout(function(){reallycheckprimenumber()},0)
}
function reallycheckprimenumber(){
number = 0;
let start = performance.now()
let value = texts.value
if(value ==''){
value = texts.placeholder;
}
for (var i = 0;i<value;i++){
time.textContent = ''
amount.textContent = ''
var nums = 2;
for (let x = 0;x<=i/2;x++){
if(nums>3){
break;
}
if(i!==0 && i!==1 && i !== x){
if(i%x === 0){
nums++;
}
}
}
if(nums === 3){
prime.push(i)
textarea.textContent += prime
number +=1
}
if(i === value-1){
status.textContent = 'done'
let end = performance.now()
time.textContent = (end-start).toFixed(5) +'ms'
amount.textContent = number
}
}
}
check()
<h1>Get Prime number application:</h1>
<h2>Prime Number: <span></span></h2>
<h3 >Processing Time: <span id = 'time'>0 ms</span></h3>
<h3>Number: <span id = 'amount'>0</span></h3>
<h3>Status: <span id = 'status'>Processing</span></h3>
<label for = 'texts'>Enter the range you want to get number from</label>
<input type = 'text' id = 'texts' placeholder = '100'>
<input type = 'button' id = 'button' value = 'set' onclick = 'check()'>
<textarea readonly></textarea>
I have tried several ways to make the application displays prime number while it is finding other prime number. However, I failed.
I found that only console will work.
I really have no idea on how to solve this problem.
Anyone have an idea and know how to solve it?
Thanks so much for any helps and supports
Start with 2,3 already, you do not have to check for them every time with === . It should be enough to check until the sqrt of the number. The below snippet will print the list to a textArea if it finds one.
Note that using setTimeout or any sort of fixed interval update does not seem like a good idea because prime numbers get sparse over time, which means it will take longer and longer to log something on the screen.
(function(start){
const list = start,
myarea = document.getElementById("myarea");
let nCurrent = start[start.length - 1];
function recurse(){
let _sqrt = Math.sqrt(nCurrent);
for (let i = 2; i <= _sqrt; ++i) {
if(!(nCurrent % i)){
break;
}
if (i === Math.floor(_sqrt)){
list.push(nCurrent);
myarea.textContent = list.toString();
}
}
nCurrent++;
};
setInterval(recurse,500);
}([2,3]))
<textArea id="myarea"></textArea>
Explanation:
Outer most function is an immediately invoked function expression (iife), which gets 1 parameter, a list to start with. In this case we start with [2,3], first 2 primes.
Inside we create 3 variables:
the list, that holds all primes found until now
nCurrent, which is the current number we are checking if prime
recurse, a recursive function that will be called by setInterval.
For every nCurrent, lets say 120, it is sufficient to look until the sqrt of 120, and see whether numbers <= sqrt(120) divides 120. If it does, the operator % will return 0, and !(nCurrent % i) will therefore return true (!0 is true). In that case we know this is not a prime number, we terminate early, increment nCurrent and wait until the next call of recurse.
If all the i's until sqrt(nCurrent) is tested and does not divide it, then we have a prime and we push it to the list.
list.toString() is defult stringification of an array in JS, which return all the elements joined by comma.
I have a question / problem about a variable.
I have two page, in the first one I recover data and in the second one I do some operations.
ActivityPage.js (the first one)
recoverActivity() {
// this function check every second if the size of array > 1000
// this call only a function in the other page (Operations)
Operations.write({
arrayTimestamp: this.arrayTimestamp,
// other things
});
}
//this function when the user click a stop button.
stopActivity() {
Actions.Operations({
arrayTimestamp: this.arrayTimestamp,
});
}
And the I have another page
Operations.js:
//this is called from the first page directly
write(objectData) {
//...
this.timestampCheck(objectData.arrayTimestamp);
//...
}
//this is call from the ComponentDidMount of the second page.
stopClick() {
//...
this.timestampCheck(this.props.arrayTimestamp);
//...
}
Now my problem is in this timestampCheck function:
timestampCheck(timestamp) {
var int_max = 65536;
this.base = 0;
var diff = "";
var start = parseInt(this.contatore);
for (let i = 0; i < timestamp.length; i++) {
let timestamp = parseInt(timestamp[i]);
diff = (this.base + timestamp) - start;
if (diffDestro < 0) {
this.base+= int_max;
diff += this.base;
}
this.tempoReale.push(diff);
}
}
This function is called from the two function stopClick and write and there I have a variable this.base. Now I don't want that this variable loose his value when it leaves the functions timestampCheck. For example the arrayTimestamp has a size > 1000 an so it call the write() functions. here calculations are made and the value of this.base is set.
At this point, if the user clicks the stop key, the stopClick () function is called which calls the same timestampCheck function and must resume the previous value of this.base and not start from scratch.
How do you think I can do it?
thank you so much.
Just use a variable outside of the function to store the new value.
So outside of the function:
var countingValue = 0;
function timestampCheck(timestamp) {
var int_max = 65536;
this.base = 0;
var valueToUse = countingValue > 0 ? countingValue : this.base;
var diff = 0;
var start = parseInt(this.contatore);
for (let i = 0; i < timestamp.length; i++) {
let timestamp = parseInt(timestamp[i]);
diff = (valueToUse + timestamp) - start;
if (diffDestro < 0) {
valueToUse += int_max;
diff += valueToUse;
}
this.tempoReale.push(diff);
countingValue = countingValue + diff;
}
}
So what I have done here is create a variable outside of the function named countingValue with an initial value of 0.
Then underneath the initialisation of this.base I have used a type of If statement known as a ternary operator which says if the current countingValue is more than 0 then we will store that value in a variable named valueToUse otherwise we will use the this.base value and store it in the valueToUse variable.
In the rest of the code I have used the valueToUse variable for the computations now instead of this.base.
Note: I changed your variable diff to an integer because it was a string. You may want to review this and swap a couple of variables around if it's not exactly what you want.
In JAVASCRIPT:
If I have a variable which value is constantly changing (100+ times a second). How do I 'record' a specific value at a specific point in time?
Added to this, how do I base this point in time off of another variable of which value has changed?
This needs to be strictly in JavaScript. I've looked at the onChange() method, but I'm unsure if I have to use this in conjunction with HTML for it to work. If not, could someone give me an example where this is not the case?
Cheers
I'm not 100% clear on what you're trying to do, but as Ranjith says you can use setTimeout to run arbitrary code at some (approximate) future time.
This example could likely be improved if I had a bit more detail about what you're doing.
If you're in a node environment you might consider using an event emitter to broadcast changes instead of having to have the variable in scope. (This isn't particularly hard to do in a browser either if that's where you are.)
The html/css parts of this are just for displaying the values in the example; not necessary otherwise.
const rand = document.getElementById('rand');
const snapshot = document.getElementById('snapshot');
let volatile = 0;
// update the value every ~100ms
setInterval(() => {
// assign a new random value
volatile = Math.random();
// display it so we can see what's going on
rand.innerText = volatile;
}, 100);
// do whatever you want with the snapshotted value here
const snap = () => snapshot.innerText = volatile;
// grab the value every 2 seconds
setInterval(snap, 2000);
div {
margin: 2rem;
}
<div>
<div id="rand"></div>
<div id="snapshot"></div>
</div>
Ok - well you can poll variable changes ... even though you can use setters...
Lets compare:
Polling:
let previous;
let watched = 0;
let changes = 0;
let snap = () => previous = watched !== previous && ++changes && watched || previous;
let polling = setInterval(snap, 100);
let delta = 1000 * 2
let start = Date.now();
let last = start;
let now;
let dt = 0
while(start + delta > Date.now()){
now = Date.now();
dt += now - last;
last = now;
if(dt > 100){
watched++;
dt = 0;
}
}
document.getElementsByTagName('h1')[0].innerText = (changes === 0 ? 0 : 100 * watched / changes) + "% hit"
if(watched - changes === watched){
throw Error("polling missed 100%");
}
<h1><h1>
emitting:
const dataChangeEvent = new Event("mutate");
const dataAccessEvent = new Event("access");
// set mock context - as it is needed
let ctx = document.createElement('span');
// add watchable variable
add('watched', 0);
//listen for changes
let changes = 0;
ctx.addEventListener('mutate', () => changes++);
let delta = 1000 * 2
let start = Date.now();
let last = start;
let now;
let dt = 0
while(start + delta > Date.now()){
now = Date.now();
dt += now - last;
last = now;
if(dt > 100){
ctx.watched++;
dt = 0;
}
}
document.getElementsByTagName('h1')[0].innerText = (changes === 0 ? 0 : 100 * ctx.watched / changes) + "% hit"
if(ctx.watched - changes === ctx.watched){
throw Error("trigger missed 100%");
}
function add(name, value){
let store = value
Object.defineProperty(ctx, name, {
get(){
ctx.dispatchEvent(dataAccessEvent, store)
return store;
},
set(value){
ctx.dispatchEvent(dataChangeEvent, {
newVal: value,
oldVal: store,
stamp: Date.now()
});
store = value;
}
})
}
<h1></h1>
The usage of a while loop is on purpose.
I'm writing analytics and I have to initialize counter counts for (keys) hours, days, weeks, years so as to get frequency of user activity. I need to create a hit count for respective time and increment accordingly. Visits are fed via a loop.
I have this working but I'm not sure if the code below is ideal to do so.
if(!analytics.users[message.user].counts.hourly[hour]) {
analytics.users[message.user].counts.hourly[hour] = 0;
}
analytics.users[message.user].counts.hourly[hour] += 1;
if(!analytics.users[message.user].counts.daily[day]) {
analytics.users[message.user].counts.daily[day] = 0;
}
analytics.users[message.user].counts.daily[day] += 1;
...
I've tried the x = x + 1 || 0 method but that hasn't worked.
Also, is there a way I can set up a function for this?
You could use a function which take the object and the key and perfoms the check and update.
function increment(object, key) {
if (!object[key]) object[key] = 0;
++object[key];
}
Call with
increment(analytics.users[message.user].counts.hourly, hour);
I've tried the x = x + 1 || 0
You almost got it. It should either be:
x = x || 0;
x++;
Or
x = x + 1 || 1;
So, change your code to:
analytics.users[message.user].counts.hourly[hour] =
(analytics.users[message.user].counts.hourly[hour] + 1) || 1
If analytics.users[message.user].counts.hourly[hour] is undefined, the increment operation returns NaN. This is a falsy value. So, it takes 1
You can create a simple increment function like the one below. It first checks for the key to be initialized and if not, it will initialize it to 0. The next line with the increment is safe to execute since the key was previously created.
let message = {
user: "user"
}
let analytics = {
users: {
"user": {
counts: {
}
}
}
}
function incrementAnalytics(analytics, period) {
analytics[period] = analytics[period] || 0;
++analytics[period];
}
let test = analytics.users[message.user].counts;
incrementAnalytics(test, "hourly");
incrementAnalytics(test, "hourly");
incrementAnalytics(test, "daily");
console.log(test);
Cheers!