preface

The biggest differences between synchronous and asynchronous are:

  • Synchronization blocks until the above code completes
  • Async does not block. The execution of the above code has not completed before the execution of the following code has begun

We know that JS is a single-threaded language, so if there are long running tasks (e.g. Timer, DOM event, asynchronous request, etc.), if these tasks are treated as synchronous tasks, it will cause a very serious “blocking phenomenon”, so the browser will classify these tasks as asynchronous tasks, and the JS engine thread will notify other threads when encountering these asynchronous tasks (e.g. Timer thread, event processing thread, asynchronous request thread, etc.) to do, the final result only needs to feedback JS engine thread on the line

Ok, what about the notification and feedback?

Hence the asynchronous programming of JavaScript: Promise, Generator, async/await

Let’s look at how these approaches accomplish this:

Promise

Promise’s basic idea

Callback to hell:Solve callback hell with Promise:

What is a Promise?

When you print a Promise on the console, you can see that it is [native Code], indicating that the function is officially wrapped and the code is local

Output promise. prototype on the console. As a result, you can see methods like THEN, catch, finally, and so on

To sum up, let’s use a Promise as a constructor and create the simplest instance p of a Promise using the new keyword:

var p = new Promise((resolve,reject) = >{
    if(1) resolve("Asynchronous Task completed")
    else reject("Asynchronous task failed")})Copy the code

Output the instance object p in the console

We prototype in instance object P__proto__PropertyPromise.prototypeTherefore, we can make the instance object P use then/catch/finally methods

Promise’s notification and feedback process

notice

var p = new Promise((resolve,reject) = >{
    if(1) resolve("Asynchronous Task completed")
    else reject("Asynchronous task failed")})Copy the code

That’s the notification process for a Promise. The Promise is an arrow function, pass in the resolve and reject arguments, and the code that runs in {} is the resolve() and reject() operations that call the other functions. Official rule: The first parameter means “task completed”, and the second parameter means “task failed”. So, the names of these two parameters are optional, but we use Resolve and Reject to be more semantic.

state

  1. We output the instance object p on the console, which displays a Promise object. The properties of the object are found in addition to the prototype[[PromiseState]]and[[PromiseResult]]Two properties, as the name impliesstateandThe results of, where the value of state isfulfilledAnd theThe results ofThe value of is the argument to the resolve() bracket we just wrote in the Promise arrow function"Asynchronous Task completed"

2. We modify the Promise function to control its task failure:

var p = new Promise((resolve,reject) = >{
    if(0) resolve("Asynchronous Task completed")
    else reject("Asynchronous task failed")})Copy the code

3. The[[PromiseResult]]That’s the argument to the reject() bracket we just wrote in the Promise arrow function"Asynchronous task failed"And the[[PromiseState]]Turned out to berejected.

The [[PromiseState]] property in the instance p (a Promise object) is changed when the arrow function in the Promise is executed:

  • If the function (resolve()) corresponding to the first argument (resolve) is executed, change the value of this property tofulfilled; (Source code is the truth)
  • If the function (reject()) for the second argument (reject) is executed, change the value of this property torejected
  1. SetTimeout () : setTimeout() : setTimeout() : setTimeout()

  1. You can see that the original value of this property ispending.

feedback

  1. We use the inherited THEN method on the instance object P (for the task completion example)

You can see that p.hen () still returns a Promise object, and that the object’sstateintofulfilled.The results ofintoundefined(Because I’m not calling other functions and passing arguments)

  1. We use the then() method for the task failure example:

  1. You can see that the status is still rejected and res is not printed, so you can use catch() on the Promise object that you return:

9. You can see that a call to p.hen ().catch() still returns a Promise object, and that this object’sstateintofulfilled.The results ofintoundefinedAnd print out err

  1. This is the essence of why the instance object p can be called in a chain, and why only the catch() method is executed when the task fails, and then() method is executed when the task completes, and then() method is executed again until the catch() does not exit
  • Then () methodEntrance to the keyis[[PromiseState]]The value of property isfulfilled;
  • The catch () methodEntrance to the keyis[[PromiseState]]The value of property isrejected. (Source code is the truth)

(Task completed P)

(P for task failure)

