I have a javascript app that reads invoices. It's working perfectly but I would like to improve it's performance a bit.
The way the app works is this. There are Next and Submit buttons. After either, a new image is loaded and a function doOcr is called. In each instance of doOCR, a worker is created which must take time. I am trying to figure out how to move the worker outside the function so it doesn't need to be created each time. Code is below. Thoughts?
//ocr the image and fill values
function doOCR(){(async () => {
worker = Tesseract.createWorker();
await worker.load();
await worker.loadLanguage('eng');
await worker.initialize('eng');
const values = [];
for (let i = 0; i < rectangles.length; i++) {
const { data: { text } } = await worker.recognize(imgFile, { rectangle: rectangles[i] });
values.push(text);
}
console.log(values);
//calculate and display result
dir = values[0].split(' ');
$("#inDir").val(dir[1]);
//get invoice number
$("#inVendor").val(dir[0]);
//get invoice #
var str = values[0];
var n = str.indexOf("Invoice:", 0);
var n1 = str.indexOf("Invoice", n+5);
invoice = str.substr(n+9, n1-n-9);
$("#inInvoice").val(invoice);
await worker.terminate();
$('#status').attr('src','check.png').show();
})()};
Thank you.
I think I got it by changing the top half of the function to:
function doOCR(){(async () => {
if (typeof(worker) == "undefined") {
worker = Tesseract.createWorker();
await worker.load();
await worker.loadLanguage('eng');
await worker.initialize('eng');
}
const values = [];
for (let i = 0; i < rectangles.length; i++) {
const { data: { text } } = await worker.recognize(imgFile, {rectangle: rectangles[i]});
values.push(text);
}
console.log(values);
[ ... ]
and removed
await worker.terminate();
Related
I have written a function to pull stream data from the fetch API. I want to convert the function to a recursive one and would like to write it as an async function.
Here is the code which works but not asynchronous:
const productsStream = async () => {
const request = {
searchRange: ['fragrance', 'perfumery', 'cologne'],
exclusionCategory: ['discounted']
}
const response = await fetch('/products/stream', {
method: 'POST',
body: JSON.stringify(request)
});
const decoder = new TextDecoderStream();
const reader = response.body.pipeThrough(decoder).getReader();
let line = "";
while (true) {
const { done, value } = await reader.read();
let chunk = remainder + value;
let products = []
let newlineIndex;
while ((newlineIndex = chunk.indexOf("\n")) != -1) {
let item = chunk.substring(0, newlineIndex);
chunk = chunk.substring(newlineIndex);
if (chunk.length > 1) chunk = chunk.substring(1);
}
line = chunk;
products = []
if ( done ) break;
}
}
I'd welcome any help in converting this.
I'm having problem with loading from local storage.
Here's a part of the code
const getTerminus = () => {
let terminus;
if (localStorage.getItem("terminus") === null) {
terminus = [];
} else {
terminus = JSON.parse(localStorage.getItem("terminus"));
}
let directions;
if (localStorage.getItem("directions") === null) {
directions = [];
} else {
directions = JSON.parse(localStorage.getItem("directions"));
}
terminus.forEach(async(stop) => {
let API_URL =
"https://ckan.multimediagdansk.pl/dataset/c24aa637-3619-4dc2-a171-a23eec8f2172/resource/d3e96eb6-25ad-4d6c-8651-b1eb39155945/download/stopsingdansk.json";
let response = await fetch(API_URL);
let data = await response.json();
const {
stops,
stopId,
stopName,
stopCode,
zoneId
} = data;
let input = stop;
let ID;
let dataArr = [];
for (let i = 0; i < stops.length; i++) {
if (
stops[i].stopName === input &&
stops[i].stopCode === directions[terminus.indexOf(input)] &&
stops[i].zoneId === 1
) {
ID = stops[i].stopId;
dataArr = [ID, stops[i].stopName];
}
}
API_URL = `https://ckan2.multimediagdansk.pl/delays?stopId=${ID}`;
response = await fetch(API_URL);
data = await response.json();
const {
delay,
estimatedTime,
routeId,
headsign
} = data;
let times = [];
let routeIds = [];
let headsigns = [];
for (let i = 0; i < delay.length; i++) {
times.push(delay[i].estimatedTime);
routeIds.push(delay[i].routeId);
headsigns.push(delay[i].headsign);
}
routeIds.push(" ");
times.push(" ");
const cardDiv = document.createElement("div");
cardDiv.classList.add("card");
const stopNameDiv = document.createElement("div");
stopNameDiv.classList.add("stop-name-div");
cardDiv.appendChild(stopNameDiv);
const stopNameSpan = document.createElement("span");
stopNameSpan.innerText = dataArr[1];
stopNameSpan.classList.add("stop-name-span");
stopNameDiv.appendChild(stopNameSpan);
const scheduleDiv = document.createElement("div");
scheduleDiv.classList.add("schedule-div");
cardDiv.appendChild(scheduleDiv);
if (headsigns.length !== 0) {
routeIds.unshift("Line");
headsigns.unshift("Direction");
times.unshift("Departure");
}
const lineSpan = document.createElement("span");
lineSpan.innerText = routeIds.join("\n");
lineSpan.classList.add("line-span");
scheduleDiv.appendChild(lineSpan);
const dirSpan = document.createElement("span");
dirSpan.innerText = headsigns.join("\n");
dirSpan.classList.add("dir-span");
scheduleDiv.appendChild(dirSpan);
const timeSpan = document.createElement("span");
timeSpan.innerText = times.join("\n");
timeSpan.classList.add("time-span");
scheduleDiv.appendChild(timeSpan);
const buttonsDiv = document.createElement("div");
buttonsDiv.classList.add("buttons-div");
cardDiv.appendChild(buttonsDiv);
const deleteButton = document.createElement("button");
deleteButton.innerHTML = '<i class="fas fa-trash"></i>';
deleteButton.classList.add("delete-button");
buttonsDiv.appendChild(deleteButton);
const dirButton = document.createElement("button");
dirButton.innerHTML = '<i class="fas fa-retweet"></i>';
dirButton.classList.add("reverse-button");
buttonsDiv.appendChild(dirButton);
stopList.appendChild(cardDiv);
});
};
document.addEventListener("DOMContentLoaded", getTerminus);
Terminus contains stop names, and directions contains direction codes.
On refresh, it fetches data from API based on stop name and direction, and displays a card with departure time etc.
The problem is, on closing and re-opening the page cards are sometimes displayed in a wrong order. I have found out, that as time between closing and opening lengthens, the probability of this occurring gets higher. After simple refresh everything is in correct order.
Does it have something to do with browser cache? Has anyone had similar issue or knows what's going on?
Alright, as #Yoshi stated, it was insequential promise error. I managed to fix it by using reduce().
Here are the threads that helped me
Resolve promises one after another (i.e. in sequence)?
Why Using reduce() to Sequentially Resolve Promises Works
I am trying to get API data so i can render it on Webpage using ReactJS. I tried many different ways to fetch api where its stored in array. But i am unable to do it.
Note:https://www.hatchways.io/api/assessment/workers/<worker_id> Here i'm looping so the
worker id gets add the of url.
const fetchAPI = e => {
let array = [];
const api2 = `https://www.hatchways.io/api/assessment/workers/`;
for (var i = 0; i <= 4; i++) {
array.push(api2 + i);
}
return array;
};
console.log(fetchAPI());
Thanks in advance.
You need to hit the url first. Async/Await would be a good choice.
<script>
async function check()
{
var arrayData =[];
var url = "https://www.hatchways.io/api/assessment/workers/";
for(var i=1;i<=4;i++)
{
const response = await fetch(url+""+i);
const myJson = await response.json();
arrayData.push(myJson);
}
console.log(arrayData)
}
check();
</script>
Use Promise.all for example:
const baseURL = 'https://jsonplaceholder.typicode.com';
const fetchUsers = fetch(`${baseURL}/users`);
const fetchPosts = fetch(`${baseURL}/posts`);
Promise.all([fetchUsers, fetchPosts]).then((responses) => {
const responsesToJson = responses.map(response => response.json());
return Promise.all(responsesToJson);
}).then((jsonResponse) => {
const [userResponse, postResponse] = jsonResponse;
console.log(userResponse);
console.log(postResponse);
});
Mediocre javascript developer here and need some help..
I want to make a GET call to a url several times in a for loop.
I am trying to use fetch, but because of the promise/timing situation, I can't figure out how to make it work.
Below is the code and it's entirely possible that the fetch approach doesn't make sense for what I am trying to do. Would appreciate your help either helping me with code or telling me I am idiot and advising an alternative :)
var fromAmt = 100;
var fromOOP = 50;
var fromGM = 50;
var fromCur = "USD"
var toCur = ["USD","EUR","INR","GBP","SGD"];
var adjAmt = [];
async function getConversionAsync(fcur,tcur,amt)
{
let response = await fetch('https://data.fixer.io/api/convert?access_key=xyxyxyxyxyxyxy&from=' + fcur + '&to=' + tcur + '&amount=' + amt);
let data = await response.json()
return data;
}
for (i = 0; i < toCur.length; i++) {
getConversionAsync(fromCur,toCur[0].toString(),fromAmt)
.then(data => display(data));
}
function display(thing){
adjAmt.push(thing.result);
}
document.getElementById("something").innerHTML = adjAmt[0].toString();
In your example, document.getElementById("something").innerHTML = adjAmt[0].toString(); is executed before anything is pushed to adjAmt. You need to wait for the loop calls to finish before displaying a result, and for this you could wrap everything inside an async function.
const fromAmt = 100;
const fromOOP = 50;
const fromGM = 50;
const fromCur = 'USD';
const toCur = ['USD', 'EUR', 'INR', 'GBP', 'SGD'];
const adjAmt = [];
const getConversionAsync = async (fcur, tcur, amt) => {
const response = await fetch(`https://data.fixer.io/api/convert?access_key=xyxyxyxyxyxyxy&from=${fcur}&to=${tcur}&amount=${amt}`);
return response.json();
}
function display(thing) {
adjAmt.push(thing.result);
}
(async () => {
for (i = 0; i < toCur.length; i += 1) {
const data = await getConversionAsync(fromCur, toCur[0], fromAmt);
display(data);
}
document.getElementById('something').innerHTML = adjAmt[0].toString();
})();
Some small changes to make it work without the API call, but you'll want to access the correct index in your loop. I don't know what the exact output you're wanting here but in this case I just joined all the values in the array.
Additionally, the setting of innerHTML needs to be done once all the values are retrieved from the API, so I would even suggest doing that when the loop terminates, or some other "done" type event.
Additionally, you can use Promise.all instead of a loop, which is what I would go with personally.
var fromAmt = 100;
var fromOOP = 50;
var fromGM = 50;
var fromCur = "USD"
var toCur = ["USD", "EUR", "INR", "GBP", "SGD"];
var adjAmt = [];
async function getConversionAsync(fcur, tcur, amt) {
let response = await sampleRequest()
/* let data = await response.json() */
return response;
}
for (i = 0; i < toCur.length; i++) {
const data = getConversionAsync(fromCur, toCur[i].toString(), fromAmt).then(data => {
display(data)
})
}
function display(thing) {
adjAmt.push(thing);
document.getElementById("something").innerHTML = adjAmt.join(', ')
}
function sampleRequest() {
return new Promise((resolve, reject) => {
resolve(Math.round(Math.random() * 1000))
})
}
<div id="something"></div>
I'm practicing my javascript skills doing a joke machine that collects jokes from an API and displays them, my problem is that currently, I'm using .then() which is fine, but I want to know how do I get my results in an array that doesn't have to wait for .then() like in fetchJokes().then(jokes => console.log(jokes));
I used to have a function that navigated the array like this:
let counter = 0;
let jokes = [joke1, joke2, joke3, joke4];
function nextJoke(jokes) {
counter++;
counter %= jokes.length; // start from 0 if we get to the end of the array
return jokes[counter]; // give us back the actual item
}
That's how it was used before fetching from the API.
And this is my current code:
const url = "https://api.icndb.com/jokes/random/5";
const fetchButton = document.querySelector("button[type=button][value=Fetch]");
async function fetchJokes() {
let jokes = [];
let data = await (await fetch(url)).json();
for (let i = 0; i < 5; i++) {
jokes[i] = data.value[i].joke;
}
return jokes;
}
fetchButton.addEventListener("click", () => {
fetchJokes().then(jokes => console.log(jokes));
});
<button type="button" value="Fetch">Fetch Jokes</button>
So I have figured out how to use buttons and all that jazz, just asking for help on how to pass the object that im receiving from fetchJokes() and store it in an Array.
You can use fetch() to retrieve the url's data. Then you have to transform it to json with .then((resp) => resp.json()).
After that, you can store the data inside your jokes array.
const url = "https://api.icndb.com/jokes/random/5";
const fetchButton = document.querySelector("button[type=button][value=Fetch]");
const nextButton = document.querySelector("button[type=button][value=Next]");
const display = document.getElementById("display");
let counter = 0;
let jokes = [];
nextButton.style.visibility = 'hidden'; //Hide next button
fetchButton.addEventListener("click", () => {
fetch(url).then((resp) => resp.json()) // Transform the data into json
.then(data => (jokes = data.value, //Set the array of jokes
fetchButton.style.visibility = 'hidden', //Hide fetch button
nextButton.style.visibility = 'visible')); //Show next button
});
nextButton.addEventListener("click", () => {
//Show next joke
display.innerHTML = jokes[counter++ % jokes.length].id + " : " + jokes[counter++ % jokes.length].joke;
});
<button type="button" value="Fetch">Fetch Jokes</button>
<button type="button" value="Next">Next joke</button>
<p id="display"></p>
This is what worked for me without modifying the main purpose of the snippet in the question.
let counter = 0;
const url = "https://api.icndb.com/jokes/random/5";
const fetchButton = document.querySelector("button[type=button][value=Fetch]");
async function fetchJokes() {
let jokes = [];
let data = await (await fetch(url)).json();
for (let i = 0; i < 5; i++) {
jokes[i] = data.value[i].joke;
}
return jokes;
}
fetchButton.addEventListener("click", () => {
fetchJokes().then(data => (jokes = data)).then(data => console.log(data));
});
<button type="button" value="Fetch">Fetch Jokes</button>
I'm not sure I understand the question...If you want to fetch from an async api and not have to use .then or have to wait, then that is not possible.
From what I understand of the question, if you do not want to use .then every time, only fetch when the array is empty (only fetch once):
const url = "https://api.icndb.com/jokes/random/5";
const fetchButton = document.querySelector("button[type=button]
[value=Fetch]");
let arr = []
let counter = 0;
async function fetchJokes() {
let data = await (await fetch(url)).json();
for (let i = 0; i < 5; i++) {
arr[i] = data.value[i].joke;
}
}
function nextJoke(jokes) {
const item = jokes[counter]
counter++;
if (counter >=jokes.length){
counter %= jokes.length;
}// start from 0 if we get to the end of the array
return item; // give us back the actual item
}
fetchButton.addEventListener("click", () => {
if (arr.length == 0){
fetchJokes()
.then(()=>console.log(nextJoke(arr)))
}else{
console.log(nextJoke(arr))
}
});
DEMO codepen
There are many ways to do this. I would suggest looking more into Javascript Promises.