Friday, December 15, 2017

My JavaScript Deity

Today, my JavaScript deity gave us an important lesson on JavaScript Promises. To help myself revise and also share the learning with potential disciples, I will summarize his teachings:

(Warning: Some grammar / terminology might sound wonky, that is because I might not be too sure how to express the actual subject.)

Before we define promises, let us look at asynchronous (async) versus synchronous (sync). When an operation is sync, it literally means sync and you have to ensure the atomic operations inside the sync operation is sequential, and in the order of how you actually write the operation.

So, let's say we have some synchronous arithmetic operations:

let x = 1
x += 1
let y = 1
console.log(y + x)

Since these operations are sync, you evaluate them line-by-line. No concurrent evaluations. So the expected answer is 3.

On the other hand, an async operation allows concurrent / out-of-order evaluations. My understand is that JavaScript is ultimately single-threaded, so a "concurrent" evaluation would be switching between threads quickly (like context switching). Each atomic operation is on a thread, and async means the control thread gets switched around, and it will then seem as if the operations are running in parallel.

As such, in the above example, there might be a possibility where x += 1 becomes the last line to finish executing, and that would mean this async counterpart could be printing 2 instead of 3. Sometimes 3, though. Whether it is 2 or 3 will depend on the computing resource itself already.

Now we are ready to define promises.

What is a Promise? You can see it as an outcome of an async operation. I am not sure how semantically sensible it is to you, but isn't a promise literally a promise? Promise to do an operation.

A Promise can be in any 1 of the 3 states: Resolved, rejected, waiting. So while you return a Promise, the promise itself might still be executing halfway, but the state will be updated accordingly. A Promise is a representation of these states. (IMO, this is the most concrete/tangible definition to me, compared to the definition in the previous paragraph, which is just high-level.)

Resolved is equivalent to success, rejected is equivalent to failure, waiting is just... waiting to be executed.

Why Promises? I have not went on to read that. My personal understanding would be to not block (probably just one reason out of the many). Synchronous operations will block until that particular line is done. Let's say we have a disk reading operation, and we make it sync. After that, we have a simple function, say, a "Hello, world" printing. If the disk reading is sync, we have to wait until the entire reading is done (possibly seconds, minutes, etc.) before we see "Hello, world". This means the printing is being blocked. However, by making the reading operation async, we can run the disk reading in the background (or sometimes becoming the control thread) while we make some time to print "Hello, world" sooner. Now we only have to wait milliseconds, or even just nanoseconds.

Okay, let's move on to legitimate teachings instead of my personal ramblings.

In JavaScript, we have stuff like:

1. Promise.all()
2. .then()
3. async
4. await

Promise.all() accepts an iterable (e.g. array) of promises and is resolved only when every element is resolved. However, within the iterable, it is all async and you will have no idea which element will finish resolving / rejecting first.

.then() accepts a function that executes only after the initial promise (before the dot) is either resolved or rejected. Sounds like a callback. But callbacks are less flexible than promises. Callbacks literally call you back and you have to handle the results from the initial async operation immediately in the callback function. For promises, we can handle the results anywhere after, like in this example:


As for async and await keywords, the documentation says:

The await operator is used to wait for a Promise. It can only be used inside an async function.

As such, when we have an await, the entire function will stop its concurrent executions until the awaited expression is completed.

For example, in an imaginary async function, we have the following expressions:

await Promise.all([A, B, C])
await D
await Promise.all([E, F, G])

A, B, C will first run concurrently. After all A, B, C are done, then D is run. E, F, G will run concurrently only after D finishes. However, in the below scenario, it is possible for D2 to finish before D1 as D1 and D2 are run asynchronously.

await Promise.all([A, B, C])
D1
D2
await Promise.all([E, F, G])

With that, I will wrap up my summary with one last question and answer: Why did this lesson even happen? It happened because I wanted to write a migration file that does some database operations synchronously (while some can remain asynchronous).

After writing the proper async functions and await expressions, I will have to look into possible database / logic errors that might cause the failure of this migration. This migration involves moving of data / records. My friend strongly recommended the conversion of migration to a transaction. This is so that the migration cannot fail "halfway" and can neither re-run or rollback properly (database operations are not pure).

Wednesday, December 06, 2017

Request instead of release (module reviews)

I have been lazy and I did not write any module reviews for the past 3 semesters. I would be willing to share if there is demand in the first place. I took the following modules, and I will label whether I was OK or died for the module. However, note that I am actually disappointed with some of the OK, but I did not die in the module (e.g. B+ so I probably got axed by the finals). Some examples of dying: Failing continual assessments / mid-terms or getting B and below.

Modules taken in AY16/17 Semester 1:

  1. CS2101 Effective Communication for Computing Professionals (OK)
  2. CS2103T Software Engineering (died)
  3. CS2309 CS Research Methodology (OK)
  4. CS3244 Machine Learning (OK)
  5. IS1103 Computing and Society (OK)

Modules taken in AY16/17 Semester 2:

  1. CS2106 Introduction to Operating Systems (OK)
  2. CS2107 Introduction to Information Security (OK)
  3. CS3230 Design and Analysis of Algorithms (OK)
  4. CS3243 Introducton to Artificial Intelligence (died)
  5. GET1006 Critical Thinking in the Information Age (OK)

Modules taken in AY17/18 Semester 1:

  1. CP3208 Undergraduate Research Opportunities Programme (UROP) (died)
  2. CS2104 Programming Language Concepts (OK)
  3. CS2105 Introduction to Computer Networking (OK)
  4. CS3216 Software Product Engineering for Digital Markets (OK)
  5. CS3230R Design and Analysis of Algorithms (died)
  6. CS4248 Natural Language Processing (died)