Posts

Showing posts with the label javascript

ES proposal: Shared memory and atomics

The ECMAScript proposal “ Shared memory and atomics ” by Lars T. Hansen has reached stage 4 this week and will be part of ECMAScript 2017. It introduces a new constructor SharedArrayBuffer and a namespace object Atomics with helper functions. This blog post explains the details. Parallelism vs. concurrency Before we begin, let’s clarify two terms that are similar, yet distinct: “parallelism” and “concurrency”. Many definitions for them exist; I’m using them as follows: Parallelism (parallel vs. serial): execute multiple tasks simultaneously Concurrency (concurrent vs. sequential): execute several tasks during overlapping periods of time (and not one after another). Both are closely related, but not the same: Parallelism without concurrency: single instruction, multiple data (SIMD). Multiple computations happen in parallel, but only a single task (instruction) is executed at any given moment. Concurrency without parallelism: multitasking via time-sharing on a single-core CPU. However,...

Making transpiled ES modules more spec-compliant

In this blog post, you’ll learn: How a proposed “spec mode” for Babel makes transpiled ES modules more spec-compliant. That’s a crucial step in preparing for native ES modules. How ES modules and CommonJS modules will interoperate on Node.js. How far along ES module support is on browsers and Node.js. Transpiling ES modules to CommonJS via Babel At the moment, the main way to use ES modules on Node.js and browsers is to transpile them to CommonJS modules via Babel. The benefit of this approach is that integration with the CommonJS ecosystem, including npm modules, is seamless. On the flip side, the code that Babel currently generates does not comply with the ECMAScript specification. That is a problem, because code that works with Babel now, won’t work as native modules. That’s why Diogo Franco has created a pull request that adds a so-called “spec mode” to transform-es2015-modules-commonjs . Modules transpiled in this mode conform as closely to the spec as is possible without using E...

Communicating between Web Workers via MessageChannel

Occasionally, you want Web Workers to communicate with each other. Doing so is not obvious as most Web Worker examples are about communicating between the main thread and a Web Worker. There, one uses postMessage() to send messages directly to the Worker. Alas, that doesn’t work for communicating between two Workers, because you can’t pass references to Workers around. MessageChannel The solution is to establish a channel between the Workers: const channel = new MessageChannel(); receivingWorker.postMessage({port: channel.port1}, [channel.port1]); sendingWorker.postMessage({port: channel.port2}, [channel.port2]); We are creating a new MessageChannel and sending references to its two ports to two Workers. Every port can both send and receive messages. Note the second parameter of postMessage() : It specifies that channel.port1 and channel.port2 should be transfered (not copied) to the Workers. We can do that because MessagePort implements the interface Transferable . Po...

ES proposal: import() – dynamically importing ES modules

The ECMAScript proposal “ import() ” by Domenic Denicola is currently at stage 3. It enables dynamic loading of ECMAScript modules and is explained in this blog post. ECMAScript modules are static ECMAScript modules are completely static: you must specify what you import and export at compile time and can’t react to changes at runtime. That has several advantages, especially w.r.t. tooling, which are explained in “Exploring ES6”. The static structure of imports is enforced syntactically in two ways. Consider the following example: import * as someModule from './dir/someModule.js'; First, this import declaration can only appear at the top level of a module. That prevents you from importing modules inside an if statement or inside an event handler. Second, the module specifier './dir/someModule.js' is fixed; you can’t compute it at runtime (via a function call etc.). The proposal enables dynamic module imports The proposed operator for loading modules dynamically w...

Controlling access to global variables via an ES6 proxy

The following function evalCode() traces the global variables that are accessed while evaluating a piece of JavaScript code. // Simple solution const _glob = typeof global !== 'undefined' ? global : self; function evalCode(code) { const func = new Function ('proxy', `with (proxy) {${code}}`); // (A) const proxy = new Proxy(_glob, { get(target, propKey, receiver) { console.log(`GET ${String(propKey)}`); // (B) return Reflect.get(target, propKey, receiver); }, set(target, propKey, value, receiver) { // (C) console.log(`SET ${String(propKey)}=${value}`); return Reflect.set(target, propKey, value, receiver); }, }); return func(proxy); } The way this works is as follows: The with statement wrapped around the code (line A) means that every variable access that “leaves” the scope of the code becomes a ...

