I have a pretty CPU intensive operation running in a JS function. To indicate to the user when it starts and stops, I am trying to display a badge. Here's what the code looks like:
function updateView() {
console.log(1)
document.getElementById('app-status').className = "badge badge-danger";
document.getElementById('app-status').textContent = "Processing";
console.log(2)
setTimeout(myUpdateView(), 0)
console.log(5)
document.getElementById('app-status').className = "badge badge-success";
document.getElementById('app-status').textContent = "Ready"; console.log(6)
}
function myUpdateView() {
console.log(3)
updateFlightParameters();
// Get departure airport.
var departureAirportICAO = $("#DEPARTURE_AIRPORT").val();
if (airports[departureAirportICAO] === undefined) {
alert("Departure airport is incorrect.");
} else {
departureAirport = airports[departureAirportICAO];
}
// Get arrival airport.
var arrivalAirportICAO = $("#ARRIVAL_AIRPORT").val();
if (airports[arrivalAirportICAO] === undefined) {
alert("Arrival airport is incorrect.");
} else {
arrivalAirport = airports[arrivalAirportICAO];
}
// Create waypoints.
createWaypoint(departureAirport);
createWaypoint(arrivalAirport);
// Create path. THIS FUNCTION CALLS SOME OTHER ASYNC FUNCTIONS.
generatePolylines(flightWaypoints);
console.log(4)
}
The problem is that the app-status element never changes it's color or text. Upon clicking the button that calls updateView(), the page hangs (to do the processing) without changing the element.
Does the heavy processing function return anything? This seems like a good idea for a do-while statement.
const doSomethingCool(){
let trackingVariable = false;
do{
result = setInterval(massiveCompute, 100)
if(result === true){
trackingVariable = true;
}
} while (trackingVariable == false)
I would make sure the computer has time to update the screen:
function doHeavyProcessing() {
for (var i=0;i<1000000000;i++) ;
document.getElementById('app-status').className = "badge badge-success";
document.getElementById('app-status').textContent = "Ready";
}
function updateView() {
document.getElementById('app-status').className = "badge badge-danger";
document.getElementById('app-status').textContent = "Processing";
setTimeout(doHeavyProcessing,100)
}
updateView()
.badge-danger { color:red }
.badge-success { color:green }
<div id="app-status"></div>
Related
I'm working on a board game with an AI mode in it. And now I'm trying to call the AI's move but it is called asynchronously. I don't know what I can do. I've tried a lot of stuff; calling setTimeout synchronously, calling it inside the onClick... Do you have any solutions?
Here's the code:
render() {
// datas that will be rendered regularly come here
const current = this.state.history[this.state.stepNumber]
const elemsPlayer = this.checkElementsAround(this.checkEmptySpaces())
if (this.state.ourPlayer !== (this.state.blackIsNext) ? 'black' : 'white') {
if (this.state.gameMode === "AI-Easy") {
setTimeout(()=>{
this.easyAI()
}, 1500)
} else if (this.state.gameMode === "AI-Hard") {
setTimeout(()=>{
this.minimaxAI()
}, 1500)
}
}
// Return the game scene here
return (
<div id="master-container">
<div id="gameboard-container">
<GameBoard squares={current} onClick={(row,col) => {
// Where player's move will be called
}}/>
</div>
</div>
)
}
Here's the easyAI function (minimax one is empty for now):
easyAI(){
const elemsAI = this.checkElementsAround(this.checkEmptySpaces())
const validsAI = []
for (let elAI=0;elAI<elemsAI.length;elAI++) {
const turningAI = this.checkTurningStones(elemsAI[elAI].directions, this.state.blackIsNext)
//console.log(turningAI)
if (turningAI.length !== 0) {
validsAI.push(elemsAI[elAI])
}
}
// ValidsAI returns an object {emptySquares: coordinates of the empty square, turningStones: coordinates of the stones that will be turned upside down if emptySquares is played}
//Check if AI has a move to make
if (validsAI.length !== 0) {
//Perform the move
var elementToTurnAI = null
try{
elementToTurnAI = validsAI[Math.floor(Math.random()*validsAI.length)]
} catch {
console.log(null)
}
//console.log(elementToTurnAI)
const turningAI = this.checkTurningStones(elementToTurnAI.directions, this.state.blackIsNext)
const selfAI = elementToTurnAI.coordinates
//console.log(selfAI)
//console.log(turningAI)
turningAI.unshift([selfAI[0],selfAI[1]])
// Turn the stones
const upcomingAI = this.handleMove(turningAI)
// Update the state
this.setState({
history: upcomingAI,
stepNumber: upcomingAI.length - 1
},() => {
this.setWinnerAndTurn(this.state.history)
//console.log(this.state.history)
})
}
}
If you have to take a look at something else in order to find a solution, please do let me know.
Thanks in advance :)
I am writing a test case which requires me to reload the page N number of times, and compare its title for a value, if that value does not exists then break the while loop without rising error.
Below is a demo program, similar to the one that I am looking to implement.
/// <reference types='cypress' />
it("Visiting Google",function(){
var webUrl = 'https://html5test.com/'
cy.visit(webUrl)
var loop_iter = 0
while(loop_iter < 5)
{
cy.get('body:nth-child(2) div:nth-child(2) div.header h1:nth-child(1) > em:nth-child(2)').then(($text_data) =>{
if($text_data.text().contains('HTML123'))
{
cy.log(" --> ITERATION = ",loop_iter)
cy.reload()
}
else
{
cy.log("Unknown website")
loop_iter = 10
}
})
loop_iter += 1
}
})
I need a way to break from the while loop when the else part is executed, without rising any error.
The if condition when false returns AssertionError, in such case it should execute else part.
cy.title() is asynchronous (proof is, you need to use .then()), so, the entire while loop ends even before the first .then() triggers. That's how asynchronism works.
You need another approach :
it("Visiting Google", async function () {
var webUrl = 'https://html5test.com/'
cy.visit(webUrl)
for (let i = 0; i < 5; i++) { // You can't await in a 'while' loop
const $text_data = await cy.title();
if ($text_data.includes('HTML')) {
cy.log(" --> ITERATION = ", i)
cy.reload()
}
else {
cy.log("Unknown website")
break;
}
}
})
Please take a look at the sample recipe Page reloads. It uses recursion as suggested in comments.
This is your code adapted to the pattern,
it('reload until "HTML" disappears', () => {
// our utility function
const checkAndReload = (recurse_level = 0) => {
cy.title().then(title => {
if (title.includes('HTML') && recurse_level < 5) {
cy.log(" --> ITERATION = ", recurse_level)
cy.wait(500, { log: false }) // just breathe here
cy.reload() // reload
checkAndReload(recurse_level + 1) // check again
} else {
cy.log("Unknown website")
}
})
}
cy.visit('https://html5test.com/') // start the test by visiting the page
checkAndReload() // and kicking off the first check
})
I'm a fair rookie to JS and I'm working on a project that needs me to make a non-functioning validation system. Here is the code i have at the moment:
I don't know why the setTimeout is not working, I checked on other posts as well but had no understanding. It seems my function dissapearText is not being recognised since i have a console.log as a test to see if it runs, but it's not appearing in the devtools console. Any simple solution would do.
Thanks,
Arthur
{
let validation = document.querySelector('.type__style');
let validation2 = document.getElementById("label__text");
const init = () =>{
const $button = document.getElementById('send__button');
$button.onclick = () => {
revealText();
setTimeout(dissapearText,4000);
}
const revealText = () => {
if (validation.value === ""){
validation.focus();
window.alert("Please enter your name.");
return false;
}else if(validation2.value === ""){
validation2.focus();
window.alert("Please fill in commentary.");
return false;
}else{
document.querySelector('.feedback').style.opacity = 1;
return true;
}
}
const dissapearText = () => {
if (revealText === true){
console.log("sup");
document.querySelector('.feedback').style.opacity = 0;
}
}
}
init();
}
The issue is
if (revealText === true)
revealText is a function which returns a boolean, you need to change this to
if (revealText() === true)
I cannot read the title attribute from the received variable, but as you see the collection is not undefined, and the title attribute also not undefined.
The error saying its undefined.
var received = document.getElementsByClassName("_2her");
if (received[0].title == "Delivered") {
chColorsForDelivered();
}
Your script started before DOM ready, If you are using html5, then use async with you script.
If you only want to check that first element (and make sure it's there after the page loads), I usually use this method:
window.onload = function() {
var received = document.getElementsByClassName("_2her")[0];
if (received.title == "Delivered") {
chColorsForDelivered();
}
}
You could also use querySelector to get the first occurrence of the class, which might be more suited to your needs:
var received = document.querySelector("_2her");
if (received.title == "Delivered") {
chColorsForDelivered();
}
var active;
var bg;
var received;
var rightDelivered;
var colorchint;
window.onload = function() {
main();
}
//=================== FUNCTIONS ===================
async function main() {
active = await document.getElementsByClassName("_2v6o");
bg = document.getElementsByClassName("_673w");
received = await document.getElementsByClassName("_2her");
rightDelivered = document.getElementsByClassName("_2jnt");
colorchint;
bg[0].onmouseover = function() {clearInterv();}
rightDelivered[0].onclick = function() {clearDeliv();}
//await sleep(2000);
if (active[0].innerText == "Active on Messenger") {
chColorsForActive();
}
else if (received[0].title == "Delivered") {
await chColorsForDelivered();
}
}
//for delivered
async function chColorsForDelivered() {
y = 1;
for (var i = 0; i < 6; i++) {
chColorsDelivered();
await sleep(1000);
}
}
function chColorsDelivered() {
if (y === 1) {
color = "#1e1e1e";
y = 2;
} else {
color = "orange";
y = 1;
}
rightDelivered[0].style.background = color;
}
//accessories
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
I put it into async. First I tried to
await for the variable received = await document.getElementsByClassName("_2her"); (it wasn't enough)
then I tried to sleep for 2 seconds (it was working)
tried to await the inner function (it was working too) But i have no idea why is it working if I wait for the inner function. I doesn't make sense to me. If I delete the await chColorsForDelivered(); await here It's complaining about the title is undefiend.
If you run this script in your messenger you will see an orange blinking span in the conversation information (where you see the pictures and stuffs, just delete the if)(It's only blinking if you have a Delivered message).
I'm currently struggling with a function call, when I call the function from an if statement it does work but when I call it from outside it doesn't, my if statement only checks which button was pressed but I'm trying to remove the function from the button and just call it as soon as my app starts.
We will look at fetchJokes() inside jokeContainer.addEventListener('click', event => {
This is my current code:
const jokeContainer = document.querySelector('.joke-container');
const jokesArray = JSON.parse(localStorage.getItem("jokesData"));
// Fetch joke count from API endpoint
async function sizeJokesArray() {
let url = 'https://api.icndb.com/jokes/count';
let data = await (await fetch(url)).json();
data = data.value;
return data;
}
// use API endpoint to fetch the jokes and store it in an array
async function fetchJokes() {
let url = `https://api.icndb.com/jokes/random/${length}`;
let jokesData = [];
let data = await (await fetch(url)).json();
data = data.value;
for (jokePosition in data) {
jokesData.push(data[jokePosition].joke);
}
return localStorage.setItem("jokesData", JSON.stringify(jokesData));;
}
const jokeDispenser = (function() {
let counter = 0; //start counter at position 0 of jokes array
function _change(position) {
counter += position;
}
return {
nextJoke: function() {
_change(1);
counter %= jokesArray.length; // start from 0 if we get to the end of the array
return jokesArray[counter];
},
prevJoke: function() {
if (counter === 0) {
counter = jokesArray.length; // place our counter at the end of the array
}
_change(-1);
return jokesArray[counter];
}
};
})();
// pass selected joke to print on html element
function printJoke(joke) {
document.querySelector('.joke-text p').textContent = joke;
}
sizeJokesArray().then(size => (length = size)); // Size of array in response
jokeContainer.addEventListener('click', event => {
if (event.target.value === 'Fetch') {
fetchJokes(length);
} else if (event.target.value === 'Next') {
printJoke(jokeDispenser.prevJoke(jokesArray));
} else if (event.target.value === 'Prev') {
printJoke(jokeDispenser.nextJoke(jokesArray));
}
});
And I'm trying to do something like this:
// pass selected joke to print on HTML element
function printJoke(joke) {
document.querySelector('.joke-text p').textContent = joke;
}
sizeJokesArray().then(size => (length = size)); // Size of array in response
fetchJokes(length);
jokeContainer.addEventListener('click', event => {
if (event.target.value === 'Next') {
printJoke(jokeDispenser.prevJoke(jokesArray));
} else if (event.target.value === 'Prev') {
printJoke(jokeDispenser.nextJoke(jokesArray));
}
});
By the way, I'm aware that currently, you can't actually iterate through the array elements using prev and next button without refreshing the page but I guess that will be another question.
Couldn't think of a better title.(edits welcomed)
Async functions are, as the name implies, asynchronous. In
sizeJokesArray().then(size => (length = size)); // Size of array in response
fetchJokes(length);
you are calling fetchJokes before length = size is executed because, as you may have guessed, sizeJokesArray is asynchronous.
But since you are already using promises the fix is straightforward:
sizeJokesArray().then(fetchJokes);
If you have not fully understood yet how promises work, maybe https://developers.google.com/web/fundamentals/getting-started/primers/promises helps.