Monday, May 22, 2017

Javascript - Two properties to keep in mind when using block-scoped variables



let and const have some interesting properties other than their operating scope, this post discusses two of these that might save you some head-scratching.

They don't add properties to the global object

Unlike var, even in the global scope, block-scoped variables do not attach properties to the global object.

This might lead to something like this.

Code snippets in this post use node as their execution environment, replace "global" with "window" for the browser.

const c = "constantC";

console.log(global.c); // undefined

global.c = "globalC";

console.log(c); // Prints "constantC"
console.log(global.c); // Prints "globalC"

So, as you can see on line 7, whenever you refer to the variable name, Javascript gives you the const value. If you want the global property you reference it from the global object.

This can lead to the following weird scenario

v = "globalV";

console.log(v); // Prints "globalV"

const v = "constV"; // No problems at all

console.log(v); // Prints "constV"

console.log(global.v); // Still "globalV"

You can indeed, in the global scope, declare a const/let variable with the same name as a global variable (memory leak warning here).

As you know, var behavior is totally different in these scenarios.

A use case

imagine this..

You're stuck with a project with some messed up dependency injection, so one module assumes the other module is in the global scope and uses it directly (talking about old school IIFE mostly)..

When wanting to test that module in isolation is it often a pain to do so, you want to mock/ stub/ fake/ double/ whatever that module.

using the above property can make you set a tempoary global variable for use by the first module, then comes the real one and declare itself as a const in the global scope with no problems.

This, however will not help you re-order tests or run them in parallel, so it's always best to architect the code in the right way (obvious, but not always as easy as it sounds).


They have a temporal "dead zone"

