Categories
Modern JavaScript

Best of Modern JavaScript — Composing Promises

Since 2015, JavaScript has improved immensely.

It’s much more pleasant to use it now than ever.

In this article, we’ll look at handling JavaScript promise exceptions.

Handling Exceptions in Promise-Based Functions

We can handle exceptions in promise-based functions.

If exceptions are thrown in then and catch callbacks, then the methods convert them into rejections.

However, if we run the synchronous code before the promise code, then the whole function throws an exception.

This may be a problem that we want to solve.

One way to solve this is to surround the synchronous and promise code with try-catch.

For example, we can write:

function foo() {
  try {
    syncFn();
    return asyncFn()
      .then(result => {
        //...
      });
  } catch (err) {
    return Promise.reject(err);
  }
}

We have the foo function with the try-catch block which runs syncFn first and then asyncFn which returns a promise.

We return the promise chain in the try block.

And if the catch block is run, then we return a rejected promise.

This lets us keep the function async all the way through.

Run the Synchronous Code in the Callback

We can also run the synchronous code in the callback.

For instance, we can write:

function foo() {
  return asyncFn()
    .then(result => {
      syncFn();
      return asyncFn2();
    })
    .then(result => {
      //...
    });
}

If the synchronous syncFn functions run in the then callback and it throws an exception, then the returned promise will be rejected.

The start of the promise chain can also be in the Promise constructor.

For example, we can write:

function foo() {
  return new Promise((resolve, reject) => {
      syncFn();
      resolve(asyncFn());
    })
    .then(result => {
      //...
    });
}

We run syncFn in the Promise constructor callback so that we run the callback so that exceptions will be propagated if an error is thrown by syncFn .

Composing Promises

We can run multiple promises in various ways.

If we want to run multiple unrelated promises in parallel, we can use the Promise.all method.

For example, we can write:

Promise.all([
    asyncFn1(),
    asyncFn2(),
  ])
  .then(([result1, result2]) => {
    //...
  })
  .catch(err => {
    //...
  });

We pass in an array of promise-returning functions.

Then we pass that in Promise.all .

And then we call then with a callback that has an array of the resolved values of both values.

Then we call catch to catch the errors occurring with them.

We can loop through the resolved items with them.

For example, we can write:

Promise.all([
    asyncFn1(),
    asyncFn2(),
  ])
  .then((results) => {
    for (const result of results) {
      console.log(result);
    }
  })
  .catch(err => {
    //...
  });

We get the results array and looped through it with the for-of loop.

Promise.race()

Promise.race is another method to chain promises.

It takes an array of promises and returns a promise that’s resolved to the value of the promise that’s resolved first.

For example, we can write:

Promise.race([
    asyncFn(),
    delay(3000).then(function() {
      throw new Error('timed out')
    })
  ])
  .then(function(text) {
    //...
  })
  .catch(function(reason) {
    //...
  });

We have an array of promises with the asyncFn and delay which both return promises.

Then we call then with a callback to get the resolved value from the promise that’s resolved the earliest.

Conclusion

We can handle errors with promise-based functions in a few ways.

Also, we can run multiple promises in many different ways.

Categories
Modern JavaScript

Best of Modern JavaScript — Yield

Since 2015, JavaScript has improved immensely.

It’s much more pleasant to use it now than ever.

In this article, we’ll look at JavaScript generators.

The yield Keyword

The yield keyword can only be used in generator functions.

For example, we can write:

function* genFn() {
  yield 'foo';
  yield 'bar';
  return 'baz';
}

But we can’t write:

function* genFn() {
  ['foo', 'bar'].forEach(x => yield x);
}

We’ll get a syntax error.

Recursion with yield*

The yield* keyword lets us call another generator function within a generator function.

For instance, we can write:

function* genFn() {
  yield 'foo';
  yield 'bar';
  yield 'baz';
}

function* bar() {
  yield 'x';
  yield* genFn();
  yield 'y';
}

const gen = bar()

to call the genFn generator function within the bar generator function.

So if we use it by writing:

const arr = [...gen];

then arr is [“x”, “foo”, “bar”, “baz”, “y”] .

Calling genFn returns an object but it doesn’t run genFn .

