Good day all,
Please i'm trying to get the latency values of a ping using xmlhttprequest in a for loop for five consecutive latencies that will be stored in an global array in a react native application, after which when the for loop finishes, other codes can now execute, but it seems that the whole code just runs through without getting the array values from the initial for loop and the final result comes out as 0, then later, I start getting the array values due to the result of the xmlhttprequest. How can I ensure that I get the latency results first before now executing the remaining code. My code is below:
let latencies = [];
class App extends Component {
startScan = () => {
this.setState({
scanning: true,
});
this.getJitter();
}
getPing = () => {
var request = new XMLHttpRequest();
var startTime = new Date();
request.open(
'GET',
'http://dummy.restapiexample.com/api/v1/employees',
true,
);
request.send();
request.onreadystatechange = (e) => {
if (request.readyState == 4 && request.status == 200) {
var endTime = new Date();
var ping = endTime.getTime() - startTime.getTime();
this.setState({ping: ping});
latencies.push(ping);
console.log('ping:', ping);
console.log(latencies);
return ping;
}
};
};
getJitter = () => {
for(var i=0; i<5; i++){
this.getPing();
}
//Get each latency difference
var total1 = 0;
for (var i = 0; i < latencies.lenght; i++) {
if (typeof latencies[i] === 'number') {
console.log(latencies[i]);
total1 += latencies[i + 1] - latencies[i];
console.log(total1);
}
}
var jitter = total1 / (latencies.length - 1);
console.log(jitter); //this comes out as 0
latencies = [];
};
render() {
return (
...
<Button title="Scan" onPress={this.startScan} />
)
};
}
Thanks
Tim
The problem is that the XMLHttpRequest is asynchronous and will allow other code to run while it is trying to fetch the resource. The solution to this is to await each request and then move on to the next block.
I've switched the XMLHttpRequest for the Fetch API. fetch returns a Promise which you can await and wait for it to finish.
class App extends Component {
startScan = () => {
this.setState({
scanning: true,
});
this.getJitter().then(() => {
this.setState({
scanning: false,
});
});
}
getPing = async () => {
const startTime = new Date();
await fetch('http://dummy.restapiexample.com/api/v1/employees');
const endTime = new Date();
const ping = endTime.getTime() - startTime.getTime();
this.setState({ ping });
return ping;
}
getJitter = async () => {
const latencies = [];
for (let i = 0; i < 5; i++){
const ping = await this.getPing();
latencies.push(ping);
}
//Get each latency difference
let total1 = 0;
for (let i = 0; i < latencies.length; i++) {
if (typeof latencies[i] === 'number') {
console.log(latencies[i]);
total1 += latencies[i + 1] - latencies[i];
console.log(total1);
}
}
const jitter = total1 / (latencies.length - 1);
console.log(jitter); //this comes out as 0
};
render() {
return (
<Button title="Scan" onPress={this.startScan} />
)
}
}
Related
I have a discord bot taking every message on a specific channel (you can type only once on it).
For each message, I put the message on a spreadsheet.
To minimize google API calls on my spreadsheet, I've implemented this :
I'm checking how many users wrote per minute.
If 10 or less : I'm calling my updatesheet function = working perfectly.
If 11 or more : I'm delaying the call with a setInterval (I took care to delay not more than 10per minute in the future aswell) = not working
I get this error message :
message: 'Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential.
which I do not understand since I'm using the exact same updatesheet function :
async function update(placeId,authorId,adressId,pointsNumber,tokensWon) {
await doc.useServiceAccountAuth({
client_email: creds.client_email,
private_key: creds.private_key,
});
await doc.loadInfo(); // loads document properties and worksheets
let sheetdailyPoints = doc.sheetsByIndex[1];
var date = new Date();
const year = date.getFullYear()
const month = `${date.getMonth() + 1}`.padStart(2, "0")
const day = `${date.getDate()}`.padStart(2, "0")
const stringDate = [day, month, year].join("/")
const rowPointsAdded = await sheetdailyPoints.addRow({
Date: stringDate,
AuthorId: authorId,
Place: placeId,
Adress: adressId,
Points: pointsNumber
});
let sheetTokensXP = doc.sheetsByIndex[3];
const rows2 = await sheetTokensXP.getRows();
var addedTokensXP = false;
let = length = rows2.length;
for(let i = 0; i < length; i++){
if(rows2[i].Adress == adressId) {
if(rows2[i].Points!='')
rows2[i].Points = parseInt(rows2[i].Points)+parseInt(pointsNumber);
else
rows2[i].Points = parseInt(pointsNumber);
rows2[i].XP = parseInt(rows2[i].XP)+200;
rows2[i].Tokens = parseInt(rows2[i].Tokens)+parseInt(tokensWon);
await rows2[i].save();
addedTokensXP=true;
return rows2[i].Tokens;
}
}
if (addedTokensXP == false) {
const rowAdded3 = await sheetTokensXP.addRow({
Adress: adressId,
Points: pointsNumber,
Tokens: tokensWon,
XP: 200
});
await rowAdded3.save();
return tokensWon;
}
}
The main function:
const prevMap = new Map();
for (i=0; i<61; i++) {
prevMap.set(i,0);
}
async function updateSheets(message,currentMin,ladderNumber,placeId,authorId,adressId,pointsNumber,tokensWon) {
if(currentMin === prevMin) {
nbUpdateAtMin = prevMap.get(currentMin);
nbUpdateAtMin++;
if(nbUpdateAtMin>10) {
let nbMinAdded = 0;
let foundPlaceAtMin;
let foundPlace = false;
for (i=currentMin+1; foundPlace; i++) {
if (prevMap.get(i) < 11 ) {
foundPlaceAtMin = i;
foundPlace = true;
}
}
nbMinAdded = foundPlaceAtMin-currentMin;
setInterval(function() {riddle.update(placeId,authorId,adressId,pointsNumber,tokensWon)},nbMinAdded*60000);
let value = prevMap.get(currentMin+nbMinAdded);
prevMap.set(currentMin+nbMinAdded,value+1);
}
else {
let value = prevMap.get(currentMin);
prevMap.set(currentMin,value+1);
riddle.update(placeId,authorId,adressId,pointsNumber,tokensWon);
}
}
else {
prevMap.set(prevMin,0);
let value = prevMap.get(currentMin);
prevMap.set(currentMin,value+1);
prevMin = currentMin;
riddle.update(placeId,authorId,adressId,pointsNumber,tokensWon)
}
}
I'm attempting to make an API call using promises. The API is paginated and as such, depending on the headers in that first API call make more to get the rest of the results if need be.
Here's what I have so far:
const get = (url, pageNo) => {
var options = {
url: url,
headers: {
'Authorization': `Token token=${apiToken}`
},
json: true,
page: pageNo
};
return new Promise((resolve, reject) => {
request.get(options, (err, resp) => {
err ? reject(err) : resolve(resp);
})
});
};
Using get() to loop and get all responses:
const getAll = (plannerId, timestamp, range) => {
const plannerBookingsUrl = new URL(
`/api/planners/${plannerId}/bookings?since=${timestamp}&range=${range}`,
baseUrl
);
let response = get(plannerBookingsUrl, 1);
let bookings = [];
bookings.push(response);
response.then(results => {
let moreRequests = true;
let currentPage = 1;
const totalPages = parseInt(results.headers['x-total-pages']);
while (moreRequests) {
if (currentPage < totalPages) {
nextBatch = get(plannerBookingsUrl, currentPage + 1);
bookings.push(nextBatch);
currentPage++;
} else {
moreRequests = false;
}
}
});
return Promise.all(bookings);
};
Main() where I'm using getAll(...):
const main = () => {
const response = getAll(
'11716',
'2020-02-27',
'7'
);
response.then(results => {
console.log(results);
.catch(error => console.log(error))
};
main();
This returns the initial promise but not the remaining promises.
What I'm really have a problem with is reading the first API, making the remainder and returning them all together to be using in my main function.
Any help would be much appreciated!
Thanks.
You could put all your fetching logic inside the while loop. The way you get your bookings is the same, except for the first time where you need to get a little more information on the amount of pages.
Accomplish this by making your function async and check the first time of the loop if the totalPages value is already known. If it's not, await the response and get the info from the headers, and otherwise just push the response to the bookings array.
const getAll = async (plannerId, timestamp, range) => {
const plannerBookingsUrl = new URL(
`/api/planners/${plannerId}/bookings?since=${timestamp}&range=${range}`,
baseUrl
);
let bookings = [];
let currentPage = 1;
let totalPages = null;
while (totalPages === null || currentPage < totalPages) {
let response = get(plannerBookingsUrl, currentPage);
if (totalPages === null) {
let results = await response;
totalPages = parseInt(results.headers['x-total-pages']);
}
bookings.push(response);
currentPage++;
}
return Promise.all(bookings);
};
The problem is that you are returning Promise.all(bookings) outside response.then callback, so at this point bookings contains only the first call get(plannerBookingsUrl, 1).
Here is a possible solution using async:
const getAll = async (plannerId, timestamp, range) => {
const plannerBookingsUrl = new URL(
`/api/planners/${plannerId}/bookings?since=${timestamp}&range=${range}`,
baseUrl
);
let response = get(plannerBookingsUrl, 1);
let bookings = [];
bookings.push(response);
const results = await response; // wait for results here
let moreRequests = true;
let currentPage = 1;
const totalPages = parseInt(results.headers['x-total-pages']);
while (moreRequests) {
if (currentPage < totalPages) {
nextBatch = get(plannerBookingsUrl, currentPage + 1);
bookings.push(nextBatch);
currentPage++;
} else {
moreRequests = false;
}
}
return Promise.all(bookings); // bookings now contains every next batch
};
adapt on main() function:
const main = async () => {
const results = await getAll(
'11716',
'2020-02-27',
'7'
);
...
};
main();
I'm trying to write a code that makes a request to a website, for webscraping
So this are the steps:
Here First part of Code STARTS
The program makes the request to the mainURL
The program selects some objects from the html of the mainURL, and store them in an array of objects(advert), on of the properties of the object, is it's link, which we'll call numberURL, that the code automatically selects using a css selector, the amount of objects is something like 80-90;
The program makes requests to every numberURL(80-90 requests),
and for each of them it does set another properties to the same object, and selects another link, that we'll call accountURL
The program creates an CSV file where it writes every object in different rows
Here First part of Code ENDS
So actually the first part works pretty good, it doesn't have any issues, but the second part does
Here Second part of Code STARTS
The program makes requests to every accountURL from the previous object
The program selects some objects from the html of the accountURL, and stores them in an another array of another objects(account), also using CSS selectors
The program should console.log() all the account objects
Here Second part of Code ENDS
But the second part does have some bugs, because when console.logging the objects we see that the objects properties doesn't changed their default value.
So in debugging purposes I took one advert object and putted it's value manually from the code
post[0].link = 'https://999.md/ru/profile/denisserj'
Finally when running the code for this object it actually works correctly, so it shows the changed properties, but for the rest of them it doesn't.
I tried to set some Timeouts, thinking that the code tries to read the link, before the second request finished, but no effects
I also tried to console.log the link, to see if it exists in the array, so it actually exists there, but also no effect.
Finally here is the code:
// CLASSES
class advert {
constructor() {
this.id = 0;
this.tile = new String();
this.link = new String();
this.phone = new String();
this.account = new String();
this.accountLink = new String();
this.text = new String();
this.operator = new String();
}
show() {
console.log(this.id, this.title, this.link, this.phone, this.account, this.accountLink, this.text, this.operator);
}
}
class account {
constructor() {
this.name = 0;
this.createdAt = 0;
this.phone = [];
this.ads = [];
this.adsNumber = 0;
}
show() {
console.log(this.name, this.createdAt, this.phone, this.ads, this.adsNumber);
}
}
// HEADERS
const mainRequest = require('request');
const auxRequest = require('request');
const cheerio1 = require('cheerio');
const cheerio2 = require('cheerio');
const fs = require('fs');
const fs2 = require('fs');
const adFile = fs.createWriteStream('anunturi.csv');
const accFile = fs2.createWriteStream('conturi.csv');
// SETTINGS
const host = 'https://999.md'
const category = 'https://999.md/ru/list/transport/cars'
const timeLimit = 60; //seconds
// VARIABLES
let post = [];
let postNumber = 0;
let acc = [];
// FUNCTIONS
function deleteFromArray(j) {
post.splice(j, 1);
}
function number(i) {
let category = post[i].link;
auxRequest(category, (error, response, html) => {
if (!error && response.statusCode == 200) {
const $ = cheerio1.load(html);
let phone;
const siteTitle = $('strong').each((id, el) => {
phone = $(el).text();
});
const txt = $('.adPage__content__description').html();
const person = $('.adPage__header__stats').find('.adPage__header__stats__owner').text();
const linkToPerson = host + $('.adPage__header__stats').find('.adPage__header__stats__owner').find('a').attr('href');
post[i].phone = phone;
post[i].account = person;
post[i].accountLink = linkToPerson;
post[i].text = txt;
if (i == postNumber) {
console.log('1. Number Putting done')
writeToFileAd(accountPutter, writeToFileAccount);
}
}
});
}
function writeToFileAd() {
adFile.write('ID, Titlu, Link, Text, Cont, LinkCont, Operator\n')
for (let i = 0; i <= postNumber; i++) {
adFile.write(`${post[i].id}, ${post[i].title}, ${post[i].link}, ${post[i].phone}, ${post[i].account}, ${post[i].accountLink}, ${post[i].operator}\n`);
}
console.log('2. Write To File Ad done')
accountPutter();
}
function accountAnalyzis(i) {
let category = post[i].link;
const mainRequest = require('request');
category = category.replace('/ru/', '/ro/');
mainRequest(category, (error, response, html) => {
if (!error && response.statusCode == 200) {
const $ = cheerio2.load(html);
const name = $('.user-profile__sidebar-info__main-wrapper').find('.login-wrapper').text();
let createdAt = $('.date-registration').text();
createdAt = createdAt.replace('Pe site din ', '');
const phones = $('.user-profile__info__data').find('dd').each((id, el) => {
let phone = $(el).text();
acc[i].phone.push(phone);
});
const ads = $('.profile-ads-list-photo-item-title').find('a').each((id, el) => {
let ad = host + $(el).attr('href');
acc[i].ads.push(ad);
acc[i].adsNumber++;
});
acc[i].name = name;
acc[i].createdAt = createdAt;
console.log(name)
if (i == postNumber) {
console.log('3. Account Putting done')
writeToFileAccount();
}
}
});
}
function writeToFileAccount() {
for (let i = 0; i <= postNumber; i++) {
accFile.write(`${acc[i].name}, ${acc[i].createdAt}, ${acc[i].phone}, ${acc[i].ads}, ${acc[i].adsNumber}\n`);
}
console.log('4. Write to file Account done');
}
function numberPutter() {
for (let i = 0; i <= postNumber; i++) {
number(i);
}
}
function accountPutter() {
for (let i = 0; i <= postNumber; i++) {
accountAnalyzis(i);
}
}
// MAIN
mainRequest(category, (error, response, html) => {
let links = [];
for (let i = 0; i < 1000; i++) {
post[i] = new advert();
}
for (let i = 0; i < 1000; i++) {
acc[i] = new account();
}
if (!error && response.statusCode == 200) {
const $ = cheerio2.load(html);
const siteTitle = $('.ads-list-photo-item-title').each((id, el) => {
const ref = host + $(el).children().attr('href');
const title = $(el).text();
post[id].id = id + 1;
post[id].title = title;
post[id].link = ref;
links[id] = ref;
postNumber = id;
});
post[0].link = 'https://999.md/ru/profile/denisserj'
numberPutter()
}
});
You have an error in line
const siteTitle = $('.ads-list-photo-item-title').each((id, el) => {
What you actually want is .find('a').each...
I have an event that fires every time a packet is received from a bluetooth device. The packet comes in as a JSON array and always contains 10 objects similar to the ones below.
var s1_data = [{"record":0,"sensor":1,"timestamp":26566,"date":{"day":7,"hour":10,"minute":45,"month":5,"second":38,"year":18}},
{"record":1,"sensor":1,"timestamp":26567,"date":{"day":7,"hour":10,"minute":45,"month":5,"second":38,"year":18}},
{"record":2,"sensor":1,"timestamp":26568,"date":{"day":7,"hour":10,"minute":45,"month":5,"second":38,"year":18}},
{"record":3,"sensor":1,"timestamp":26569,"date":{"day":7,"hour":10,"minute":45,"month":5,"second":38,"year":18}},
{"record":4,"sensor":1,"timestamp":26570,"date":{"day":7,"hour":10,"minute":45,"month":5,"second":38,"year":18}},
{"record":5,"sensor":1,"timestamp":26571,"date":{"day":7,"hour":10,"minute":45,"month":5,"second":38,"year":18}},
{"record":6,"sensor":1,"timestamp":26572,"date":{"day":7,"hour":10,"minute":45,"month":5,"second":38,"year":18}},
{"record":7,"sensor":1,"timestamp":26573,"date":{"day":7,"hour":10,"minute":45,"month":5,"second":38,"year":18}},
{"record":8,"sensor":1,"timestamp":26574,"date":{"day":7,"hour":10,"minute":45,"month":5,"second":38,"year":18}},
{"record":9,"sensor":1,"timestamp":26575,"date":{"day":7,"hour":10,"minute":45,"month":5,"second":38,"year":18}}]
I need to push each individual object into a node.js stream that is being consumed by another stream.
Can anyone give an example on how I can push these to a Readable object stream on an ongoing basis (or do I need to use a PassThrough stream)? I can’t seem to get my head around how to do this!
Edited to add sample code below. chunk.toString() fails as chunk is undefined
var Readable = require('stream').Readable;
var util = require('util');
var through2 = require('through2');
var s1 = require('./sensor1.js');
var s2 = require('./sensor2.js');
var minLength = s1.length;
//console.log(s1);
var s1stream = new Readable({ objectMode: true });
var s2stream = new Readable({ objectMode: true });
s1stream._read = function () {
this.push();
};
s2stream._read = function () {
this.push();
};
if (s2.length < minLength){
minLength = s2.length;
}
var n1 = 0;
setInterval(function() {
if (n1++ < minLength) {
console.log(s1[n1].record);
s1stream.push(s1[n1]);
} else if (n1++ === minLength) {
s1stream.push(null);
}
}, 1000);
var n2 = 0;
setInterval(function() {
if (n2++ < minLength) {
s2stream.push(s2[n2]);
} else if (n2++ === minLength) {
s2stream.push(null);
}
}, 1000);
s1stream.pipe(through2.obj(function (chunk, enc, callback) {
this.push(chunk.toString())
callback()
})).pipe(process.stdout);
Edit below shows working code. Looks like it was to do with the way I was creating the read functions
var Readable = require('stream').Readable;
var util = require('util');
var through2 = require('through2');
var Transform = require('stream').Transform;
var s1 = require('./sensor1.js');
var s2 = require('./sensor2.js');
var minLength = s1.length;
//console.log(s1);
var s1stream = new Readable({
objectMode: true,
read() {}
})
const s2stream = new Readable({
objectMode: true,
read() {}
})
if (s2.length < minLength){
minLength = s2.length;
}
var n1 = 0;
setInterval(function() {
if (n1 < minLength) {
s1stream.push(s1[n1]);
n1++;
} else if (n1 == minLength) {
s1stream.push(null);
}
}, 1000);
var n2 = 0;
setInterval(function() {
if (n2++ < minLength) {
s2stream.push(s2[n2]);
} else if (n2++ === minLength) {
s2stream.push(null);
}
}, 1000);
var jsonStream = through2.obj(function(file, encoding, cb) {
this.push(file.record.toString())
cb()
})
s1stream.pipe(jsonStream).pipe(process.stdout);
You will need to implement a Readable stream that "wraps" your bluetooth source. When the packet received event is fired you'll loop through your array of objects and call your Readable stream's push method, passing in each object. A somewhat similar example of this can be seen here
Note that since you'll be sending actual JSON objects you'll want to enable the objectMode option when you write your implementation as described here
I'm writing little snippets to learn more about using Javascript with API's, and have stumbled onto another problem I can't figure out on my own. I have a global variable (object?) "coins", read in from the API, and its' data field "symbol". I can use "symbol" to reference the data held there, in part of my code, without any errors. Later in the code, I use it again, and I get an error about it being undefined, despite the fact that the values returned from using it, are both defined, and, what I expected. While we are at it, maybe someone can tell me why I assign values to global variables (declared outside of all of the functions), but the variables when called, are "undefined". To see it in action, visit www.mattox.space/XCR and open up dev tools.
/*
FLOW:
get ALL coins, store NAME and SYMBOL into an object.
loop over the names object comparing to $SYMBOL text from form, return the NAME when found.
hit the API again, with the $NAME added to the URL.
create a table row.
insert data from second API hit, into table row
SOMEWHERE in there, do the USD conversion from BTC.
*/
//var name = getName();
var bitcoinValue = 0;
var coins = new Array;
var form = ""; // Value pulled from the form
var symbol = ""; // "id" on the table
var id = ""; // value pulled from the table at coins[i].id matched to coins[i].symbol
var formSym = "";
var formUSD = 0;
var formBTC = 0;
var form24h = 0;
function run() {
getFormData();
allTheCoins("https://api.coinmarketcap.com/v1/ticker/");
testGlobal();
}
function testGlobal() {
console.log("These are hopefully the values of the global variables");
console.log(formSym + " testGlobal");
console.log(formUSD + " testGlobal");
console.log(formBTC + " testGlobal");
console.log(form24h + " testGlobal");
}
function getFormData(){ //This function works GREAT!
form = document.getElementById("symbol").value //THIS WORKS
form = form.toUpperCase(); //THIS WORKS
}
function allTheCoins(URL) {
var tickerRequest = new XMLHttpRequest();
tickerRequest.open('GET', URL);
tickerRequest.send();
tickerRequest.onload = function() {
if (tickerRequest.status >= 200 && tickerRequest.status < 400) {
var input = JSON.parse(tickerRequest.responseText);
for(var i in input)
coins.push(input[i]);
testFunction(coins);
}
else {
console.log("We connected to the server, but it returned an error.");
}
console.log(formSym + " allTheCoins!"); // NOPE NOPE NOPE
console.log(formUSD) + " allTheCoins!"; // NOPE NOPE NOPE
console.log(formBTC + " allTheCoins!"); // NOPE NOPE NOPE
console.log(form24h + " allTheCoins!"); // NOPE NOPE NOPE
}
}
function testFunction(coins) {
for (var i = 0; i < coins.length; i++) {
if (coins[i].symbol == form) { // But right here, I get an error.
formSym = coins[i].name;
formUSD = coins[i].price_usd;
formBTC = coins[i].price_btc;
form24h = coins[i].percent_change_24h;
console.log(formSym + " testFunction");
console.log(formUSD + " testFunction");
console.log(formBTC + " testFunction");
console.log(form24h + " testFunction");
//DO EVERYTHING RIGHT HERE! On second thought, no, this needs fixed.
}
else if (i > coins.length) {
formSym = "Error";
formUSD = 0;
formBTC = 0;
form24h = 0;
}
}
}
/*
if (24h >= 0) {
colorRED
}
else {
colorGreen
}
*/
here is a possible way of doing it that you can get inspired by. its based on a httpRequest promise that set the headers and method.
let allTheCoins = obj => {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open(obj.method || obj.method, obj.url);
if (obj.headers) {
Object.keys(obj.headers).forEach(key => {
xhr.setRequestHeader(key, obj.headers[key]);
});
}
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response);
} else {
reject(xhr.statusText);
}
};
xhr.onerror = () => reject(xhr.statusText);
xhr.send(obj.body);
});
};
allTheCoins({
url: "https://api.coinmarketcap.com/v1/ticker/",
method: "GET",
headers: {"Accept-Encoding": "gzip"}
})
.then(data => {
ParseCoins(data);
})
.catch(error => {
console.log("We connected to the server, but it returned an error.");
});
function ParseCoins(data) {
const coins = JSON.parse(data);
const form = getFormVal();/*retrieve form val*/
const id = getTableId(); /*retrieve table id*/
const bitcoinValue = getBitcoinVal();/*retrieve bitcoin Value*/
const final_result = [];
for (let i = 0, len = coins[0].length; i < len; i++) {
const coin = coins[0][i];
for (let ii in coin) {
if (coin.hasOwnProperty(ii)) {
if (coin[ii].symbol == form) {
let element = {
formSym: coin[ii].name,
formUSD: coin[ii].price_usd,
formBTC: coin[ii].price_btc,
form24h: coin[ii].percent_change_24h
};
final_result.push(element);
}
}
}
}
coontinueElseWhere(final_result);
}