69

I'm using axios to check if an alias has not already been used by another in the database.

Problem: The ajax call doesn't wait for the server response to execute the remaining code.

The code looks like :

export default {
    data () {
        return {
            id: null,
            alias: null,
            valid: true,
        }
    },

    methods: {
        // triggered by the save button
        save () {
            this.valid = true;
            console.log('before checking');

            this.checkUniqueness();
            // other validations here

            if (this.valid) {
                console.log('3. checked valid, can save now');
                // save now
            }
        },

        checkUniqueness () {
            axios.get('/api/unique/alias', {
                params: {
                    id: this.id,
                    alias: this.alias,
                }
            })
                .then((response) => {
                    console.log('2. server response:' + response.data.unique)
                    this.valid = response.data.unique;
                });
        },

    },
}

The console shows the following result:

1. before checking
3. checked valid, can save now
2. server response:false

I cannot move the code of the save() method into .then because I do other validations on the input data such as alpha-numeric characters, minimum of characters...

I was able to delay the 3rd part (if (this.valid) {) using set setTimeout but it's not the best solution. what if the server takes more or less than the defined waiting time..

Question Is there a way to make this call sequential (1, 2, 3) instead of (1, 3, 2)?

Koray Tugay
  • 22,894
  • 45
  • 188
  • 319
Warrio
  • 1,853
  • 4
  • 28
  • 45
  • 1
    Sync requests are not implemented yet and won't be implemented in Axios as sync requests are deprecated in most browsers and unavailable in Node.js. Info: https://github.com/mzabriskie/axios/issues/681 – palaѕн Sep 21 '17 at 15:29
  • is there another way to hack this validation without sync calls? – Warrio Sep 21 '17 at 15:31
  • Moving the code into the .then method answered my question thanks ;) – Josh Oct 23 '20 at 07:49

3 Answers3

65

You can't (or at least really shouldn't) make it synchronous, so you'll need a different way forward.

One idea: return the promise from Axios:

checkUniqueness () {
    return axios.get('/api/persons/unique/alias', {
        params: {
            id: this.id,
            alias: this.alias,
        }
    })
    .then((response) => {
        console.log('2. server response:' + response.data.unique)
        this.valid = response.data.unique;
    });
}

and then call then() on it in save():

this.checkUniqueness()
.then((returnVal) => {
   // other validations here
  //  save
})
.catch(err => console.log("Axios err: ", err))

You could even do all your checking on one place if you returned the value from Axios's then() rather than setting the flag:

.then((response) => {
    console.log('2. server response:' + response.data.unique)
    return response.data.unique;
 });

then in save:

this.checkUniqueness()
.then((valid) => {
    if (valid) // do something
   // other validations here
   //  save
})
Mark
  • 90,562
  • 7
  • 108
  • 148
  • 8
    Just spent ages looking for this answer, and finally found this simple, clear explanation! Thanks. Can't believe more people don't have this question! – Andy Brown Jan 21 '19 at 10:11
  • 2
    @Andy Brown, I too have exactly the same question! The response saved my day :) – mvsagar Oct 20 '19 at 10:11
  • 6
    `You can't (or at least really shouldn't) make it synchronous` this is not very explanatory. – Raman Sinclair Nov 30 '20 at 07:23
  • @MarkMeyer, it is true if the app has the UI, or needs to be able to do some stuff in parallel. In my case it is a server routine that must be synchronous, so I was wondering why you advice against it. Finally, I decided not use axios after all (: – Raman Sinclair Nov 30 '20 at 08:34
  • @Arsinclair fwiw, running node on the server will also suffer problem if you block the main thread. While you are waiting on a long task you can not respond to incoming requests. If you do this on a busy server requests will eventually back up and the server will stop working. The solution is to never block the main thread, which is why all the node libraries that deal with I/O take callbacks or return promises. – Mark Nov 30 '20 at 14:47
18

axios.get(...) returns a promise (a task that is promised for later) and you can wait the interpreter untill this promise ends with an await word in ES6+ :

let response = await axios.get(...)

but axios.get(...) returns the response while axios.get(...).then(...) returns what you intended to return. so if you dont return anything in then part it will be undefined:

let response = await axios.get(...).then() // nothing returns in then
console.log(response) // undefined
12

You can treat Axios just as any you would any Javascript Promise- just do what the (mozilla) JS docs show.

Be careful about making the request synchronous bc it can freeze the UI and the rest of your app.

       async save () {
            this.valid = true;
            console.log('before checking');

            const isUnique = await this.checkUniqueness();
            console.log(isUnique); // => value waited for and returned from this.checkUniqueness()
            // other validations here

            if (this.valid) {
                console.log('3. checked valid, can save now');
                // save now
            }
        }
Taysky
  • 4,331
  • 2
  • 20
  • 28
  • 1
    This added to the previous answer gives a complete solution. I had to add the await to the outer call to get it to return the value instead of the promise again. Uptick +1. – justdan23 Jun 08 '20 at 17:25
  • 1
    But await is contagious - if you use it in a method, you have to change the signature to async and Promise is returned. So the consumer will use await => async, returned Promise etc. *** Am I right to strip off these async + Promise I have to consume new Promise(asyncMethod).then()? – Leos Literak Sep 11 '21 at 14:13