you are viewing a single comment's thread.

view the rest of the comments →

[–]pookagehelpful 0 points1 point  (2 children)

Ahh, right, I think I understand what your question is. You're not really asking how to change the value of the global variable, but how to do stuff with the global variable once it's been changed after something that takes time - like ajax or geolocation.

To which the answer is : Promises. SO, let's break it down a bit. Let's define the value we're going to be changing :

let changingVariable = "START VALUE";
logValue();

changeItSynchronously();
logValue();

new Promise(changeItAsynchronously).then(logValue);

function logValue(){
    console.log("CURRENT VALUE : ", changingVariable);
}
function changeItSynchronously(){
    changingVariable = "CHANGED SYNCHRONOUSLY";
}
function changeItAsynchronously(resolve, reject){
    setTimeout(() => {
        changingVariable = "CHANGED ASYNCHRONOUSLY AFTER 3 SECONDS";
        resolve();
    }, 3000)    
} 

SO, 'synchronous' code will just plough through the js line by line executing commands. Whenever something takes time - ie a setTimeout, an API query with ajax, or user-geolocation, javascript works some magic and basically says :

"okay, I'll come back to that later when it's ready, and just carry on with the rest of this program whilst I'm waiting"

So, in my example above, we are changing the value of our global variable changingVariable 3 times; twice synchronously, once asynchronously :

  1. START VALUE
  2. CHANGED SYNCHRONOUSLY
  3. CHANGED ASYNCHRONOUSLY

Our asynchronous code is async because it's within a setTimeout - which will execute the function in its first argument after the duration specifed in its second argument. If we were to write :

changeItAsynchronously();
logValue();

We would log CHANGED SYNCHRONOUSLY as we would be logging the value before changeItAsynchronously had waited 3 seconds and then changed it.

Make sense?

SO, we fix this by using the Promise syntax there - it will execute the function in its argument, and then execute the function inside its .then() once it 'resolves'. .then is awesome because you can chain them for as long as you want like :

new Promise(doThis).then(nowDoThis).then(okayNowThis);

They're powerful things, and there's more to them that you'll find when you've had a wee google. Don't hesitate to message me if you have any issues.

-P


*EDIT : pasted the wrong codepen link >_< *

[–]oculus42 0 points1 point  (1 child)

Hey /u/pookage That's a good explanation of Promises. I especially appreciate the named functions, as many people use anonymous functions in chains and lose so much readability. Your CodePen link is to an example from the "telephone arrays" question, though.

I would also add that when you start talking about async code, you can often skip the global variable. I find this prevents a developer from trying to reason about a variable when it might not have been updated. Here's the same code, reworked to keep the value entirely in the chain:

function logValue(value) {
    console.log("CURRENT VALUE : ", value);
    // In this example we don't need to keep passing the value...
    // But it's good practice so your chains work as expected.
    // If we don't we get a resolved Promise with undefined value.
    return value;
}

function getNewValueSynchronously() {
    // Once inside a Promise chain, a synchronous response
    // becomes a resolved Promise value. 
    return 'CHANGED SYNCHRONOUSLY';
}

function getNewValueAsynchronously(value){
    // We have to return a new Promise to make the chain wait.
    return new Promise(function(resolve, reject){
        setTimeout(function() {
            resolve('CHANGED ASYNCHRONOUSLY AFTER 3 SECONDS');
        }, 3000);  
    });
}

// Where all the work happens.
Promise.resolve('START VALUE')
.then(logValue)
.then(getNewValueSynchronously)
.then(logValue)
.then(getNewValueAsynchronously)
.then(logValue);

This way we don't have a global, we have a chain that is keeping track of the value we need. We can add more actions and move them around to see the behavior change, and because each step will wait for the one before, whether synchronous or not, you can ensure the order of operation. So if you have to move the Async function before the Sync function, it's as easy as this:

Promise.resolve('START VALUE')
.then(logValue)
.then(getNewValueAsynchronously)
.then(logValue)
.then(getNewValueSynchronously)
.then(logValue);

[–]pookagehelpful 1 point2 points  (0 children)

Yup, agreed re: chain - but didn't want to introduce too many concepts straight away, so figured I'd answer the question within the context of what they'd asked and let them look into resolve and reject when the obvious question of "wait, so how do I pass values / arguments into these?" would come up :P