Asynchronous test function - javascript

I'm trying to create a function to testing asynchronous code, but I'm kind of lost, I want the TEST_F and TEST function below also work with asynchronous code, such as loading the image for example.
const CHECK = (actual, expected) => {
return (actual === expected);
};
const TEST = (name, ...testFunctions) => {
console.log(name+':');
for (let test of testFunctions)
console.log(test);
};
const TEST_F = (name, f) => {
const tStart = performance.now();
const check = f();
const tEnd = performance.now();
const duration = tEnd - tStart;
const details = name + ': ' + '(' + duration + ') = ' + check;
return details;
};
const imageDownload = (path, successCallback) => {
let img = new Image();
img.addEventListener("load", successCallback, false);
img.src = path;
return img;
};
TEST("TestImage",
TEST_F("testImageDownload", () => {
let spyCountSuccess = 0;
const expectedCountSuccess = spyCountSuccess + 1;
const successCallback = () => {
spyCountSuccess++;
};
const pathImage = 'https://i.imgur.com/Wutekcp.jpg';
imageDownload(pathImage, successCallback);
const actualCountSuccess = spyCountSuccess;
return CHECK(actualCountSuccess, expectedCountSuccess);
})
);
With the code above I will always i get false, even if the image is loaded, because I am not dealing right with the concept of asynchronous, I would like to understand how to adapt the code thus to also test ascincrono code.

I was able to test the asynchronous code after some tests. I do not know if I'll keep it that way, but it's working, I'll try to study these lines and see what I can improve:
const CHECK = (actual, expected) => {
return (actual === expected);
};
const TEST = (name, ...testFunctions) => {
console.log(name+':');
for (let test of testFunctions)
if(test === undefined)
continue;
else
console.log(test);
};
const TEST_F = (name, f) => {
const tStart = performance.now();
const check = f();
const tEnd = performance.now();
const duration = tEnd - tStart;
const details = name + ': ' + '(' + duration + ') = ' + check;
return details;
};
const TEST_F_ASYNC = (name, f) => {
const tStart = performance.now();
f((check) => {
const tEnd = performance.now();
const duration = tEnd - tStart;
const details = name + ': ' + '(' + duration + ') = ' + check;
console.log(details);
});
};
const imageDownload = (path, successCallback) => {
let img = new Image();
img.addEventListener("load", successCallback, false);
img.src = path;
return img;
};
TEST("TestImage",
TEST_F_ASYNC("testAsync", (done) => {
let spyCountSuccess = 0;
const expectedCountSuccess = spyCountSuccess + 1;
const successCallback = () => {
spyCountSuccess++;
const actualCountSuccess = spyCountSuccess;
const result = CHECK(actualCountSuccess, expectedCountSuccess)
done(result);
};
const pathImage = 'https://i.imgur.com/Wutekcp.jpg';
imageDownload(pathImage, successCallback);
}),
TEST_F('testSync', () => {
return CHECK(1, 1);
})
);

Related

Foreach for array

