---
title: "Evaluating JavaScript code in the browser"
description: "Learn how we evaluate JavaScript in NeetoCourse"
canonical_url: "https://www.bigbinary.com/blog/evaluating-javascript-in-neeto-course"
markdown_url: "https://www.bigbinary.com/blog/evaluating-javascript-in-neeto-course.md"
---

# Evaluating JavaScript code in the browser

Learn how we evaluate JavaScript in NeetoCourse

- Author: Sayooj Surendran
- Published: October 8, 2024
- Categories: JavaScript

[NeetoCourse](https://www.neeto.com/neetocourse) allows anyone to build
interactive courses where they can add code blocks and assessments. This allows
the user to run their code, see the output and check if their solution is
correct or not. Check out
[Bigbinary Academy's JavaScript course](https://courses.bigbinaryacademy.com/learn-javascript/array/challenge-create-array/)
to see this in action.

Let's see how we evaluate JavaScript code and check if the output matches the
corresponding solution.

## Synchronous code

For a simple synchronous code, the first thing we need to check is if everything
logged by the user is the same as that of the solution code. What we do here is
aggregate all the logs to an array and then compare that array with the array
generated by the solution code. This is done by transforming the code using an
[AST library](https://www.npmjs.com/package/abstract-syntax-tree)

Take this
[exercise](https://courses.bigbinaryacademy.com/learn-javascript/variables/challenge-variables/)
as an example.

![code](https://www.bigbinary.com/blog/images/images_used_in_blog/2024/evaluating-javascript-in-neeto-course/code1.png)

Now let's see the transformed code.

![transformed](https://www.bigbinary.com/blog/images/images_used_in_blog/2024/evaluating-javascript-in-neeto-course/transformed1.png)

Here `pushTologs` replaces the `console.log` function and `logsAggregator` is an
array that stores all the logs. We also replace `throw` statements with
`pushToLogs` to evaluate exceptions.

We also perform serialization to make comparison easier. The transformed code is
then ran as an
[IIFE](https://www.bigbinary.com/videos/learn-javascript/immediately-invoked-function-expression)
and the result is used for comparison.

We run the user submitted code in an iframe so that any bug in the submitted
code doesn't mess up the page.

## How code is transformed

Let's see how this "code transformation" works. We mentioned the use of an
[AST library](https://www.npmjs.com/package/abstract-syntax-tree). AST(abstract
syntax tree) is a tree representation of the code which helps the compiler to
understand the structure of the code. Let's use a tool called
[AST Explorer](https://astexplorer.net/) to see how the AST looks like for the
below code.

```js
const priceOfPencil = 5;

console.log("Price of 1 pencil:");
console.log(priceOfPencil);
```

![astexplorer](https://www.bigbinary.com/blog/images/images_used_in_blog/2024/evaluating-javascript-in-neeto-course/astexplorer-2.png)

Here, `MemberExpression` is a node and in that node we can use `object.name`.
See the underline highlights using pink color.

Using `object.name` we can get to value `console`. See the green arrow.

Similarly using `property.name` we can get to `log`.

Now our goal is to walk the tree and replace all `console.log` statements with
`pushToLogs` statement. For walking and replacing the value we will use the
`replace` function provided by the library.

```js
replace(tree, node => {
  const { callee } = node;

  // create the node that needs to be put instead of console.log
  const pushToLogsExpression = parse("pushToLogs()").body[0].expression;

  // check for the console.log node
  if (
    callee?.type === "MemberExpression" &&
    callee?.object?.name === "console" &&
    callee?.property?.name === "log"
  ) {
    pushToLogsExpression.arguments = node.arguments;
    node = pushToLogsExpression;
  }

  return node;
});
```

Here we are creating a new node by parsing the string `"pushToLogs()"`. We are
then adding the arguments of the `console.log` to the `pushToLogs` node. When we
return this new node, the code transformation is complete.

## Asynchronous code

Evaluating async code is a bit tricky since we won't get the output of the code
right away. What we do in this case is transform the code to make it
synchronous. For evaluating the output, these are the information we need:

1. Console logs
2. Exceptions
3. The order in which the code needs to be executed

We will transform the code in such a way that this information are available to
us. Let's see how the code is transformed in the following cases:

### SetTimeout / SetInterval

![code](https://www.bigbinary.com/blog/images/images_used_in_blog/2024/evaluating-javascript-in-neeto-course/code2.png)

![transformed](https://www.bigbinary.com/blog/images/images_used_in_blog/2024/evaluating-javascript-in-neeto-course/transformed2.png)

In this case the function that needs to be executed after the specified timeout
is executed inline. And the delay value is just added to the `logsAggregator`
for record keeping. There will be no delay in the evaluation.

We do the same for `setInterval`.

In both the cases we evaluate the function "inline" and then compare the
console.log outputs.

What if we want an exercise involving `clearTimeout` ? We simply add
`Timeout cleared` to the `logsAggregator`.

### Promises

![code](https://www.bigbinary.com/blog/images/images_used_in_blog/2024/evaluating-javascript-in-neeto-course/code3.png)

![transformed](https://www.bigbinary.com/blog/images/images_used_in_blog/2024/evaluating-javascript-in-neeto-course/transformed3.png)

Without going too much in details, to evaluate Promises all we did was move the
callbacks from the `then` method of the promise to the arguments of a function.

We handle `async/await` code in a similar style.

What happens in the case of promise chaining?

![code](https://www.bigbinary.com/blog/images/images_used_in_blog/2024/evaluating-javascript-in-neeto-course/code5.png)

![transformed](https://www.bigbinary.com/blog/images/images_used_in_blog/2024/evaluating-javascript-in-neeto-course/transformed5.png)

Here, if we detect that there are more than one `then` calls, then the second
body of `then` is passed as `resolveFn` to the function that the first `then`
returns. This can go multiple levels based on the chaining.

In other words, we go back to adding "callbacks".

This is how we evaluate JavaScript in NeetoCourse. We evaluate HTML, CSS and SQL
similarly on the browser. We have also recently added the evaluation of HTML
Canvas. Evaluation of HTML Canvas animations is on the roadmap. But these can be
a story for another day.

Want to see code evaluation in action. Checkout
[this question](https://courses.bigbinaryacademy.com/learn-javascript/challenges-set-4/find-second-largest-value-in-array/)
from our JavaScript course.

Interested to know more about NeetoCourse? Follow
[@NeetoCourse](https://twitter.com/NeetoCourse) to see what we're up to.

## Links

- [Human page](https://www.bigbinary.com/blog/evaluating-javascript-in-neeto-course)
