This repository is a self reference readme guide to ES6.
- A function executes until it reaches a return or end of the function.
- An ES6 generator can be used to pause or resume at arbitary points inside the function.
- To create a generator we place an '*' after the function keyword.
function* Kakarot()
- When we call a generator
Kakarot()
it returns an instance of itself and doesn't execute itself. - To execute, we assign the generator to a variable and call the
next()
on the variable, which executes until the next block is over.
function* CallKakarot() {
console.log('Super saiyan God!');
}
const kakarot = CallKakarot();
kakarot.next();
- To pause a generator we use
yield
keyword. - To execute the second block, (ie) the block after the
yield
keyword, we again callnext()
- We can have as many as
yield
inside the generator.
function* CallKakarot() {
console.log('Super saiyan!');
yield
console.log('Super saiyan God!');
}
const kakarot = CallKakarot();
kakarot.next();
kakarot.next();
- We can pass message from an instance of a generator to a generator and vice versa
- Calling
next()
returns an object with propertiesvalue
anddone
.value
holds the passed data anddone
denotes whether the generator is done with the execution or not.
/* Pass from an instance to a generator */
function* CallKakarot() {
const message = yield
console.log(`Message to Kakarot: ${message}`);
}
const kakarot = CallKakarot();
// { value: undefined, done: false }
console.log(kakarot.next());
// Message to Kakarot: A new threat is approaching!
// { value: undefined, done: true }
console.log(kakarot.next('A new threat is approaching!'));
/* Pass from a generator to an instance */
function* CallKakarot() {
yield 'Kame hame ha!'
}
const kakarot = CallKakarot();
// { value: 'Kame hame ha!', done: false }
console.log(kakarot.next());
// { value: undefined, done: true }
console.log(kakarot.next());
- Generators looks like synchronous code, but it is actually asynchronous. We can do multiple asynchronous work between the blocks before resuming.
- Because of
yield
keyword we can pause and resume at arbitary points, there are chances where arbitary amount of things may go wrong between different blocks. - If something goes wrong between the first and second
next()
, we can usethrow()
to throw an error inside the generator where it is paused.
function* CallKakarot() {
const message = yield
console.log(`A message to Kakarot: ${message}`);
}
const kakarot = CallKakarot();
kakarot.next();
/* Our app will crash without a try-catch block */
// const message = yield
// ^
// undefined
kakarot.throw();
function* CallKakarot() {
try {
const message = yield
console.log(`A message to Kakarot: ${message}`);
} catch(e) {
console.log(`Error Message: ${e}`);
}
}
const kakarot = CallKakarot();
kakarot.next();
// Error Message: Kakarot is not in Earth right now!
kakarot.throw('Kakarot is not in Earth right now!');
- To get different values from generator, we can call
next()
multiple times untildone
is true or use awhile
to loop through. - We can prevent the ugliness of calling the
next()
multiple times by usingfor...of
loop in ES6. for...of
loop pauses and resumes the generator dramatically and passes on the value yielded by the generator.
function* CallKakarot() {
yield '1st try'
yield '2nd try'
yield '3rd try'
yield '4th try'
}
const kakarot = CallKakarot();
// { value: '1st try', done: false }
console.log(kakarot.next());
// { value: '2nd try', done: false }
console.log(kakarot.next());
// { value: '3rd try', done: false }
console.log(kakarot.next());
// { value: '4th try', done: false }
console.log(kakarot.next());
// { value: undefined, done: true }
console.log(kakarot.next());
function* CallKakarot() {
yield '1st try'
yield '2nd try'
yield '3rd try'
yield '4th try'
}
const kakarot = CallKakarot();
let next = kakarot.next();
// 1st try
// 2nd try
// 3rd try
// 4th try
while(!next.done) {
console.log(next.value);
next = kakarot.next();
}
function* CallKakarot() {
yield '1st try'
yield '2nd try'
yield '3rd try'
yield '4th try'
}
const kakarot = CallKakarot();
for (let count of kakarot) {
// 1st try
// 2nd try
// 3rd try
// 4th try
console.log(count);
}
yield
keyword has something similar to thefunction
keyword. If we useyield* CallKakarotAgain()
along with a generator, the current generator (CallKakarot()
) scope delegates its control to the other generator (CallKakarotAgain()
).- We can even return a value from the delegated generator and receive it in the current generator.
function* CallKakarot() {
yield '1st try'
yield '4th try'
}
function* CallKakarotAgain() {
yield '2nd try'
yield '3rd try'
}
for (let called of CallKakarot()) {
// 1st try
// 4th try
console.log(called);
}
function* CallKakarot() {
yield '1st try'
yield* CallKakarotAgain()
yield '4th try'
}
function* CallKakarotAgain() {
yield '2nd try'
yield '3rd try'
}
for (let called of CallKakarot()) {
// 1st try
// 2nd try
// 3rd try
// 4th try
console.log(called);
}
function* CallKakarot() {
yield '1st try'
const tried = yield* CallKakarotAgain()
console.log(tried)
yield '4th try'
}
function* CallKakarotAgain() {
yield '2nd try'
return '3rd try'
}
for (let called of CallKakarot()) {
// 1st try
// 2nd try
// 3rd try
// 4th try
console.log(called);
}
- Promises are used to manage callbacks.
- Promises act as an intermediary between our calling code and async code.
- Promises are not a replacement to callbacks but an alternate.
- Promises are a special kind of object, which contains another object.
- Promises can be thought of as an event listener, upon which we can register to a specific task. When the task is completed, the event will be fired once. It is important to note that it will be fired only once.
- We can chain promise for sequencing a series of async operations.
- A promise can only be one of the following,
- fulfilled - Final value called fulfillment (- succeeded)
- rejected - Final value called reason (reason for rejected) (- failed)
- pending - (- neither fulfilled nor rejected)
- settled - (- either fulfilled or rejected)
- Promises can only be resolved once. Any further attempts will be ignored (value is immutable).
- If a promise has been fulfilled or rejected and a success/failure callback is added later, the correct callback will be called, even though the async operation completed earlier.
- Testing promises are easier, because we can use
setTimeout()
as an async task. - Its provides the following improvement over callbacks-only async, namely predictability, order and trustability.
// Use Promise(..) constructor to construct a promise function
// The Promise(..) constructor should only be used for legacy async tasks (setTimeout / XMLHttpRequest)
let promise = new Promise((resolve, reject) => {
let xmlHttp = new XMLHttpRequest();
xmlHttp.open('GET', 'http://<url>', true);
xmlHttp.send();
xmlHttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
resolve(this.responseText); // Success
}
if (this.status == 501) {
reject('Internal Server Error!'); // Failure
}
}
});
promise
.then(isSaiyanGod => { /* success */ })
.catch(msg => { /* failure */ });
// then(..) also takes two arguments, a success callback and a failure callback
promise.then((result) => {
console.log(result); // "Alternate timeline is at peace!"
}, (err) => {
console.log(err); // Error: "Black Goku must be destroyed!"
});
- If we call resolve(..) and pass in another promise, current promise simply adopts the state (immediate/eventual) of the passed promise (fulfilled/rejected).