conclusion

  • Steps for solving asynchrony problems with promises:
  1. Use the Promise constructor to create an instance object;
  2. Write an arrow function in the constructor, passing two arguments, one for task completion and one for task failure.
  3. Execute the asynchronous task in the arrow function. After the execution is complete, call the function named with these two names and pass the result as an argument.
  4. The asynchronous task of the arrow function in Promise() will return a Promise object that has been assigned to the instance p; P can use methods such as then()/catch() inherited from Promise.prototype
  5. P will look at these methods before executing them[[PromiseState]]The value of this property is to see if it goes into the current method, and then it goes out[[PromiseState]]and[[PromiseResult]]The values of both properties can change;
  6. Each execution still returns a Promise object

With that in mind, you have a pretty good idea of what the basic framework of Promise’s source code is (although HHH may still be hard to understand right now), as well as the various uses and scenarios that follow.

The above said the essential things, next we study the Promise source code, is how to achieve “notification” and “feedback”, want to skip directly the students click here

Promise((resolve,reject)=>{}

  • Core:
    • Return Promise object
    • This is very depressing. This is very depressing. How to achieve this: this task will be fulfilled with the state set to “fulfilled” or “rejected” with the state set to “fulfilled” and the value returned
    • How to do this: instead of sending back results to the asynchronous task when it is completed, a microtask queue is placed and then() is called

From the practices of the students of God Sanyuan:

class MyPromise {
  // Pass an asynchronous function in
  constructor(excutorCallBack){
    this.status = 'pending';
    this.value = undefined;
    this.fulfillAry = [];
    this.rejectedAry = [];
    / / = > Excutor execution
    let resolveFn = result= > {
      if(this.status ! = ='pending') return;
      let timer = setTimeout(() = > {
        this.status = 'fulfilled';
        this.value = result;
        this.fulfillAry.forEach(item= > item(this.value));
      }, 0);
    };
    let rejectFn = reason= > {
      if(this.status ! = ='pending')return;
      let timer = setTimeout(() = > {
        this.status = 'rejected';
        this.value = reason;
        this.rejectedAry.forEach(item= > item(this.value))
      }, 0)};try{
      // Execute this asynchronous function
      excutorCallBack(resolveFn, rejectFn);
    } catch(err) {
      //=> Exception information is processed according to the rejected staterejectFn(err); }}then(fulfilledCallBack, rejectedCallBack) {
    // The resolve and reject functions are actually microtasks, so they are not executed immediately, but after the then call completes
    this.fulfillAry.push(fulfilledCallBack);
    this.rejectedAry.push(rejectedCallBack);
    // After a push, they are executed}}Copy the code

Promise.then().catch(

  • Core:
    • How to implement this: task success results are caught by the THEN method, and errors are only caught by catch
    • How to implement: Chained calls

Change the then() method in MyPromise class above:

  //then pass in two functions
  then(fulfilledCallBack, rejectedCallBack) {
    // Make sure both are functions
    typeoffulfilledCallBack ! = ='function' ? fulfilledCallBack = result= > result:null;
    typeofrejectedCallBack ! = ='function' ? rejectedCallBack = reason= > {
      throw new Error(reason instanceof Error? reason.message:reason);
    } : null
    // Return a new Promise object called "New Promise"
    return new Promise((resolve, reject) = > {
      // Note that this refers to the current Promise object, not the new Promise
      // It is important to repeat:
      // The resolve and reject functions of the current Promise(not the new Promise return here) are actually a microtask
      // So they are not executed immediately, but after the then call completes
      this.fulfillAry.push(() = > {
        try {
          // Execute the methods in the then
          // The purpose of execution has been achieved
          let x = fulfilledCallBack(this.value);
          // The next step after execution is to record the execution status and determine how the new Promise will behave
          // If the return value x is a Promise object, then the operation is performed
          // If it is not a Promise, call the new Promise's resolve function directly,
          // The new promises are now empty after the new promises' THEN operations. The resolve implementation of the new Promise
          x instanceof Promise ? x.then(resolve, reject):resolve(x);
        }catch(err){
          reject(err)
        }
      });
      // The same is true
      this.rejectedAry.push(() = > {
        try {
          let x = rejectedCallBack(this.value);
          x instanceof Promise ? x.then(resolve, reject):resolve(x);
        }catch(err){
          reject(err)
        }
      })
    }) ;
  }
Copy the code

With the THEN method, catch calls are natural:

  catch(rejectedCallBack) {
    return this.then(null, rejectedCallBack);
  }
Copy the code

The test is as follows:

var p = new MyPromise((resolve, reject) = > {
  setTimeout(() = > {
    let num = Math.random()
    console.log(num)
    num < 0.5 ? resolve(100) : reject(-100);
  }, 1000)})console.log(p)
p.then(res= >{
  console.log(p)
  console.log(res)
}).catch(err= >{
  console.log(p)
  console.log(err)
})
Copy the code

(Asynchronous task succeeded)

(Asynchronous task failed)

Promise().then().catch() handles multiple serial asynchronous tasks

For example, there is a demand — want to know how many districts a prefecture has:

  1. We now need to call the get Local province interface
  2. Only after you get the province ID can you call the interface of “Get a prefecture”
  3. After getting the id of the corresponding prefecture level city, the interface of “How many districts does the prefecture level city have” can be invoked

The pseudocode is as follows:

ajax('url_1',data1);
ajax('url_2',data2); // We need to get the ajax('url_1') result before we execute
ajax('url_3',data3); // We need to get the ajax('url_2') result before we execute
Copy the code

The callback function is written as follows:

ajax('url_1', data1, function (err, result) {
    if (err) {
        return handle(err);
    }
    ajax('url_2', data2, function (err, result) {
        if (err) {
            return handle(err);
        }
        ajax('url_3', data3, function (err, result) {
            if (err) {
                return handle(err);
            }
            return success(result);
        });
    });
});
Copy the code

Aside from the fact that it’s not readable, if something goes wrong in the middle, it’s hard to fix. So we use Promise to solve this problem. The advantage is that the Promise implements the sequential execution of multiple asynchronous tasks in a synchronous task execution order

let promise = fn('url_1',data1)
promise.then(data2= > { // Note that the promise is not parentheses, it is executing new promise (...) After an object is returned
    fn('url_2',data2)
}).then(data3= > {
    fn('url_3',data3)
}).then(res= >{
    console.log(res) // The serial is finished and you can get the result you want
}).catch(err= > {
    console.log(err)
})

function fn(url,data){
     return new Promise((resovle,reject) = >{
        ajax(url,data).success(function(res){
            resolve(res)
        })
    })
}
Copy the code

This makes the code much more readable and clear. (In fact, there is a more concise method later.)

So serial, what about parallel? When you have multiple asynchronous events, unrelated and in no particular order, you just need to finish them all and start working.

Serial adds the wait time for each asynchronous event, obviously blocking completion. So how do you make sure it’s all done in parallel?

Promise.all and promise. race solve parallel problems

Promise.all([promise1,promise2,promise3,…] )

  • Receive an array, each item of which is a Promise object
  • When all promises in the array reach resolved, promise. all becomes Resolved
  • If one of the promise states becomes rejected, the promise. all state will become rejected
  • The result of a call to the THEN method succeeds. The arguments to the callback function are also an array that holds the values of each promise object’s resolve execution, in order
let promise1 = new Promise((resolve,reject) = >{
    setTimeout(() = >{
        resolve(1);
    },4000)});let promise2 = new Promise((resolve,reject) = >{
    setTimeout(() = >{
        resolve(2);
    },3000)});let promise3 = new Promise((resolve,reject) = >{
    setTimeout(() = >{
        resolve(3);
    },5000)});let promiseAll = Promise.all([promise1,promise2,promise3])
promiseAll.then(res= >{
    console.log(res); / / [1, 2, 3]
}).catch(err= > {
    console.log(err);
})
Copy the code

Console output after 5s :(the promise with the longest execution time is completed)

In the order [1,2,3], show which promise state becomes resolved firstHas nothing to do

let promise1 = new Promise((resolve,reject) = >{
    setTimeout(() = >{
        reject(1);
    },4000)});let promise2 = new Promise((resolve,reject) = >{
    setTimeout(() = >{
        resolve(2);
    },3000)});let promise3 = new Promise((resolve,reject) = >{
    setTimeout(() = >{
        resolve(3);
    },5000)});let promiseAll = Promise.all([promise1,promise2,promise3]);
promiseAll.then(res= > {
    console.log(res);
}).catch(err= > {
    console.log("Task" + err + "Failed.") // 1 Indicates that the asynchronous task in promise1 failed to execute
})
Copy the code

Output after console 4s :(one promise exits upon failure)

How promise.all () is implemented:

Promise.all = function (promises) {
    let index = 0
    let result = [] // Save the result of asynchronous task execution
    if (promises.length === 0) resolve(result)
    return new Promise((resolve, reject) = > {
        for (let i = 0; i < promises.length; i++) {
            Promise.resolve(promises[i]).then((data) = > {
                processValue(i, data) // Take the result of the task completion
            }, (err) = > {
                reject(err) // Throw an error as soon as it is found
                return})}function processValue(i, data) {
            result[i] = data // Store the result of completing the task in an array
            if (++index === promise.length) { 
            // On each success, the counter is incremented by one until all tasks are deemed to have succeeded when they match the length of values
                resolve(result)
            }
        }
    })
}
Copy the code

Conclusion:

  1. The then() and catch() methods are called on each promise object in the array to verify the results and are thrown if an error is found
  2. If the result of the promise object currently traversed is successful, it is put into a Results array
  3. Return the results array if it is the same length as the original promises array

Promise.race([promise1,promise2,promise3,…] ) Race mode

  • Accept an array in which each item is a promise.
  • Unlike all, when the first promise object becomes resolved, it becomes resolved, and when the first promise becomes Rejected, it becomes rejected. The first promsie that becomes Resolved will be used
let promise1 = new Promise((resolve,reject) = >{
    setTimeout(() = >{
        resolve(1);
    },4000)});let promise2 = new Promise((resolve,reject) = >{
    setTimeout(() = >{
        resolve(2);
    },3000)});let promise3 = new Promise((resolve,reject) = >{
    setTimeout(() = >{
        resolve(3);
    },5000)});let promiseRace = Promise.race([promise1,promise2,promise3])
promiseRace.then(res= > {
    console.log(res); // Print out 2 because promise2 will finish it first and ignore the rest
}).catch(err= > {
    console.log("Task" + err + "Failed.");
})
Copy the code

“Task accomplished” is displayed in both “promise1” and “Promise3” output on the console. This means that the loser of the “race” will still complete the race

How promise.race () is implemented

Promise.race = function (promises) {
    let index = 0
    let result = [] // Save the result of asynchronous task execution
    if (promises.length === 0)  resolve(result)
    return new Promise((resolve, reject) = > {
        for (let i = 0; i < promises.length; i++) {
            Promise.resolve(promises[i]).then((data) = > {
                resolve(data) // Throw one of the tasks as soon as it has the result of completing the task
            }, (err) = > {
                reject(err) // Throw an error as soon as it is found
                return})}})}Copy the code

Conclusion:

  1. The results of calling the THEN () and catch() methods on each promise object in the array are checked
  2. As soon as one of the Promise objects is found to be in the completed state of the task, it is thrown
  3. As soon as one of the Promise objects is found to be in a failed task state, it is thrown

Promise. Resolve () and Promise. Reject ()

Promise. Resolve the usage ()

The function of promise.resolve () is to convert an existing Promise object to a Promise object whose state is fulfilled

The following four different parameters are divided into four cases to discuss its use effect:

1. Promise.resolve(Promsie instance)

The parameter is a Promise instance, in which case promise.resolve () does nothing

2. Promise.resolve(thenable object)

The argument is an object (the thenable object) that has a THEN method. The promise. resolve method converts this object to a Promise object, and then immediately executes the THenable object’s THEN method. Such as:

let thenable = {
  then: function(resolve, reject) {
    resolve(42); }};let p1 = Promise.resolve(thenable);
p1.then(function(value) {
  console.log(value);  / / 42
});
Copy the code

In the code above, after the THEN method on the Thenable object is executed, the p1 object becomes in the resolved state and immediately executes the callback function specified by the last THEN method, with output 42

3. Promise.resolve(normal object or raw value)

If the argument is not an object with a THEN method, or not an object at all, promise. resolve returns an object in the Resolved state

const p = Promise.resolve('Hello');
// As p is in the resolved state. Then () can be executed immediately
p.then(function (s){
 console.log(s)
});
// Hello
Copy the code

4. Promise.resolve() takes no arguments

In this case, the Promise object in the Resolved state is returned. If you want to get a Promise object, it is convenient to call it directly. A Promise object that is resolved immediately is at the end of the current event loop, not at the beginning of the next. Example:

setTimeout(function () {
  console.log('three');
}, 0);

Promise.resolve().then(function () {
  console.log('two');
});

console.log('one');
// one
// two
// three
Copy the code

In the above code, setTimeout(fn, 0) is executed at the start of the next round of “event loop”, promise.resolve () is executed at the end of the current round of “event loop”, and console.log(‘ one ‘) is executed immediately, so it is printed first

How promise.resolve () is implemented

The core is to convert an existing object to a Promise object with the state fulfilled, or return it directly if it is already a Promise object

Promise.resolve = function (value) {
    if (value instanceof Promise) return value
    return new Promise(resolve= > resolve(value))
}
Copy the code

Promise. Reject the usage ()

Promise.resolve() converts an existing object to a Promise.resolve(). There are four types of arguments, similar to promise.resolve ()

How promise.reject () is implemented

The core is to convert an existing object to a Promise object with the state rejected

Promise.reject = function (value) {
    return new Promise((resolve, reject) = > reject(value))
}
Copy the code

Generator

What is the Generator

Generator is a new data type introduced by the ES6 standard. A generator looks like a function, but can return multiple times

function* fn(max) {
    yield. ;return;
}
Copy the code

Generator Generators look like functions, but are defined with function* instead

The yield keyword

The keyword yield is like return. The difference between yield and return is:

  • Return returns only after a function call. You are not allowed to perform any other operations after a return statement
  • Yield is equivalent to pausing the function and returning a value. The next time next() is called, it is executed to the next yield statement

Return The value returned

Output the value of return on the console (if there is no return, the function ends) will result in a Generator object with properties[[GeneratorState]]The value issuspendedStands for “suspended state”

The Generator. The prototype. The next () method

In the prototype of the console output Generator object, you’ll see methods like next, return, throw, and so on. Let’s focus on the next method:

Using the g.ext () method results in an object{value: 1,done: false}In this case, output G, the state can be observed assuspendedWhich will be obtained after the third execution of g.ext (){value: 1,done: false}Object, the state of the output G is “closed”. Notify the outside world that the Generator object has completed execution

The value returned is the yield return value, and done indicates whether the generator has finished executing. If done is true, then value is the return value of return. When done is true, the generator object is fully executed and no further calls to next() are required.

The generator.prototype.next () method passes arguments

The next() method can also pass arguments

function* gen(x){
  var y = yield x + 2;
  return y;
}
var g = gen(1);
g.next() // { value: 3, done: false }
g.next(2) // { value: 2, done: true }
Copy the code

The first g.ext () output {value: 3, done: The reason for false} is that gen(1) is passed in as an argument 1, and then yield returns 1 + 2, so the value is 3, and the second time g.ext () is passed in as an argument 2, so the whole yield x + 2 is replaced by 2, So return y with the value 2 and done with the value true

The Generator. The prototype. The return () method

The return() method, which returns the given value and terminates the traversal of the Generator function

function* gen() {
  yield 1;
  yield 2;
  yield 3;
}
var g = gen();
g.next()        // { value: 1, done: false }
g.return('foo') // { value: "foo", done: true }
g.next()        // { value: undefined, done: true }
Copy the code

The Generator. The prototype. Throw () method

The iterator object returned by the Generator function has a throw method that throws an error outside the function body and then catches it inside the Generator body

function* gen(x){
  try {
    var y = yield x + 2;
  } catch (e){
    console.log(e);
  }
  return y;
}

var g = gen(1);
g.next();
g.throw('Something went wrong');
/ / make a mistake
Copy the code

This is equivalent to replacing the entire yield x + 2 statement with a throw(” something went wrong “), and then trying… catch… Statement caught, so output e

The use of the Generator

  • Output each term of the Fibonacci sequence

Take a famous Fibonacci number list as an example:

0 1 1 2 3 5 8 13 21 34.Copy the code

To write a function that generates a Fibonacci sequence, write:

function fib(max) {
    var
        t,
        a = 0,
        b = 1,
        arr = [0.1];
    while (arr.length < max) {
        [a, b] = [b, a + b];
        arr.push(b);
    }
    return arr;
}
/ / test:
fib(5); // [0, 1, 1, 2, 3]
fib(10); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
Copy the code

Normal functions can only return once, so they must return an Array. Sometimes we need to return one of these values at a time, for example, to make a progress bar that interacts with the user. Normal functions return only once, so this can’t be done. However, with a generator, we can return one number at a time, repeatedly:

function* fib(max) {
    var
        t,
        a = 0,
        b = 1,
        n = 0;
    while (n < max) {
        yield a;
        [a, b] = [b, a + b];
        n ++;
    }
    return;
}
Copy the code

Try calling directly:

fib(5); // fib {[[GeneratorStatus]]: "suspended", [[GeneratorReceiver]]: Window}
Copy the code

Calling a generator directly is not the same as calling a function. Fib (5) simply creates a Generator object. This object can be thought of as an array of hidden results that will spawn the elements of the array over and over again if we trigger it again and again

var f = fib(5);
f.next(); // {value: 0, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 2, done: false}
f.next(); // {value: 3, done: false}
f.next(); // {value: undefined, done: true}
f.next(); // {value: undefined, done: true}
Copy the code

The next() method executes the generator’s code, and then, every time it hits yield x; Return an object {value: x, done: true/false} and “pause” it.

Or just use for… The of loop iterates over the Generator object in a way that doesn’t require us to go to next() and judge done every time:

for (var x of fib(5)) {
    console.log(x); // Output 0, 1, 1, 2, 3
}
Copy the code
  • Fixed callback hell :(same as the example above to find out how many districts a city has)
ajax('url_1', data1, function (err, result) {
    if (err) {
        return handle(err);
    }
    ajax('url_2', data2, function (err, result) {
        if (err) {
            return handle(err);
        }
        ajax('url_3', data3, function (err, result) {
            if (err) {
                return handle(err);
            }
            return success(result);
        });
    });
});
Copy the code

With a Generator, you can write something like this when using AJAX:

try {
    r1 = yield ajax('url_1', data1);
    r2 = yield ajax('url_2', data2); // You can use the ajax('first') result, which is r1
    r3 = yield ajax('url_3', data3); // You can use the ajax('second') result, which is R2
    success(r3);
}
catch (err) {
    handle(err); 
}
Copy the code

Use try… catch… So in the try{} area, there is no need to handle the error of r1, R2, r3, which part of the error will be caught by the catch statement naturally, and output error parameter err

  • A more advanced application is in lazy-loading

(Unfinished)

Generator

Implementation principle of Generator

How a Generator works: My simple idea of how a Generator works is that it’s kind of like storing the result of a function in an object (array) and returning it, and then we iterate through that object (array) one by one, getting the result we want each time we think about it. The difference is that using a Generator instead of a function doesn’t waste space because the Generator function is run when the Generator is executed. Next (

Yield

Inside the Generator function, the code is run as follows:

  • The first time is from the start of the function to the first yield statement;
  • The last time is from the last yield statement to the end of the function or return;
  • Each other is stopped from the yield statement to the next yield statement.

So it’s like dividing a function into many, many subblocks, each of which starts with a yield statement and ends with the next yield statement (except for the first and last one), and it’s a natural “pause” effect. And the return value of each piece of function is stored in a container called an iterator

Finally, the Generator function returns an iterator at the end of its execution

Generator.next() — The iterator pattern

Definition: The iterator pattern provides a way to access the elements of an aggregate object sequentially without exposing the internal representation of the object

Let’s implement a simple iterator that iterates through all elements without exposing the inner representation of the object:

// Do not select the deep copy content during data retrieval,
// There is a problem with handling reference types
// This is just a simplification
function Iterdtor(arr){
    let data = [];
    if(!Array.isArray(arr)){
        data = [arr];
    }else{
        data = arr;
    }
    let length = data.length;
    let index = 0;
    // The iterator core next
    // When next is called, it starts to output the next item of the inner object
    this.next = function(){
    	let result = {};
    	result.value = data[index];
    	result.done = (index === length - 1 ? true : false;)
    	if(index ! == length){ index++;return result;
    	}
    	// Return a string hint when the content is gone
    	return 'data is all done'
    };
}
let arr = [1.2.3.4];
// Generate an iterator object.
let iterdtor = new Iterdtor(arr);
Copy the code

Console output:

Async and await

The async function is the syntax sugar for Generator functions. Use the async keyword instead of asterisk * for Generator functions and the await keyword instead of yield

The async function improves four things compared to the Generator function:

  • Built-in actuator Generator functions must be executed by the actuator, hence the CO module, while async functions have their own actuators.
  • Async and await have clearer semantics than * and yield. Async means that there are asynchronous operations in the function, and await means that the expression immediately following it needs to wait for the result.
  • For the wider applicability of the CO module convention, the yield command can only be followed byThunk functionorPromise object, and after the await command of the async function, can bePromise objectandThe value of the primitive type.
  • The async function returns a Promise object, which is much more convenient than the Generator function returning an Iterator. You can specify the next action with the THEN method.

Use of async and await

  • Normal functions begin with the function keyword
  • The async function starts with the keyword async function
  • Await isWaiting for theThe completion of the latter item, if the latter item is not completed it will never go down

How many districts does a city have?

ajax('url_1',data1);
ajax('url_2',data2); // We need to get the ajax('url_1',data1) result before we execute
ajax('url_3',data3); // We need to get the ajax('url_2',data2) result before executing
Copy the code

Use async/await:

function fn(url,data) {
    return new Promise((resolve, reject) = > {
        ajax(url, data, function (err, res) {
            if (err) reject(err)
            resolve(res)
        })
    })
}
async function asyncFn() {
    let p1 = await fn('url_1',data1)
    let p2 = await fn('url_2',data2)
    let p3 = await fn('url_3',data3)
    return p3
}
asyncFn().then(result= > {
    console.log(result)
}).catch(error= > {
    console.log(error)
})
Copy the code

Matters needing attention

  1. Everything is added in frontA function of asyncAfter the executionAutomatically returns a Promise object
  2. awaitMust beUsed in async functionsCannot be used alone
  3. "Await" is followed by "await"Promise object, it waits for the execution of functions in the object to complete. If with thenotThe Promise object executes the following code/equals the following value
// Await is followed by the Promise object
let promiseDemo = new Promise((resolve, reject) = > {
    setTimeout(() = >{
        resolve('success')
        console.log(3)},0)})async function test() {
    let result = await promiseDemo / / 3
    return result
}
// Await is not a Promise object
let promiseDemo = fn(() = > {
    console.log(3)})async function test() {
    let result = await promiseDemo / / 3
    return result
}
Copy the code

The execution order of async and await

This question relates to async/await applications and also to the JavaScript series event Loop event polling

console.log(1) / / 1
let promiseDemo = new Promise((resolve, reject) = > {
    console.log(2) / / 1. 2
    setTimeout(() = > {
        let random = Math.random()
        if (random >= 0) {
            resolve('success')
            console.log(3) // 1 2 4 6 3
        } else {
            reject('failed')
            console.log(3)}},1000)})async function test() {
    console.log(4) 4/1/2
    let result = await promiseDemo New Promise(...) = new Promise(...) After an object is returned
    return result
}
test().then(result= > {
    console.log(5) // 1 2 4 6 3 5
}).catch((result) = > {
    console.log(5)})console.log(6) // 1, 2, 4, 6
Copy the code

It is worth noting that:

  • We already execute the arrow function code in the Promise when we start the new Promise
  • The async function test() is called only when test().then().catch(), and the code inside test() starts executing

Resolution:

  • 1, 2, 4, and 6 are synchronous tasks that are handled by the main thread, so they are printed in the first half
  • Enter async function test() and then execute toawait promiseDemoStatement, it waits for the timer to complete and prints 3
  • The async function then returns a Promise object and assigns it to the variable result. The async function then returns the Promise object to the function body
  • The function body uses the THEN () and catch() methods on the Promise object to output 5

Refer to the article

  • 9 k word | Promise/async/Generator principle parsing
  • Understanding the Beauty of asynchrony: Promise and Async await
  • Understanding the Beauty of asynchrony: Promise and Async Await
  • Understand the Beauty of async – Promise and async await (3)
  • Understand the async/await
  • Async /await is related to Promise
  • Generator – The official website of Liao Xuefeng
  • ES6: Promise is a Promise