I have an array which I populate like so
var list = [];
featureLayer.queryFeatures(querySnTR)
.then((result) => {
result.attachmentInfos.forEach((x) => {
list.push(uriString + "/" + x.id);
});
});
console.log("list", list);
I print out the list with console.log and it returns values inside.
Afterwards I do a foreach to go through all the elements inside and create a div for each of them. The thing is, it doesn't even go in the foreach function.
list.forEach((x) => {
console.log("CL", list);
console.log("x element", x);
var image = document.createElement("img");
image.src = x;
image.className = "queryImg";
document.getElementById("queryResults").appendChild(image);
});
It doesn't print out CL or x element for that matter.
Any ideas as to why?
The whole original code, for reference
startup: function () {
var _that = this;
_this = _that;
this.map.on("click", function (e) {
_this.map.graphics.clear();
identifyTask = new IdentifyTask("https://server/arcgis/rest/services/MUNICIPALITY_BUNDLE/ZK_KATASTAR_NA_ZELENILO/MapServer");
identifyParams = new IdentifyParameters();
identifyParams.tolerance = 10;
identifyParams.returnGeometry = true;
identifyParams.layerIds = [1];
identifyParams.layerOption = IdentifyParameters.LAYER_OPTION_ALL;
identifyParams.width = _this.map.width;
identifyParams.height = _this.map.height;
identifyParams.spatialReference = _this.map.spatialReference;
identifyParams.geometry = e.mapPoint;
identifyParams.mapExtent = _this.map.extent;
identifyTask.execute(identifyParams).then(function (data) {
objId = data[0].feature.attributes.objectid;
const querySnTR = {
where: "1 = 1",
outFields: ["*"]
};
var uriString = "https://server/arcgis/rest/services/MUNICIPALITY_BUNDLE/ZK_KATASTAR_NA_ZELENILO/MapServer/101/" + objId + "/attachments";
var featureLayer = new esri.layers.FeatureLayer(uriString);
featureLayer.queryFeatures(querySnTR)
.then((result) => {
result.attachmentInfos.forEach((x) => {
list.push(uriString + "/" + x.id);
});
});
const myFunction = async () => {
const { attachmentInfos } = await featureLayer.queryFeatures(querySnTR);
const list = attachmentInfos.map(({ id }) => `${uriString}/${id}`);
console.log("list", list);
list.forEach((x) => {
var image = document.createElement("img");
image.src = x;
image.className = "queryImg";
document.getElementById("queryResults").appendChild(image);
});
};
});
});
}
That's a trick on how the console works.
When you are executing the log the list is empty (100% sure) because you are populating it asynchronously. But the console has the reference to it and it will print it afterwards.
That's why your list is empty. You need to handle asynchrony here. You could work with an async/await approach or using promises, that will depend on the rest of your code, this is an example of how to do it with an async function (and rewritted it to modern javascript):
const myFunction = async () => {
const {attachmentInfos} = await featureLayer.queryFeatures(querySnTR);
const list = attachmentInfos.map(({id}) => `${uriString}/${id}`);
console.log("list", list);
list.forEach((x) => {
// put your code here
});
};
Edited:
Now that you share all your code you can simply do:
featureLayer.queryFeatures(querySnTR)
.then((result) => {
result.attachmentInfos.forEach((attachmentInfo) => {
var x = uriString + "/" + attachmentInfo.id
var image = document.createElement("img");
image.src = x;
image.className = "queryImg";
document.getElementById("queryResults").appendChild(image);
});
});
I would recommend you also to give vars meaningful names, not x but attachmentInfo, etc...

How can I get the data from an api request from the then() method, so I can process the data outside of the function?

