Awat doesn't wait for async - javascript

I'm new to async and await, I have a simple web app with firebase which gets files through input fields and upload them to the firebase via a button click but when I click button it does,t wait for async function to uload the files at first click. But when I click second time the files uploaded and I got the expected output. How can I solve this?
Here are my codes
Upload Function
async function uploadImages() {
var storageRef = firebase.storage().ref();
var uploadImages = document.getElementsByName("fupload").forEach((element) => {
var imageRef = storageRef.child(
"projects/" + projectName + "/" + (element as HTMLInputElement).files[0].name
);
let file = (element as HTMLInputElement).files[0];
imageRef.put(file).then((snapshot) => {
snapshot.ref.getDownloadURL().then(function (downloadURL) {
paragraphUrl.push(downloadURL);
});
});
});
if (document.getElementsByName("fupload").length == paragraphUrl.length) {
return paragraphUrl;
} else {
return 1;
}
}
Button click function
async function upload(){
await uploadImages().then((data) => {
if (data != 1) {
paragraphData = paragraphData.map(
function (x, i) {
return {
Title: x.Title,
Paragraph: x.Paragraph,
Image: data[i],
};
}.bind(this)
);
console.log(paragraphData);
//dispatch("paragraphData",{data})
} else {
console.log("d");
}
});
}

Thank you all I fixed the problem I'll add my code below.
Upload function
async function uploadImages() {
var storageRef = firebase.storage().ref();
for (const file of document.getElementsByName("fupload")) {
// let test = (file as HTMLInputElement).files[0].name;
// console.log(test);
var imageRef = storageRef.child(
"projects/" + projectName + "/" + (file as HTMLInputElement).files[0].name
);
let test = (file as HTMLInputElement).files[0].name;
let testFile = (file as HTMLInputElement).files[0];
await imageRef.put(testFile).then((snapshot) => {
snapshot.ref.getDownloadURL().then(function (downloadURL) {
paragraphUrl.push(downloadURL);
});
});
}
return paragraphUrl;
}
Button Click function
async function submitParagraphData() {
paragraphTitles = [];
paragraphs = [];
var e = document.getElementsByName("ParagrphTitle").forEach((element) => {
paragraphTitles.push((element as HTMLInputElement).value);
});
var f = document.getElementsByName("Paragraph").forEach((element) => {
paragraphs.push((element as HTMLInputElement).value);
});
let paragraphData = paragraphTitles.map(
function (x, i) {
return { Title: x, Paragraph: paragraphs[i] };
}.bind(this)
);
await uploadImages().then((data) => {
console.log(data);
});
}
The problem I had was when I click the button it displayed an empty array because file upload takes some time but when I click second time it displays the expected output because file was uploaded. So I added await to the line
imageRef.put(testFile) ............
So it fixed my problem.Thank you all for the support.

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...

Trouble applying the logic of grabbing links from next pages within my current implementation

I've created a script in node to scrape the links of different posts from a webpage. The script seems to be working in the right way. Now, I wish to capture the links of different posts from next pages also.
As I'm new to write code in node, I just don't find any idea how I can apply the logic of grabbing links from next pages within my current implementation.
const request = require('request');
const cheerio = require('cheerio');
const link = 'https://stackoverflow.com/questions/tagged/web-scraping';
const items = [];
let getLinks = () => {
return new Promise((resolve, reject) => {
request(link, function(error, response, html) {
let $ = cheerio.load(html);
if (error) return reject(error);
try {
$('.summary > h3 > a.question-hyperlink').each(function() {
items.push(base_link + $(this).attr("href"));
});
resolve(items);
} catch (e) {
reject(e);
}
});
});
};
getLinks().then(resultList => {
var i;
for (i = 0; i < resultList.length; i++) {
console.log(resultList[i]);
}
})
Something like this?
const request = require('request');
const cheerio = require('cheerio');
const base_url = 'https://stackoverflow.com';
let requestURL = 'https://stackoverflow.com/questions/tagged/web-scraping';
let pageLimit = 5;
(async function main() {
while (pageLimit-- && requestURL) {
console.log(`----- current: ${requestURL}, remains: ${pageLimit}`);
const result = await getLinks(requestURL);
for (const link of result.links) {
console.log(link);
}
requestURL = result.nextPageURL;
}
})().catch(console.error);
function getLinks(link) {
return new Promise((resolve, reject) => {
request(link, function(error, response, html) {
if (error) return reject(error);
let $ = cheerio.load(html);
const links = [];
try {
$('.summary > h3 > a.question-hyperlink').each(function() {
links.push(base_url + $(this).attr('href'));
});
const nextPageURL = base_url + $('a[rel="next"]').attr('href');
resolve({ links, nextPageURL });
} catch (e) {
reject(e);
}
});
});
};