The yield* keyword runs the generator function when it’s time for its items to be yielded.

yield* Considers End-of-Iteration Values

yield* ignores return values.

For example, if we have:

function* genFn() {
  yield 'foo';
  yield 'bar';
  return 'baz';
}

function* bar() {
  yield 'x';
  yield* genFn();
  yield 'y';
}

const gen = bar()
const arr = [...gen];

Then arr is [“x”, “foo”, “bar”, “y”] , yield* skipped over 'baz' since it’s returned instead of yield.

We can use yield* to recursively call generator functions.

So we can easily use it to return items from a tree structure.

For instance, we can create a Tree class with various branch nodes:

class Tree {
  constructor(value, left = null, center = null, right = null) {
    this.value = value;
    this.left = left;
    this.center = center;
    this.right = right;
  }

  *[Symbol.iterator]() {
    yield this.value;
    if (this.left) {
      yield* this.left;
    }

    if (this.center) {
      yield* this.center;
    }

    if (this.right) {
      yield* this.right;
    }
  }
}

left , center , and right are all generator functions created from the Tree class.

So we can write:

const tree = new Tree('a',
  new Tree('b',
    new Tree('c'),
    new Tree('d'),
    new Tree('e')),
  new Tree('f'));

for (const x of tree) {
  console.log(x);
}

And we get:

a
b
c
d
e
f

The value is the value for the tree node itself.

And we populate the nodes with the Tree constructor.

Generators as Observers

Generators can also be data observers.

We use it to send values with the next method.

The next method keeps returning values from then generator until the values run out.

For instance, if we have:

function* genFn() {
  yield 'foo';
  yield 'bar';
  return 'baz';
}

const gen = genFn();
console.log(gen.next());

And we get:

{value: "foo", done: false}

We can also call next with an argument to return that index of what’s yielded with the generator.

For example, we can write:

function* genFn() {
  console.log(yield);
  console.log(yield);
  console.log(yield);
}

const gen = genFn();
console.log(gen.next('a'));
console.log(gen.next('b'));
console.log(gen.next('c'));

We use the yield keyword to get the value passed in from the argument we passed into next .

The value return from the next method is:

{value: undefined, done: false}

value is undefined and done is false .

yield keyword without an operand gets the value from the next method.

Conclusion

The yield and yield* keyword have many uses.

yield can return values and also takes them from the next method.

Categories
Modern JavaScript

Best of Modern JavaScript — Regex y Flag

Since 2015, JavaScript has improved immensely.

It’s much more pleasant to use it now than ever.

In this article, we’ll look at new JavaScript regex features.

Search and the y Flag

The String.prototype.search method ignores the y flag.

lastIndex isn’t changed by it.

For example, if we have:

const REGEX = /foo/y;

REGEX.lastIndex = 8;
const match = 'barfoobarfoo'.search(REGEX);
console.log(match.index);
console.log(REGEX.lastIndex);

Then match us undefined and lastIndex stays at 8.

We can only search from the beginning of the string with it.

The String.prototype.match works differently depending on whether the g flag is added with y .

If g isn’t, it works like exec .

If g is set, then it returns an array with string parts that’s matched or null .

For instance, if we write:

const REGEX = /a/;

REGEX.lastIndex = 7;
console.log('abab'.match(REGEX).index);
console.log(REGEX.lastIndex);

Then indx is 0, and lastIndex is 7.

It gets the first if no flag is added.

If we add the y flag:

const REGEX = /a/y;

REGEX.lastIndex = 2;
console.log('abab'.match(REGEX).index);
console.log(REGEX.lastIndex);

Then the match is only returned if the search starts from the lastIndex .

The index must be exact.

lastIndex will then be updated after the match is found.

If the g flag is set, then match will match all the substrings and put them in the array.

For example, we can write:

const REGEX = /a|b/g;

REGEX.lastIndex = 0;
console.log('abab'.match(REGEX));
console.log(REGEX.lastIndex);

And match returns [“a”, “b”, “a”, “b”] .

lastIndex is still 0.

lastIndex is ignored with the g flag enabled.

The result is the same with the gy flags added.

match and lastIndex all give us the same result.