Block-scoped variables will not hoist (In the way we're used to, anyway) to the top of the block, causing a temporal dead zone between the top of the block and variable initialization.

when a Var is defined in code, it is automatically initializaed with undefined, block-scoped variables do not follow the same behavior, which means that declaration and initialization phases are decoupled, which in turn causes an error thrown when trying to access the variable anywhere above its initialization line.

console.log(letV); // Throws an error: letV is not defined

let letV = 2;

A use case

Imagine you want to do something if some object is available to use, like if exports is present in the global scope, then attach members to it.

var exports = exports || null;
if (exports) {
  exports.thing = myThing;
}

This is something you can't do with a const or let without throwing an error.


That's it.

Hope that helped. Please share your thoughts in the comments.

Sunday, April 23, 2017

WebAssembly - sending a Javascript array to wasm for modification and getting back the modified version.



Alright so WebAssembly has hit the MVP and is enabled by default in more than one browser right now, so starting to use it makes sense.

One of the main functions of WebAssembly is to let it handle the heavy lifting part of the code.

This post is going to take you through sending an array to a 'wasm' function, make some crazy low level stuff on its elements and finally reflecting that change on the web page with Javascript.

Note that this post explains how to send an array that's already filled, which involves copying the elements into the WebAssembly memory space. In a lot of cases, though, you would want to skip the copying part and just build the array incrementally directly into the WebAssembly memory space (see the JS code near the end).

For the sake of simplicity, his post assumes that you are using C/C++ with Emscripten to generate the helper JS file.

C

Let's start at the C level (sorry)

#include <stdint.h>

int addThree(uint8_t *buf, int len) {
  uint8_t *item;
  uint8_t *end = buf + len;

  for (item = buf; item<end; item++) {
    *item += 3;
  }

  return 0;
}

Let's break things down..

On line 1, we include the stdint library which gives consistent operation across different machines.

On line 3, we define our function, it takes two parameters:

  • a pointer to the start address of the array in memory (which is technically the location of index 0). Array pointers have to be one byte in size.
  • and the number of elements in this array (to help us loop through the items).

We then define two pointers to the start and end location of the array in memory (it is safe to add together diffreent integer sizes).

We then loop through the array items and do the crazy stuff (like adding 3 to each element in this case) and just return 0 to say that we are done.

Look out for overflows, like in the above example, we have used the unsigned int8 integer to hold the data, which can store integers from 0 to 255, so adding a 3 to say a 253 will cause an overflow and get you into trouble.

Alright, One thing left, we've got to compile that code and export the addThree function.

assuming that you already have emcc into your PATH, compile the C file with this (I choose the name "freeThree.c", because it rhymes).

 emcc -o three.html freeThree.c -s WASM=1 -s EXPORTED_FUNCTIONS="['_addThree']"

Here we are just telling the compiler to use native WebAssembly (and not asm.js) and we tell it to expose the addThree function.

Notice the "_" before the function name, this is very important.


While we are here and before we go to the Javascript side of things, if you may have to pass large arrays to this function, consider making room for the extra memory.

one technique that I use is to use the ALLOW_MEMORY_GROWTH flag, run the web page, and keep an eye on the console, it's going to give you the a number every time is grows the memory. Note that when your app demands extra memory, the size of memory doubles rather than keping up with the exact demanded size, still you can get a nice approximation about what your maximum memory size should be. Add this to the end of the previous compile command after EXPORTED_FUNCTIONS="['_addThree']".

-s ALLOW_MEMORY_GROWTH=1

ALLOWMEMORYGROWTH prevents some optimizations that the compiler can make, so after you have decided that your app will use a maximum of X memory it's better to use that number for specifying the static memory of your app. So instead of the ALLOW_MEMORY_GROWTH flag, use this

-s TOTAL_MEMORY=X


Javascript

Now let's shift our focus to the Javascript level.

After you've run the above command, emscripten should have outputted a nice bloated three.html file with a .js file with the same name (along with the .wasm file itself), this .js file is gonna make our life a lot easier when dealing with the weird WebAssembly memory model.

We won't change anything in the script file, it's just our interface to the WebAssembly binary (.wasm file), it fetches, compiles and instantiate the wasm file and gives us a nice and clean Module object ready to be used.

Now open the three.html file and inside the first <script> tag, right before the closing </script> tag which is right above the other <script> tag (I hope this has clarified more than confused..), create a function with the following Javascript (you can use it as an event handler, or just shove it into the Mosule's postRun array, which is on around line 1226 in your three.html file, to run it as soon as the Module loads)

const myArray = new Uint8Array([100, 200, 250]);

const buffer = Module._malloc(myArray.length);
Module.HEAPU8.set(myArray, buffer);

Module.ccall('addThree', 'number', ['number', 'number'], [buffer, myArray.length]);

console.log(Module.HEAPU8.subarray(buffer, buffer+myArray.length));

Module._free(buffer);

Here's what's going on..

On line 1, we create our array that we wish to send to the C function for manipulation.

Please note that AFAIK (and according to the emscripten docs), you can only send Uint8Array or or Int8Array. If you have figured out a way to send other typed arrays please share it with us.

Then on line 3, we allocate enough memory (in bytes, it's just the length of the array here because each element is one byte in size) to hold our array elements.

We then actually copy the elements from the array into the buffer we have just created, which means that we are copying the data into the WebAssembly Module's memory space. While the module's memory is represented as a single ArrayBuffer, Module.HEAPU8 is the Uint8 view of that buffer, so it's just a normal Javascript typed array built around that buffer, so in turn, it has the set function.

After that we use the utility function ccall to call the C function, passing in the buffer to act as a pointer to the first element in the array.

ccall docs and other options of calling the C function can be found here.

Line 8 uses the subarray function to peek at the array items while they are sitting happily in their ArrayBuffer, you can use subarray or slice to deal with the modified elements. You can find more details here, but the bottom line is if you just wanna look at the elements or loop over them or the likes and then throw them, use subarray, it's way faster then slice.

Finally we must free up the allocated memory space (a la C malloc/free functions).


The catch

Copying the data (with set) takes time, if you have a huge array this can easily be your app's performance bottleneck.

Imagine you have a canvas that you want to manipulate which is 4000 in width and 3000 in height, this canvas has 4000*3000 pixels, which is 12 million pixels. Now you want to get the ImageData array to be processed by the fast C function, this array gives every pixel 4 entries, which is 4 bytes, now we have 48 million entries/bytes that we have to copy into the memory space of WebAssembly. On a modern machine this takes something close to 2 seconds!

So three's a tradeoff happening here, just be sure that copying the data isn't going to be your bottleneck (like, don't use it for adding 3 to the entries). If so, you better off doing it with Javascript, it would be a lot faster (You can also use workers to get some concurrency).


Hope that helps clear things up. please share your suggestions and questions below.

Thursday, April 13, 2017

Javascript typed arrays - slice vs subarray



What

Both of these TypedArrays' methods appear to do the same thing, except for a cool difference. Let's start with examples..

const a = new Uint8Array([1, 2, 3, 4]);

const b = a.slice(1, 3); // b becomes Uint8Array [ 2, 3 ]
const c = a.subarray(1, 3); // c becomes Uint8Array [ 2, 3 ]

Now let's see what happens when we change the values of these new arrays

b[0] = 5; // b is now Uint8Array [ 5, 3 ]
console.log(a); // Uint8Array [ 1, 2, 3, 4 ]

c[0] = 5; // c is now Uint8Array [ 5, 3 ]
console.log(a); // Uint8Array [ 1, 5, 3, 4 ]

See what happened at line 5? when we changed c, a has changed too, where on the other hand, b doesn't have the same effect, that's the difference.


Why

As you know, subarray exists only for typed arrays, that's the key to understand what's going on.

TypedArrays in javascript are represented in the memory as a single slab of bytes with the size reflecting the number of array items (if every item is one byte and the array has 3 items, then the memory taken is 3 bytes). Let's compare what slice does with what subarray does..

  • slice: Allocate a new space in memory and copy the items from the original array between the start and end indices provided in the arguments into these new memory locations, return the new array.
  • subarray: make a new empty typed array object, which points to a part of the original array between the start and end indices provided in the arguments.

So basically subarray lets a and c see and modify the same memory locations, it provides a smaller "view" (window) over the original array.

That makes subarray very fast compared to slice, because no copying is involved.


When

you can take advantage of this when you have a huge array that you want to convert a range of it into another type. One such situation that comes to mind is when the canvas demands a Uint8ClampedArray to draw its pixels.

const d = new Uint8ClampedArray(c);

the constructor sees c as a Uint8Array, because it really is an independent array which happens to look at the same memory location as a.

This gives you a new array d with the contents of a part of a without having to create an intermediate copy of the range that we want from a.


I hope I have managed to clear up the difference. feel free to ask questions, point out flaws and speak your mind in the comments.

Wednesday, March 15, 2017

Javascript - create fast lookup for string characters with this one-liner



This is another language shortcut, you may use it if you find yourself wanting to check if a string contains some character, and you want to do it fast, because it's inside a loop or something.

const stringy = "strings";

const stringLookup = new Set([...stringy]);

// stringLookup.has('s') === true

This is going to create a set, a hash-table-ish structure with all unique characters in the string.

The spread operator is creating an array from the string, which is essentially equivalent to stringy.split('').

So, stringLookup now has these entries { 's', 't', 'r', 'i', 'n', 'g' }.

View Set as a bag of unique elements, so it's most useful for quick character lookups.


A note about String.prototype.includes

This method uses the same algorithm used for String.prototype.indexOf, which in most implementations has an inside loop, which is not perfect for performance demanding apps.


I'm sure there are a lot of other ways, please share your favorite way of doing it in a comment.