Node JS + Express - Asynchronous request

I'm trying to learn some stuff with Node.js + Express as a web server, trying to make it asynchronous. I've created an app to test time complexity of sorting algorithms (college homework inspiration), but it is not working asynchronously as I was intending. Any other REST call to the Express server is blocked until the former sorting code finishes running. I'm also using 'express-namespace-routes' to have some namespaces, so that it looks like an API call.

This is my class Sort:

class Sort {
   static async binarySearch(array, inf, sup, key) {
    let half = inf + Math.floor((sup - inf) / 2);

    if (inf == sup) return inf;
    else if (key > array[half]) return this.binarySearch(array, half + 1, sup, key);
    else if (key < array[half]) return this.binarySearch(array, inf, half, key);
    else return half;
}

static async binaryInsertionSort(array) {
    let changes = 0;
    const time = process.hrtime();
    for (let j = 1; j < array.length; j++) {
        let key = array[j];
        let i = j - 1;
        let posicao = await this.binarySearch(array, 0, j, key);
        while (i >= posicao) {
            array[i + 1] = array[i];
            i--;
            changes++
        }
        array[posicao] = key;
    }
}

static async createRandomArray(size) {
    let array = await this.createSortedArray(size);
    for (let s = size; s > 0; s--) {
        let index = Math.floor(Math.random() * s);

        let temp = array[s - 1];
        array[s - 1] = array[index];
        array[index] = temp;
    }
    return array;
}
}

This is part of my index.js file, where I'm creating the namespace:

routes.prefix('/sorted', sorted => {
    sorted.get('/binaryInsertion/:size', async (req, res) => {
    Sort.createRandomArray(req.params.size)
      .then(array => Sort.binaryInsertionSort(array))
      .then(data => res.json(data))
      .catch(err => res.send(err));
  });
});

And this is me calling the server:

$.ajax(`${arrayType}/${sortingAlgorithm}/${arraySize}`).then(console.log);

Any idea? What could I possibly be doing wrong? Everything looks assynchronous for me. The problem is not only in the binaryInsertionSort, so I think the problem is not in the algorithm code, as it block requests for all my already implemented algorithms

Upvotes: 1

Views: 1417

Answers (1)

jfriend00
jfriend00

Reputation: 707836

First off, all your code is synchronous and blocking. It's all local Javascript. You don't call any built-in asynchronous operations.

You can't make normal Javascript in node.js run asynchronously. The only things that run asynchronously are things that have some sort of native code implementation that is asynchronous such as file I/O or networking. And, then code that uses callbacks or promises for those natively asynchronous operations will return control back to the event loop (allowing other things to run) and then will resume when their callback gets called. But, none of that allows your own Javascript to "run in the background" or "run without blocking and using the single Javascript thread" in node.js.

Node.js runs your Javascript as single threaded. So, if you're doing some big sorting algorithm, that's going to hob that single thread until it's done. It does not help you at all to make the function async. ALL that does is change the return value of the function. It doesn't affect how the synchronous code in that function runs.

If you really want to run your code outside the single Javascript thread, then you have these options:

  1. Use the child_process module to create a second node.js process to run your sorting code.
  2. Use the cluster module to cluster your app so you have multiple identical processes serving requests and while one is running your sorting algorith, another can be handling other requests.
  3. Write native code that runs your sort in another thread and communicates back the result asynchronously (likely via a callback event in the event queue).
  4. Create a set of worker node.js processes that you communicate with using your favorite form of interprocess communication and then you can create work queue where you pass items to your worker processes and you handle the CPU consuming tasks outside the main node.js app.

Why would it block? I'm calling it asynchronously.

You aren't calling it asynchronously. An async function does not make anything asynchronous. All it does is allow await inside and force the return value of the function to be a promise. Any Javascript inside that function still runs with the single node.js thread and still blocks while its running. If you do an await on a function that returns a promise, that will suspend execution of the function until the promise resolves and allow other things to run, but if all you have in any of your functions is synchronous code, then everything is just going to run synchronously (there's one tiny exception for .then() handlers which just makes them wait until the next cycle of the event loop), but it still doesn't allow synchronous code to run "in the background" or anything like that.

I just want that function to run in the "background", wouldn't my code be doing this?

You can't "run Javascript in the background" in a single node.js process. The architecture of node.js does not work that way. Your code is not doing that. It appears you misunderstand what an async function does.

If not, what could I do?

See the four numbered options above.

Upvotes: 5

Related Questions