Why Blob.getDataAsString return string with zero length?

One and the same json file. The same code. The random result. One time non-zero length, another time zero length. What happens?
Especially often the error appears when running on a trigger. For example, once a minute. When running from the editor, almost never.
The code worked without errors on triggers for more than a month. Errors started appearing yesterday and today.
Code runs on Google Apps Script. You can run it too. Download file to Google Drive in folder Data. And use block Full code
function tryParseJSON(file) {
if (!file) return [];
console.log('file', file.getName());
let blob = file.getBlob();
console.log('blob', blob.toString());
let text = blob.getDataAsString();
console.log('text length', text.length);
console.log('text', text);
try {
return JSON.parse(text);
} catch (e) {
console.error('Не удалось перевести строку JSON в объект.', e, e.stack, 'text', text);
return [];
}
}
Run
function debug() {
let x = Cache.read('test.json');
}
Logs
// time 00:38:17
file test.json
blob Blob
text length 0
text
SyntaxError: Unexpected end of JSON input
at JSON.parse (<anonymous>)
at tryParseJSON (Library:1966:25)
at Object.read (Library:1888:16)
at debug (Debug:2:22)
at __GS_INTERNAL_top_function_call__.gs:1:8 text
// time 00:37:17
file test.json
blob Blob
text length 19
text {
"id": 1
}
Full code
const Cache = (function () {
const FOLDER_NAME = 'Data';
const rootFolder = getRootFolder();
return {
read: read,
write: write,
append: append,
clear: clear,
copy: copy,
remove: remove,
rename: rename,
};
function read(filename) {
return tryParseJSON(getFile(filename));
}
function append(filename, content, place = 'end', limit = 100000) {
if (!content || content.length == 0) return;
let currentContent = read(filename);
if (place == 'begin') {
appendNewData(content, currentContent);
} else if (place == 'end') {
appendNewData(currentContent, content);
}
function appendNewData(xData, yData) {
Combiner.push(xData, yData);
Selector.keepFirst(xData, limit);
write(filename, xData);
}
}
function clear(filename) {
write(filename, []);
}
function write(filename, content) {
let file = getFile(filename);
if (!file) {
file = createFile(filename);
}
file.setContent(JSON.stringify(content));
}
function copy(filename) {
let file = getFile(filename);
if (file) {
filename = 'Copy' + formatExtension(filename.split('.')[0]);
file.makeCopy().setName(filename);
return filename;
}
}
function remove(filename) {
let file = getFile(filename);
if (file) {
file.setTrashed(true);
}
}
function rename(oldFilename, newFilename) {
let file = getFile(oldFilename);
if (file) {
file.setName(formatExtension(newFilename));
}
}
function getFile(filename) {
let files = getFileIterator(filename);
if (files.hasNext()) {
return files.next();
}
}
function createFile(filename) {
return rootFolder.createFile(formatExtension(filename), '');
}
function getFileIterator(filename) {
return rootFolder.getFilesByName(formatExtension(filename));
}
function tryParseJSON(file) {
if (!file) return [];
console.log('file', file.getName());
let blob = file.getBlob();
console.log('blob', blob.toString());
let text = blob.getDataAsString();
console.log('text length', text.length);
console.log('text', text);
try {
return JSON.parse(text);
} catch (e) {
console.error('Не удалось перевести строку JSON в объект.', e, e.stack, 'text', text);
return [];
}
}
function getRootFolder() {
let folders = DriveApp.getFoldersByName(FOLDER_NAME);
if (folders.hasNext()) {
return folders.next();
}
return DriveApp.createFolder(FOLDER_NAME);
}
function formatExtension(filename) {
if (!filename.includes('.')) {
filename += '.json';
}
return filename;
}
})();

Tensor shape must be [-1,-1,-1,3] but was [X,XXX,XXXX,X]?

I'm new to JS (especially to Node and tfjs) and I want to convert my image into a tensor.
But whenever I try to do so, I get this error:
UnhandledPromiseRejectionWarning: Error: The shape of dict['image_tensor'] provided in model.execute(dict) must be [-1,-1,-1,3], but was [1,628,1100,4]
Here's my code:
async function gotMessage(msg) {
if(msg.content === '!object') {
const attachments = (msg.attachments).array();
const filepath = "./images/" + Date.now() + "J" + ".png";
console.log(filepath);
const imageurl = attachments[0].url;
await saveImageToDisk(imageurl,filepath)
let img_buffer = fs.readFileSync(filepath)
const img = tf.node.decodePng(img_buffer)
coco.load().then(model => {
// detect objects in the image.
model.detect(img).then(predictions => {
console.log('Predictions: ', predictions);
});
});
msg.reply('Enjoy');
msg.channel.send(attachments[0].url);
}
}
async function saveImageToDisk(url,path) {
return new Promise((resolve, reject) => {
var fullUrl = url;
var localPath = fs.createWriteStream(path);
var request = https.get(fullUrl,function(response) {
//console.log(response)
response.pipe(localPath)
response.on('end', resolve);
}).on('error', reject);
});
}
decodePng returns a 4D array. If you want to use it for training your model, just pass
expand_animations=True to decodePng. It will return a 3D array.
Tensorflow doc on decodePng

