I've been trying to get this bit of code to work for a while, and I just can't seem to get it. It's for a live-updating graph, that takes in an array of [x, y] for each point, so an array of arrays.
The input is a JSON
list ing from a server, that updates that same JSON
object (so it changes one JSON
and updates only the value):
[
{
"Value": 10,
"Name": "Name of variable"
}
]
I need to extract the value only.
I tried it like this:
var getValueData = async function() {
var valueJSON = await Promise.resolve($.getJSON( "{% url 'get_value' %}" ));
return valueJSON[0]['Value'];
};
var data = [];
var totalPoints = 100;
var updateInterval = 1000;
var now = new Date().getTime();
function getData() {
data.shift();
while (data.length < totalPoints) {
var value = [now += updateInterval,
getValueData().then(function(result) {
result;
})
];
data.push(value);
};
};
Basically, getData()
is trying to build an array of X = timestamp.now()
, and Y = "Value"
from JSON
, then push that array into my "overall"
data array.
Doing it this way makes value
an array of [<timestamp>, Unresolved]
.
Doing it this way:
while (data.length < totalPoints) {
getZScoreData().then(function (result) {
var valueArray = [now += updateInterval, result];
data.push(valueArray);
});
};
Makes valueArray
be an actual [<timestamp>, <JSON "value"]
, if I console.log(value)
, except this way seems to hang the server forever and consume a huge amount of RAM for the tab, as if I was doing an infinite loop (hundreds of get requests to the web server, even though the max length should 100). I'm not sure of the what's going inside the Promise to get this behavior though.
This here is the code that works in the example:
while (data.length < totalPoints) {
var y = Math.random() * 100;
var value = [now += updateInterval, y];
data.push(value);
};
It seems straightforward enough. Where it says y (in var value = [now += updateInterval, y];
) make "y" get the value from my API.
I have no clue how to actually achieve this.
I'm following the example from this Flot example but I just can't manage to make it work with an actual live value from AJAX or Promise (I even tried fetch).
All examples for "live updating table" end up just using math.random()
, which is pretty misleading, as it just kinda moves about, but isn't really live.
I believe I'm not resolving the promise in the loop properly, but due to lack of experience, at this point I'm not even sure what is wrong.
I'm not sure where in my code I would go Y = "live value"
, or whether I have to return result somewhere? I'm not familiar with Promises or AJAX that much.
I've been trying to get this bit of code to work for a while, and I just can't seem to get it. It's for a live-updating graph, that takes in an array of [x, y] for each point, so an array of arrays.
The input is a JSON
list ing from a server, that updates that same JSON
object (so it changes one JSON
and updates only the value):
[
{
"Value": 10,
"Name": "Name of variable"
}
]
I need to extract the value only.
I tried it like this:
var getValueData = async function() {
var valueJSON = await Promise.resolve($.getJSON( "{% url 'get_value' %}" ));
return valueJSON[0]['Value'];
};
var data = [];
var totalPoints = 100;
var updateInterval = 1000;
var now = new Date().getTime();
function getData() {
data.shift();
while (data.length < totalPoints) {
var value = [now += updateInterval,
getValueData().then(function(result) {
result;
})
];
data.push(value);
};
};
Basically, getData()
is trying to build an array of X = timestamp.now()
, and Y = "Value"
from JSON
, then push that array into my "overall"
data array.
Doing it this way makes value
an array of [<timestamp>, Unresolved]
.
Doing it this way:
while (data.length < totalPoints) {
getZScoreData().then(function (result) {
var valueArray = [now += updateInterval, result];
data.push(valueArray);
});
};
Makes valueArray
be an actual [<timestamp>, <JSON "value"]
, if I console.log(value)
, except this way seems to hang the server forever and consume a huge amount of RAM for the tab, as if I was doing an infinite loop (hundreds of get requests to the web server, even though the max length should 100). I'm not sure of the what's going inside the Promise to get this behavior though.
This here is the code that works in the example:
while (data.length < totalPoints) {
var y = Math.random() * 100;
var value = [now += updateInterval, y];
data.push(value);
};
It seems straightforward enough. Where it says y (in var value = [now += updateInterval, y];
) make "y" get the value from my API.
I have no clue how to actually achieve this.
I'm following the example from this Flot example but I just can't manage to make it work with an actual live value from AJAX or Promise (I even tried fetch).
All examples for "live updating table" end up just using math.random()
, which is pretty misleading, as it just kinda moves about, but isn't really live.
I believe I'm not resolving the promise in the loop properly, but due to lack of experience, at this point I'm not even sure what is wrong.
I'm not sure where in my code I would go Y = "live value"
, or whether I have to return result somewhere? I'm not familiar with Promises or AJAX that much.
- What's the error you're getting? Past a full debug please – Frondor Commented May 3, 2018 at 13:53
-
getValueData() is returning a constant so I believe you can't do
getValueData().then()
. – Satish Kumar Commented May 3, 2018 at 13:53 - @Frondor there is no error, it just doesn't show anything as the "y" value of the arrays is just a Promise (unresolved) object, so the graphing library doesn't know what to do with it. I just don't get a graph at all (expected). If I try it with the method that hangs the server, I don't get any response, it just keeps sending get requests to the server infinitely. – Mormoran Commented May 3, 2018 at 14:11
-
Promises are functional and they don't get along with loops well. Promises already have some tools like
Promise.all()
,Promise.race()
or dynamic sequential execution of promises to handle your needs on recurring asynchronous cases. If you are fond of loops then you should look intoasync-await
abstraction. – Redu Commented May 3, 2018 at 20:09
3 Answers
Reset to default 3Promises in loops are rarely a good idea, you'll usually want to use Promise.all()
to execute multiple Promises at once, and get their results collected in an array:
function getData() {
// Note: Why is this here?
data.shift();
var promises = [];
while (data.length < totalPoints) {
promises.push(getValueData());
}
Promise.all(promises).then(results => {
for (let result of results) {
var value = [
now += updateInterval,
result
];
data.push(value);
}
});
};
MDN has some good materials on Promises: https://developer.mozilla/en-US/docs/Web/JavaScript/Guide/Using_promises
As a side note, executing 100 AJAX requests at the same time sounds pretty strenuous, even with Promise.all()
. You should either try to optimize the backend if you have any influence over it, or look into Worker
s to execute the requests in batches.
You can generate array of Promises and then wait of resolve with Promise.all
.
// Let's imitate some async operation
// It is instead of your getValueData
function twiceAsync(a) {
// returns a promise resolving to twice argument
return new Promise(function(ok) {
setTimeout(function(){ok(2*a)}, 100);
});
}
var pList = [];
for (var i = 0; i < 100; ++i) {
// collect promises returned by twiceAsync to an array
pList.push(twiceAsync(i));
}
Promise.all(pList) // provide array of promises to Promise.all
.then(function(results) { // receive resolved results, they should be even numbers from 0*2 to 99*2
console.log(results);
})
Some things you should take in mind
- Your
getValueData
is not reaching the return statement because it resolves as soon as it reachPromise.resolve
. (In the my example, nowgetData
returns a promise) - Use
Promise.all
so you don't wait for the previous one to plete before executing the next... It resolves once every promise in the raid resolves, or one of them fails (you have to.catch
that). - Learn more about Promises, they are scary at first, but you'll end up loving em
Try this code, it may not work because I don't have the full working example, but you can get around errors probably and get it to work.
var results = [],
totalPoints = 100,
pointsLeft = totalPoints, // since we are using Promise.all, now we have to track this instead of results.length
updateInterval = 1000,
promises = [],
getValueData = async function(timestamp) {
await $.getJSON('yourURL').done(function (data) {
pointsLeft-- // promise fulfilled
Promise.resolve({ data, timestamp })
}).fail(Promise.reject)
};
function getData() {
// results.shift(); why?
while (pointsLeft) {
// push the promise to the stack, collect them later
promises.push(getValueData(Date.now()))
};
Promise.all(promises).then(function (responses) {
responses.forEach(function (data, timestamp) {
results.push([timestamp, data])
})
}).catch(console.warn)
};