#### Modern JavaScript Part 18: Everything new in ES2017

Sun Jun 03 2018 / book

ES2017 introduced many new cool features, which we are going to see here.

## String padding(`padStart` and `padEnd`)

We can now add some padding to our strings, either at the end (`padEnd`) or at the beginning (`padStart`) of them.

``````    "hello".padStart(6);
// " hello"
// "hello "``````

We specified that we want 6 as our padding, but why in both cases we got only 1 space? It happens because `padStart` and `padEnd` will go and fill the empty spaces. In our example "hello" is 5 letters, and our padding is 6, which leaves only 1 empty space. Look at this example:

``````    "hi".padStart(10);
// 10 - 2 = 8 empty spaces
// "        hi"
// 10 - 6 = 4 empty spaces
// "   welcome"``````

### Right align with `padStart`

We can use `padStart` if we want to right align something.

``````    const strings = ["short", "medium length", "very long string"];

const longestString = strings.sort(str => str.length)
.map(str => str.length)[0];

// very long string
//    medium length
//            short``````

First we grabbed the longest of our strings and measured its length. We then applied a `padStart` to all the strings based on the length of the longest so that we now have all of them perfectly aligned to the right.

We are not bound to just add a white space as a padding, we can pass both strings and numbers.

``````    "hello".padEnd(13," Alberto");
// "hello Alberto"
// "001"
// "099"``````

## `Object.entries()` and `Object.values()`

Let's first create an Object.

``````    const family = {
father: "Jonathan Kent",
mother: "Martha Kent",
son: "Clark Kent",
}``````

In previous versions of JavaScript we would have accessed the values inside the object like this:

``````    Object.keys(family);
// ["father", "mother", "son"]
family.father;
"Jonathan Kent"``````

`Object.keys()` returned us only the keys of the object that we then had to use to access the values. We now have two more ways of accessing our objects:

``````    Object.values(family);
// ["Jonathan Kent", "Martha Kent", "Clark Kent"]

Object.entries(family);
// ["father", "Jonathan Kent"]
// ["mother", "Martha Kent"]
// ["son", "Clark Kent"]``````

`Object.values()` returns an array of all the values whilst `Object.entries()` returns an array of arrays containing both keys and values.

## `Object.getOwnPropertyDescriptors()`

This method will return all the own property descriptors of an object. The attributes it can return are `value`, `writable`, `get`, `set`, `configurable` and `enumerable`.

``````    const myObj = {
name: "Alberto",
age: 25,
greet() {
console.log("hello");
},
}
Object.getOwnPropertyDescriptors(myObj);
// age:{value: 25, writable: true, enumerable: true, configurable: true}

// greet:{value: ƒ, writable: true, enumerable: true, configurable: true}

// name:{value: "Alberto", writable: true, enumerable: true, configurable: true}``````

## Trailing commas in function parameter lists and calls

This is just a minor change to a syntax. Now, when writing objects we need to leave a trailing comma after each parameter, whether or not it is the last one.

``````    // from this
const object = {
prop1: "prop",
prop2: "propop"
}

// to this
const object = {
prop1: "prop",
prop2: "propop",
}``````

Notice how I wrote a comma at the end of the second property. It will not throw any error if you don't put it, but it's a better practice to follow as it will make the life easier to your colleague or team members.

``````    // I write
const object = {
prop1: "prop",
prop2: "propop"
}

const object = {
prop1: "prop",
prop2: "propop"
prop3: "propopop"
}
// suddenly, he gets an error because he did not notice that I forgot to leave a comma at the end of the last parameter.``````

## Shared memory and `Atomics`

From MDN:

When memory is shared, multiple threads can read and write the same data in memory. Atomic operations make sure that predictable values are written and read, that operations are finished before the next operation starts and that operations are not interrupted.

`Atomics` is not a constructor, all of its properties and methods are static (just like `Math`) therefore we cannot use it with a new operator or invoke the `Atomics` object as a function. Examples of its methods are:

• and / or / xor

## Async and Await

ES2017 introduced a new way of working with promises, called "async/await".

## `Promise` review

Before we dive in this new syntax let's quickly review how we would usually write a promise:

``````    // fetch a user from github
fetch('api.github.com/user/AlbertoMontalesi').then( res => {
// return the data in json format
return res.json();
}).then(res => {
// if everything went well, print the data
console.log(res);
}).catch( err => {
// or print the error
console.log(err);
})``````

This is a very simple promise to fetch a user from GitHub and print it to the console. Let's see a different example:

``````    function walk(amount) {
return new Promise((resolve,reject) => {
if (amount < 500) {
reject ("the value is too small");
}
setTimeout(() => resolve(`you walked for \${amount}ms`),amount);
});
}

walk(1000).then(res => {
console.log(res);
return walk(500);
}).then(res => {
console.log(res);
return walk(700);
}).then(res => {
console.log(res);
return walk(800);
}).then(res => {
console.log(res);
return walk(100);
}).then(res => {
console.log(res);
return walk(400);
}).then(res => {
console.log(res);
return walk(600);
});

// you walked for 1000ms
// you walked for 500ms
// you walked for 700ms
// you walked for 800ms
// uncaught exception: the value is too small``````

Let's see how we can rewrite this `Promise` with the new async/await syntax.

## Async and Await

``````    function walk(amount) {
return new Promise((resolve,reject) => {
if (amount < 500) {
reject ("the value is too small");
}
setTimeout(() => resolve(`you walked for \${amount}ms`),amount);
});
}

// create an async function
async function go() {
// use the keyword `await` to wait for the response
const res = await walk(500);
console.log(res);
const res2 = await walk(900);
console.log(res2);
const res3 = await walk(600);
console.log(res3);
const res4 = await walk(700);
console.log(res4);
const res5 = await walk(400);
console.log(res5);
console.log("finished");
}

go();

// you walked for 500ms
// you walked for 900ms
// you walked for 600ms
// you walked for 700ms
// uncaught exception: the value is too small``````

Let's break down what we just did:

• to create an `async` function we need to put the `async` keyword in front of it
• the keyword will tell JavaScript to always return a promise
• if we specify to `return <non-promise>` it will return a value wrapped inside a promise
• the `await` keyword only works inside an `async` function.
• as the name implies, `await` will tell JavaScript to wait until the promise returns its result

Let's see what happens if we try to use `await` outside an `async` function

``````    // use await inside a normal function
function func() {
let promise = Promise.resolve(1);
let result = await promise;
}
func();
// SyntaxError: await is only valid in async functions and async generators

// use await in the top-level code
let response = Promise.resolve("hi");
let result = await response;
// SyntaxError: await is only valid in async functions and async generators``````

Remember that you can only use `await` inside an `async` function.

## Error handling

In a normal promise we would use `.catch()` to catch eventual errors returned by the promise. Here, it is not much different:

``````    async function asyncFunc() {

try {
let response = await fetch('http:your-url');
} catch(err) {
console.log(err);
}
}

asyncFunc();
// TypeError: failed to fetch``````

We use `try...catch` to grab the error, but in a case where we do not have them we can still catch the error like this:

``````    async function asyncFunc(){
let response = await fetch('http:your-url');
}
asyncFunc();
// Uncaught (in promise) TypeError: Failed to fetch

asyncFunc().catch(console.log);
// TypeError: Failed to fetch``````