Why does this work? [].concat[1,2,3]

In this blog post, we look at a syntactic puzzle. This is just for fun; there is nothing useful you can do with what we examine. It may, however, make you more aware of how JavaScript works, syntactically. Question What do you need to do to get the following result? And why does it work? > [].concat[1,2,3] [ 1, 2, 3 ] Answer This expression looks very similar to: [].concat([1,2,3]) But, actually, something completely different is going on: First, the result of [].concat is computed. The result is the function stored in Array.prototype.concat . Then the operand of the square bracket operator is evaluated. It consists of the comma operator (in this context, the comma is an operator, like + ) applied to three numbers: > 1,2,3 3 Lastly, property '3' of the function returned by [].concat is accessed. Normally, that produces undefined : > [].concat[1,2,3] undefined If, however, you make the following assignment, you’ll get the result shown at ...

Pitfall: not all objects can be wrapped transparently by proxies

A proxy object can be seen as intercepting operations performed on its target object – the proxy wraps the target. The proxy’s handler object is like an observer or listener for the proxy. It specifies which operations should be intercepted by implementing corresponding methods ( get for reading a property, etc.). If the handler method for an operation is missing then that operation is not intercepted. It is simply forwarded to the target. Therefore, if the handler is the empty object, the proxy should transparently wrap the target. Alas, that doesn’t always work, as this blog post explains. Wrapping an object affects this Before we dig deeper, let’s quickly review how wrapping a target affects this : const target = { foo() { return { thisIsTarget: this === target, thisIsProxy: this === proxy, }; } }; const handler = {}; const proxy = new Proxy(target, handler); If you call target.foo() directly,...

Computing tag functions for ES6 template literals

This blog post describes what you can do with functions that return tag functions for ES6 template literals. For an introduction to template literals, tagged template literals and tag functions, consult chapter “ Template literals ” in “Exploring ES6”. Calling values via template literals The common way of calling a value in JavaScript is to append arguments in parentheses: > const value = x => x; > value(123) 123 In ES6, you can additionally call values via template literals: > value`abc` [ 'abc' ] value is now a tag function whose first parameter is an Array with template strings and whose remaining parameters are the substitutions. Functions that return tag functions If the value you call via a template literal is a function that returns a tag function then you can use arguments for the former function to parameterize the latter function. For example: In the following interaction, repeat(x) returns a tag function that repeats its template li...

Three ways of understanding Promises

This blog post covers three ways of understanding Promises . This is an example of invoking a Promise-based function asyncFunc() : function asyncFunc() { return new Promise((resolve, reject) => { setTimeout(() => resolve('DONE'), 100); }); } asyncFunc() .then(x => console.log('Result: '+x)); // Output: // Result: DONE So what is a Promise? Conceptually, invoking asyncFunc() is a blocking function call. A Promise is both a container for a value and an event emitter. Conceptually: calling a Promise-based function is blocking function asyncFunc() { return new Promise((resolve, reject) => { setTimeout(() => resolve('DONE'), 100); }); } async function main() { const x = await asyncFunc(); // (A) console.log('Result: '+x); // Same as: // asyncFunc() // .then(x => console.log('Result: '+x)); }...

Tips for using async functions (ES2017)

This blog post gives tips for using async functions. If you are unfamiliar with them, you can read chapter “ Async functions ” in “Exploring ES2016 and ES2017”. Know your Promises The foundation of async functions is Promises . That’s why understanding the latter is crucial for understanding the former. Especially when connecting old code that isn’t based on Promises with async functions, you often have no choice but to use Promises directly. For example, this is a “promisified” version of XMLHttpRequest : function httpGet(url, responseType="") { return new Promise( function (resolve, reject) { const request = new XMLHttpRequest(); request.onload = function () { if (this.status === 200) { // Success resolve(this.response); } else { // Something went wrong (404 etc.) reject(new Error(this...