Split Strings

String.prototype.split method lets us split a string.

The y flag will make the method’s behavior change.

For example, we can write:

console.log('abb'.split(/b/y))
console.log('bba'.split(/b/y))

The strings will be split with b as the separator.

So we get:

["a", "", ""]

and

["", "", "a"]

The y flag works regardless of the location of the flag.

We can also put the pattern in a capturing group:

console.log('abb'.split(/(b)/y))

Then we get:

["a", "b", "", "b", ""]

as the result.

Replace Strings

TheString.prototype.replace method lets us replace strings by matching them with a regex.

For instance, if we write:

const REGEX = /a/;
console.log('baba'.replace(REGEX, 'x'));

Then we get 'bxba’ logged.

It only logs the first entry that’s matched.

If the y flag is added, we also get at most one match.

But the match is always searched from the beginning of the string.

For example, if we have:

const REGEX = /a/y;
REGEX.lastIndex = 2;
console.log('baba'.replace(REGEX, 'x'));

Then we get 'baba’ logged.

If the lastIndex is beyond the first match, then it’ll be ignored even if there’s a match available.

With the g flag, the replace replaces all matches.

So, if we have:

const REGEX = /a/g;
REGEX.lastIndex = 2;
console.log('baba'.replace(REGEX, 'x'));

Then we get 'bxbx' logged.

If we combine the g and y flags:

const REGEX = /a/gy;
console.log('baba'.replace(REGEX, 'x'));

Then 'baba’ is returned from the replace method.

But if we have:

const REGEX = /a/gy;
console.log('aaba'.replace(REGEX, 'x'));

Then we get ‘xxba’ . This means that the first match must be at the beginning of the string for replace to work.

Conclusion

The y flag is a new flag introduced with ES6 which works differently with different methods.

Categories
Modern JavaScript

Best of Modern JavaScript — Regex u Flag and Timers

Since 2015, JavaScript has improved immensely.

It’s much more pleasant to use it now than ever.

In this article, we’ll look at new JavaScript regex features and timers.

The u Flag

The u flag is another flag that’s introduced with ES6.

It switches on Unicode mode for regexes.

The most can recognize Unicode point escape sequences like u{094F} in our regex.

Also, characters in the regex pattern and the string are also recognized as code points.

Code units are converted into code points.

In non-Unicode mode, a lone surrogate matches surrogate pair code points.

For example, if we have:

/uD83D/.test("uD83DuDC2B")

We get true returned.

With Unicode mode on, this will return false since the 2 code points should be put together to create one character.

So /uD83D/u.test(“uD83DuDC2B”) returns false .

Actual lone surrogates are still matched with the u flag on:

/uD83D/u.test("uD83D uD83DuDC2B")

So the expression above returns true .

This means that 2 code points together will be interpreted as the one correct character in Unicode mode.

The dor operator will match code points instead of code units.

For instance:

'uD83DuDC2B'.match(/./gu).length

returns .

But:

'uD83DuDC2B'.match(/./g).length

returns 2.

In Unicode mode, quantifiers apply to code points.

But in non-Unicode mode, they apply to single code units.

So if we have:

/uD83DuDC2B{2}/u.test("uD83DuDC2BuD83DuDC2B")

This will return true .

But:

/uD83DuDC2B{2}/.test("uD83DuDC2BuD83DuDC2B")

returns false .

flags Property

The flags property is a new property of a regex object.

It returns the flags that’s added to the regex.

For example, if we have:

/foo/gy.flags

We get “gy” .

We can’t change the flags of an existing regex.

But we can use the flags property to make a copy of a regex with the flags.

For instance, we can write:

const regex = /foo/gy
const copy = new RegExp(regex.source, regex.flags);

The source property has the regex pattern.

And flags has the flags.

RegExp Constructor

The RegExp constrictor is useful for copying regexes as we can see.

It takes the pattern and the flags.

String Methods that Delegate to Regex Methods

Some string instance methods delegate to regex instance methods.

They’re:

  • String.prototype.match calls RegExp.prototype[Symbol.match]
  • String.prototype.replace calls RegExp.prototype[Symbol.replace]
  • String.prototype.search calls RegExp.prototype[Symbol.search]
  • String.prototype.split calls RegExp.prototype[Symbol.split]