Why is my code not waiting for the completion of the function?

I am trying to read some data from a file and store it in a database.
This is part of a larger transaction and I need the returned ids for further steps.
async parseHeaders(mysqlCon, ghID, csv) {
var self = this;
var hIDs = [];
var skip = true;
var idx = 0;
console.log("Parsing headers");
return new Promise(async function(resolve, reject) {
try {
var lineReader = require('readline').createInterface({
input: require('fs').createReadStream(csv)
});
await lineReader.on('close', async function () {
console.log("done: ", JSON.stringify(hIDs));
resolve(hIDs);
});
await lineReader.on('line', async function (line) {
line = line.replace(/\"/g, '');
if (line.startsWith("Variable")) { //Variable,Statistics,Category,Control
console.log("found variables");
skip = false; //Ignore all data and skip to the parameter description.
return; //Skip also the header line.
}
if (!skip) {
var data = line.split(",");
if (data.length < 2) { //Variable section done return results.
console.log("Found sub?",line);
return lineReader.close();
}
var v = data[0];
var bidx = data[0].indexOf(" [");
if (bidx > 0)
v = data[0].substring(0, bidx); //[] are disturbing mysql (E.g.; Air temperature [�C])
var c = data[2];
hIDs[idx++] = await self.getParamID(mysqlCon, ghID, v, c, data);//, function(hID,sidx) { //add data in case the parameter is not in DB, yet.
}
});
} catch(e) {
console.log(JSON.stringify(e));
reject("some error occured: " + e);
}
});
}
async getParamID(mysqlCon,ghID,variable,category,data) {
return new Promise(function(resolve, reject) {
var sql = "SELECT ID FROM Parameter WHERE GreenHouseID="+ghID+" AND Variable = '" + variable + "' AND Category='" + category + "'";
mysqlCon.query(sql, function (err, result, fields) {
if(result.length === 0 || err) { //apparently not in DB, yet ... add it (Acronym and Machine need to be set manually).
sql = "INSERT INTO Parameter (GreenHouseID,Variable,Category,Control) VALUES ("+ghID+",'"+variable+"','"+category+"','"+data[3]+"')";
mysqlCon.query(sql, function (err, result) {
if(err) {
console.log(result,err,this.sql);
reject(err);
} else {
console.log("Inserting ",variable," into DB: ",JSON.stringify(result));
resolve(result.insertId); //added, return generated ID.
}
});
} else {
resolve(result[0].ID); //found in DB .. return ID.
}
});
});
}
The functions above are in the base class and called by the following code:
let headerIDs = await self.parseHeaders(mysqlCon, ghID, filePath);
console.log("headers:",JSON.stringify(headerIDs));
The sequence of events is that everything in parseHeaders completes except for the call to self.getParamID and control returns to the calling function which prints an empty array for headerIDs.
The console.log statements in self.getParamID are then printed afterward.
What am I missing?
Thank you
As you want to execute an asynchronous action for every line we could define a handler to do right that:
const once = (target, evt) => new Promise(res => target.on(evt, res));
function mapLines(reader, action) {
const results = [];
let index = 0;
reader.on("line", line => results.push(action(line, index++)));
return once(reader, "close").then(() => Promise.all(results));
}
So now you can solve that easily:
let skip = false;
const hIDs = [];
await mapLines(lineReader, async function (line, idx) {
line = line.replace(/\"/g, '');
if (line.startsWith("Variable")) { //Variable,Statistics,Category,Control
console.log("found variables");
skip = false; //Ignore all data and skip to the parameter description.
return; //Skip also the header line.
}
if (!skip) {
var data = line.split(",");
if (data.length < 2) { //Variable section done return results.
console.log("Found sub?",line);
return lineReader.close();
}
var v = data[0];
var bidx = data[0].indexOf(" [");
if (bidx > 0)
v = data[0].substring(0, bidx); //[] are disturbing mysql (E.g.; Air temperature [�C])
var c = data[2];
hIDs[idx] = await self.getParamID(mysqlCon, ghID, v, c, data);
}
});

Categories

Resources