How can I get the data from an api request from the then() method, so I can process the data outside
of the function. Can I store the data in a state object for example and how to do that.
// openweathermap async await api request
async function getData(){
try{
const url = `http://api.openweathermap.org/data/2.5/forecast?
q=${city}&units=metric&appid=${key}`;
const data = await axios(url)
console.log(data)
return data;
}catch(error){
temperature.insertAdjacentHTML('afterend', '<div id="error">Oooops
something went wrong!</div>');
}
}
getData().then( data => {
const temp = data.data.list[0].main.temp;
temperature.textContent = temp.toFixed(1) + ' \xB0' + "C ";
const temp2 = data.data.list[1].main.temp;
temperature2.textContent = temp2.toFixed(1) + ' \xB0' + "C ";
const forecast = data.data.list[0].weather[0].description;
foreCast.textContent = forecast.toLowerCase();
const forecast2 = data.data.list[1].weather[0].description;
foreCast2.textContent = forecast2.toLowerCase();
const icon = data.data.list[0].weather[0].icon
weatherIcon.insertAdjacentHTML('afterbegin', `<img
src="http://openweathermap.org/img/w/${icon}.png">`)
const icon2 = data.data.list[1].weather[0].icon
weatherIcon2.insertAdjacentHTML('afterbegin', `<img
src="http://openweathermap.org/img/w/${icon2}.png">`)
day.textContent = newTime;
day2.textContent = newTime2;
})
Should axios(url) be axios.get(url)?
Then you can handle the data inside the callback function:
getData().then(data => console.log(data))
Get data is already an async function which means it returns a Promise. Just assign variable data by calling getData function. This should be done in an async function.
(async () => {
const data = await getData();
const temp = data.data.list[0].main.temp;
temperature.textContent = temp.toFixed(1) + ' \xB0' + "C ";
const temp2 = data.data.list[1].main.temp;
temperature2.textContent = temp2.toFixed(1) + ' \xB0' + "C ";
const forecast = data.data.list[0].weather[0].description;
foreCast.textContent = forecast.toLowerCase();
const forecast2 = data.data.list[1].weather[0].description;
foreCast2.textContent = forecast2.toLowerCase();
const icon = data.data.list[0].weather[0].icon
weatherIcon.insertAdjacentHTML('afterbegin', `<img src="http://openweathermap.org/img/w/${icon}.png">`)
const icon2 = data.data.list[1].weather[0].icon
weatherIcon2.insertAdjacentHTML('afterbegin', `<img src="http://openweathermap.org/img/w/${icon2}.png">`)
day.textContent = newTime;
day2.textContent = newTime2;
})();
Found a solution: Create a class with the getData() method, create a function to control the data and store it in the state object.
// Create class
class Weather {
constructor(){
}
async getData(){
try{
const url = `http://api.openweathermap.org/data/2.5/forecast?
q=${city}&units=metric&appid=${key}`;
const data = await axios(url)
this.data = data
}catch(error){
temperature.insertAdjacentHTML('afterend', '<div id="error">Oooops something
went wrong!</div>');
}
}
}
// Create state object, declare function to get data and store data in state object
const state = {}
const controlData = async () => {
state.data = new Weather()
await state.data.getData()
const temp = state.data.data.data.list[0].main.temp;
temperature.textContent = temp.toFixed(1) + ' \xB0' + "C ";
const temp2 = state.data.data.data.list[1].main.temp;
temperature2.textContent = temp2.toFixed(1) + ' \xB0' + "C ";
const forecast = state.data.data.data.list[0].weather[0].description;
foreCast.textContent = forecast.toLowerCase();
const forecast2 = state.data.data.data.list[1].weather[0].description;
foreCast2.textContent = forecast2.toLowerCase();
const icon = state.data.data.data.list[0].weather[0].icon
weatherIcon.insertAdjacentHTML('afterbegin', `<img
src="http://openweathermap.org/img/w/${icon}.png">`)
const icon2 = state.data.data.data.list[1].weather[0].icon
weatherIcon2.insertAdjacentHTML('afterbegin', `<img
src="http://openweathermap.org/img/w/${icon2}.png">`)
day.textContent = newTime;
day2.textContent = newTime2;
let sRise = convertTime(state.data.data.data.city.sunrise);
let sSet = convertTime(state.data.data.data.city.sunset);
sunRise.textContent = `Sunrise ${sRise}`;
sunSet.textContent = `Sunset ${sSet}`;
}
controlData()

cant pass data from textbox inside a loop

so im getting my data from Darksky api, i have elements generated with loops, and i update the text content of those via loop of the api data array. whenever i search, everthing else static changes values, not the one inside the loop
function search(ele) {
if(event.key === 'Enter') {
var url3 = 'https://geocode.xyz/' + ele.value +'?json=1' //this is where i convert the long,lat to city name
fetch(url3)
.then(z => z.json())
.then(z => {
locres = (z.latt+','+z.longt)
render()
renderLoop()
})
}
}
function renderLoop(){
var proxyUrl = 'https://cors-anywhere.herokuapp.com/';
var url1 = 'https://api.darksky.net/forecast/c34e122a56ae30a3090687878bce72c3/' + locres + '?units=auto' //i have to use proxy because of CORS
fetch(proxyUrl + url1)
.then(x => x.json())
.then(x => {
var skycons = new Skycons({"color": "white"});
skycons.set("icon0", Skycons = x.currently.icon);
skycons.play();
console.log(x.daily.data)
for(i=0;i<8;i++){
console.log(x.daily.data[i].time)
console.log(x.daily.data[i].summary)
const divs = document.createElement('div')
divs.className = ('week-day-container')
const divsholdr = document.querySelector('.week-stage')
const canv = document.createElement('canvas')
canv.id = ('icons'+(i+1))
canv.height = 100
canv.width = 70
divs.appendChild(canv)
divsholdr.appendChild(divs)
const dates = document.createElement('p')
dates.textContent = x.daily.data[i].time
divs.appendChild(dates)
const temp = document.createElement('p')
temp.textContent = 'High: '+ x.daily.data[i].temperatureHigh + 'Low: ' + x.daily.data[i].temperatureLow
divs.appendChild(temp)
const summ = document.createElement('p')
summ.textContent = x.daily.data[i].summary
divs.appendChild(summ)
}
for(y=0;y<8;y++){
skycons.set('icons'+(y+1), Skycons = x.daily.data[y].icon)
}
})
}

How to handle axios.all request fails

How can I handle request fails in this example of axios.all requests. I.e. if all servers are responde with JSON all is okay and I have JSON file at end of a cycle. But if one of this servers not responde with JSON or not responde at all I do have nothing in "/data.json" file, even all other servers are working perfectly. How can I catch a server fail and skip it?
var fs = require("fs");
var axios = require('axios');
var util = require('util');
var round = 0;
var tmp = {};
var streem = fs.createWriteStream(__dirname + '/data.json', {flags : 'w'});
toFile = function(d) { //
streem.write(util.format(d));
};
start();
setInterval(start, 27000);
function start(){
streem = fs.createWriteStream(__dirname + '/data.json', {flags : 'w'});
monitor();
}
function monitor(){
axios.all([
axios.get('server1:api'),
axios.get('server2:api'),
axios.get('server3:api'),
axios.get('server4:api'),
]).then(axios.spread((response1, response2, response3, response4) => {
tmp.servers = {};
tmp.servers.server1 = {};
tmp.servers.server1 = response1.data;
tmp.servers.server2 = {};
tmp.servers.server2 = response2.data;
tmp.servers.server3 = {};
tmp.servers.server3 = response3.data;
tmp.servers.server4 = {};
tmp.servers.server4 = response4.data;
toFile(JSON.stringify(tmp));
round++;
streem.end();
streem.on('finish', () => {
console.error('Round: ' + round);
});
})).catch(error => {
console.log(error);
});
}
The most standard way to approach this would be a recursive function like below.
let promises = [
axios.get('server1:api'),
axios.get('server2:api'),
axios.get('server3:api'),
axios.get('server4:api'),
];
async function monitor() {
const responses = (arguments.length === 1 ? [arguments[0]] : Array.apply(null, arguments))[0];
const nextPromise = promises.shift();
if (nextPromise) {
try {
const response = await getSentenceFragment(offset);
responses.push(response);
}
catch (error) {
responses.push({});
}
return responses.concat(await monitor(responses));
} else {
return responses;
}
}
monitor([]).then(([response1, response2, response3, response4]) => {
tmp.servers = {};
tmp.servers.server1 = {};
tmp.servers.server1 = response1.data;
tmp.servers.server2 = {};
tmp.servers.server2 = response2.data;
tmp.servers.server3 = {};
tmp.servers.server3 = response3.data;
tmp.servers.server4 = {};
tmp.servers.server4 = response4.data;
toFile(JSON.stringify(tmp));
round++;
streem.end();
streem.on('finish', () => {
console.error('Round: ' + round);
});
});

I would like to analyze the image with tensorflw.js - nodejs

mobilenet.js
var loadFrozenModel = require('#tensorflow/tfjs-converter');
var NamedTensorMap = require('#tensorflow/tfjs-converter');
var tfc = require('#tensorflow/tfjs-core');
var IMAGENET_CLASSES = require('./imagenet_classes');
const GOOGLE_CLOUD_STORAGE_DIR = 'https://storage.googleapis.com/tfjs-models/savedmodel/';
const MODEL_FILE_URL = 'mobilenet_v1_1.0_224/optimized_model.pb';
const WEIGHT_MANIFEST_FILE_URL = 'mobilenet_v1_1.0_224/weights_manifest.json';
const INPUT_NODE_NAME = 'input';
const OUTPUT_NODE_NAME = 'MobilenetV1/Predictions/Reshape_1';
const PREPROCESS_DIVISOR = tfc.scalar(255 / 2);
class MobileNet {
constructor() {}
async load() {
this.model = await loadFrozenModel(
GOOGLE_CLOUD_STORAGE_DIR + MODEL_FILE_URL,
GOOGLE_CLOUD_STORAGE_DIR + WEIGHT_MANIFEST_FILE_URL);
}
dispose() {
if (this.model) {
this.model.dispose();
}
}
predict(input) {
const preprocessedInput = tfc.div(
tfc.sub(input.asType('float32'), PREPROCESS_DIVISOR),
PREPROCESS_DIVISOR);
const reshapedInput =
preprocessedInput.reshape([1, ...preprocessedInput.shape]);
const dict = {};
dict[INPUT_NODE_NAME] = reshapedInput;
return this.model.execute(dict, OUTPUT_NODE_NAME);
}
getTopKClasses(predictions, topK) {
const values = predictions.dataSync();
predictions.dispose();
let predictionList = [];
for (let i = 0; i < values.length; i++) {
predictionList.push({value: values[i], index: i});
}
predictionList = predictionList
.sort((a, b) => {
return b.value - a.value;
})
.slice(0, topK);
return predictionList.map(x => {
return {label: IMAGENET_CLASSES[x.index], value: x.value};
});
}
}
module.exports = MobileNet;
test.js
var tfc = require('#tensorflow/tfjs-core');
var MobileNet = require('./mobilenet');
var fs = require('fs');
var image = require('get-image-data')
var i = 0;
var meta;
image('./cat.jpg', function(err, getImageData){
if(err) throw err;
console.log('start to image data ');
console.log(i++);
console.log("meta : " + getImageData.data.length);
console.log("getImageData :"+getImageData);
const mobileNet = new MobileNet();
console.time('Loading of model');
// await mobileNet.load();
console.timeEnd('Loading of model');
console.log("maybee this is error on the data type");
const pixels = tfc.fromPixels(image);
console.time('First prediction');
let result = mobileNet.predict(pixels);
const topK = mobileNet.getTopKClasses(result, 5);
console.timeEnd('First prediction');
resultElement.innerText = '';
topK.forEach(x => {
resultElement.innerText += `${x.value.toFixed(3)}: ${x.label}\n`;
});
console.time('Subsequent predictions');
result = mobileNet.predict(pixels);
mobileNet.getTopKClasses(result, 5);
console.timeEnd('Subsequent predictions');
mobileNet.dispose();
});
I want to analyze the image using the tensorflow.js.
But it doesn't work.
ReferenceError: ImageData is not defined
at MathBackendCPU.fromPixels (/Users/leeyongmin/Documents/tfjs-converter-master-2/demo/node_modules/#tensorflow/tfjs-core/dist/kernels/backend_cpu.js:75:31)
at Engine.fromPixels (/Users/leeyongmin/Documents/tfjs-converter-master-2/demo/node_modules/#tensorflow/tfjs-core/dist/engine.js:292:29)
at ArrayOps.fromPixels (/Users/leeyongmin/Documents/tfjs-converter-master-2/demo/node_modules/#tensorflow/tfjs-core/dist/ops/array_ops.js:195:41)
at /Users/leeyongmin/Documents/tfjs-converter-master-2/demo/node_modules/#tensorflow/tfjs-core/dist/ops/operation.js:11:61
at Object.Tracking.tidy (/Users/leeyongmin/Documents/tfjs-converter-master-2/demo/node_modules/#tensorflow/tfjs-core/dist/tracking.js:36:22)
at Object.descriptor.value [as fromPixels] (/Users/leeyongmin/Documents/tfjs-converter-master-2/demo/node_modules/#tensorflow/tfjs-core/dist/ops/operation.js:11:26)
at /Users/leeyongmin/Documents/tfjs-converter-master-2/demo/test.js:26:22
at /Users/leeyongmin/Documents/tfjs-converter-master-2/demo/node_modules/get-image-data/index.js:18:7
at load (/Users/leeyongmin/Documents/tfjs-converter-master-2/demo/node_modules/get-image/server.js:18:5)
at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:511:3)

Categories

Resources