0

I am new to reactJS and am trying to build a sorting visualizer. The problem I am facing is while implementing the quickSort() routine.
My quickSort() routine is as follows:

async quickSort(array, p, r) {
         if(p<r){
                this.Partition(array,p,r).then((q)=>{
                console.log(p, ' ', r)
                this.quickSort(array, p, q-1)
                this.quickSort(array,q+1,r)

                })  
            }   
    }

The reason I have a .then with the Partition function is because I am using async/await in the Partition routine for animations. Then the Partition routine returns the value of the partition 'q' and then the recursion can occur. The Partition function returns a promise whose value is the partition value 'q' without which the recursion cannot proceed hence the '.then' part.

Now, the code is running correctly but I want to add a little bit more functionality. I am calling this quickSort() routine from inside of a quickSortHelper() routine. In quickSortHelper() I first disable a button, then call quickSort() and after completion of quickSort() I want to again enable the button. But the problem is that the quickSort(array, 0 , n-1) returns after only the first call to it and so the button is instantly disabled and enabled without waiting for the entire recursion to unfold.

I tried returning a promise from inside quickSort() to ensure that when the promise is resolved only then do we proceed to enable the button. But the promise resolves after 1-2 iterations (which makes sense because the moment p>r I think the function would return) and so the button gets enabled without waiting for the entire recursion to finish.

Any suggestions on how to fix this? Is there a way to pause execution until the quickSort() completes and then continue on with the work of enabling the button?

async quickSortHelper(){
        this.setState({generateButton: true})
        console.log(this.state.generateButton)

        var array = this.state.array

        this.quickSort(array, 0, array.length-1 ).then(()=>{
            this.setState({array})
            this.setState({generateButton: false})
        })
    }

Also one more thing, the console.log(this.state.generateButton) outputs false. So it is never setting the state to true? I don't understand why this is happening?

  • You should put `await` before the expressions that return a promise. But without seeing how you actually create and resolve the promises, it is impossible to say that this is all you have to do. Instead of describing in words what your quickSort related functions do (like Partition, helper...), it is less ambiguous if you just post the code (but not more than needed to reproduce the issue) – trincot Aug 16 '20 at 08:24
  • isn't await providing the same functionality as using .then? This is the whole code apart from the Partition routine which just picks a partition index. The helper function is at the end. – JANVI SHARMA Aug 16 '20 at 08:27
  • To check for `this.state.generateButton` returning false, please share the code for setting the state (`this.setState`) – Kunal Kukreja Aug 16 '20 at 08:40

2 Answers2

1

Your quickSort function currently returns a promise that immediately resolves with value undefined. You need to return a promise, and await its resolution. So either continue the then chain (and then you don't really need async), or use async/await (cf. further down):

function quickSort(array, p, r) {
    if (p < r) {
        return this.Partition(array,p,r).then((q) => {
    //  ^^^^^^
            console.log(p, ' ', r);
            return this.quickSort(array, p, q-1);
    //      ^^^^^^
        }).then(() => {
            return this.quickSort(array,q+1,r);
    //      ^^^^^^
        });
    }   
}

Of course, mixing async and then is a bit strange, so you should just replace that then with an await syntax also:

async quickSort(array, p, r) {
    if (p < r) {
        let q = await this.Partition(array,p,r);
        console.log(p, ' ', r);
        await this.quickSort(array, p, q-1);
        await this.quickSort(array,q+1,r);
    }   
}

NB: use semi-colons. Relying on automatic semicolon insertion is giving away control when you can take control yourself.

trincot
  • 211,288
  • 25
  • 175
  • 211
  • Yes I agree that I should stick to either just using await or just using then to make the code more readable. I tried implementing what you suggested and I am getting a parsing error saying 'cannot use await outside of an async function'. (this is when I tried the first thing you suggested with the return statement) – JANVI SHARMA Aug 16 '20 at 08:35
  • the second one did the job!! I was missing the await of the quickSort and did not realize that an undefined value was being returned! thanks! – JANVI SHARMA Aug 16 '20 at 08:39
  • indeed, the first version should really continue the `then` chain. See update of the first version. – trincot Aug 16 '20 at 09:03
1

This should do the job:

async quickSort(array, p, r) {
    if(p<r){
        const q = await this.Partition(array,p,r);
        console.log(p, ' ', r);
        await this.quickSort(array, p, q-1);
        await this.quickSort(array,q+1,r);
    }
}
Kunal Kukreja
  • 544
  • 3
  • 13