Async Programming

JavaScript has extensive async programming features.

Each browser tab runs in a single process called the event loop.

The loop runs browser-related things that’s fed via the task queue.

Tasks include parsing HTML, running JavaScript code, listening to user input, and more.

Timers

JavaScript has the setTimeout to delay the execution of a piece of code.

It takes a callback to run the code after a given delay.

The first argument is the callback to run.

And the 2nd is the number milliseconds after now to add the callback to the queue.

Once it’s called, the callback is added to the task queue.

The delay specifies when the callback is added, not when it actually runs.

This may happen later.

DOM Changes

DOM changes don’t happen immediately.

It happens every 16ms.

Conclusion

The u flag lets us enable Unicode mode to let us search for Unicode strings properly.

setTimeout lets us run code with a delay.

Categories
Modern JavaScript

Best of Modern JavaScript — Promises

Since 2015, JavaScript has improved immensely.

It’s much more pleasant to use it now than ever.

In this article, we’ll look at JavaScript promises.

Benefits of Promises

Promises are chained.

And they look similar to synchronous code.

For example, we can write:

asyncFunction(arg)  
  .then(result1 => {  
    console.log(result1);  
    return asyncFunction2(x, y);  
  })  
  .then(result2 => {  
    console.log(result2);  
  });

We return a promise in the then callback to let us call then again.

Chaining is also simple since we just call then until we’re done with running the promises we want.

Composing async calls is easier since we can do the chaining.

Error handling can be done with the catch method.

For instance, we can write:

asyncFunction(arg)  
  .then(result1 => {  
    console.log(result1);  
    return asyncFunction2(x, y);  
  })  
  .then(result2 => {  
    console.log(result2);  
  })  
  .catch(error => {  
    console.log(error);  
  })

The catch method takes a callback that has an error parameter.

So we can do whatever we want with them inside the callback.

The function signatures are clear and we can see the parameters easily.

Promises is also a standard way to write async code.

Before promises are introduced to ES6 as a native features, there’re many libraries that implement the same thing.

But now, ES6 makes promises standard so we can use it anywhere.

Creating Promises

To create a promise, we can use the Promise constructor.

For instance, we can write:

new Promise((resolve, reject) => {  
  setTimeout(() => resolve('DONE'), 100);  
});

We use the constructor with a function that takes the resolve and reject parameters.

resolve is a function that’s called to return the value when it succeeds.

reject is a function that’s called to return the reason why the promise fails.

A promise is a container for value and an event emitter.

Promises looks like synchronous code, but they’re non-blocking.

They can’t return anything synchronously.

ES6 introduced a way for us to suspend and resume code with generators.

Therefore, this is used as the foundation for promises and async functions in JavaScript.

For instance, if we have:”

async function main() {  
  const x = await asyncFunc();  
  console.log(x);  
  //...  
}  
main();

asyncFunc returns a promise and runs the console log after the function is called.

await is like yield in JavaScript generator functions.

It does the same thing. It pauses the code and then continues running when the result is retrieved.

Using Promises

Promises have 3 states.

They can be pending, fulfilled, or rejected.

Pending means that the result hasn’t been computed.

Fulfilled means the result was computed successfully.

Rejected means a failure occurred during computation.

The parameter we pass into the Promise constructor is called an executor.

In addition to calling reject to make a promise fail, we can also reject a promise with an exception.

Consuming a Promise

To consume a promise, we can call then to get the resolved result from a promise.

The callback we pass into then takes the resolved results of a promise.

catch takes a callback which takes the argument we passed into reject .

For example, we can write:

promise  
  .then(value => {  
    //...  
  })  
  .catch(error => {  
    //...  
  });

value has the resolved value of promise .

error has the rejected value.

then can also take 2 arguments.

One is the resolved callback and the 2nd argument is the rejected callback.

So we can also catch errors by writing:

promise.then(  
  null,  
  error => {  
    //...  
  });

The 2nd argument is the same as the catch callback and catches the error of the promise.

Conclusion

Promises have many benefits, and we can create and consume them in a standard way.