Introduction: a different north drift programmer, welcome to add wechat criticism and correction of communication technology or play together about dinner

Antecedents feed

Promise from introduction to handwriting: juejin.cn/post/693968… The last article is mainly divided into four parts:

  • Promiseintroduce
  • PromiseThe characteristics of
  • Promiseuse
  • Promisehandwritten

If necessary, you can click on the above link. I personally think this article is relatively complete, but after the feedback from my colleagues and friends in the comment section of the Nugget, I decide to complete the previous article. This article is as follows:

  • Promise supplement| : including Promise A + specification in such way to written Promise
  • Generator: | Generator is introduced and the usage of the Generator and coroutines | the Generate automatically perform (actuators)
  • async/awaitUsage: the async/await | contrast improvement of the Generator
  • Knowledge supplement: | co Thunk function module is introduced and the source code
  • bootleg: the last word | end spare bull belongs to my style of classic articles

Ok, let’s start our journey

Promise supplement

Promise A + specification

We’ve already implemented the Promise in the previous section, and we’ll write it again as A class, but I didn’t seem to introduce the Promise A+ spec website. You really only need to pay attention to chapter 2 in the link above. Chapter TWO is divided into three parts:

  • Promise StatesThe state of the Promise
  • The then MethodThen method
  • The Promise Resolution ProcedureThat is, the processing of the Promise

Here I find A Promise A+ specification in Chinese and English translation I also here to make A simple summary:

  1. PromiseIt is essentially a state machine, and the state can only be of the following three types:Pending(waiting),Fulfilled(Success),Rejected(failure), the state change is one-way and irreversible, only fromPending -> FulfilledPending -> Rejected.
  2. thenMethod receives two optional parameters, one for the callback that is triggered when the state changes.thenMethod returns apromise.thenThe method can be the samepromiseCall multiple times.

Of course, there are many details about the Promise A+ specification, and my summary is not complete. For example, in chapter 2 and Section 3 of the official website, IT is difficult for me to summarize the process of Promise processing in A simple way. Moreover, the Chinese and English translation above is very good, and you can suggest to have A look at it when you have time. Also in fact like I say so simply, the specific details or to see the official website or translation of Chinese and English translation ~

In fact, according to the full Promise A+ specification, in fact, the previous code in some details can not fully pass the Promise A+ specification.

Promise handwriting (class style)

The change is not much different from the previous article. One thing to note, however, is that methods like resolve,reject,all, and race are static methods of the class, so use the static keyword.

On each method of writing, thinking, in the last article has a complete introduction, if there is not understand, you can go to see the article before. I believe we can answer most of the questions.

 // How to write the Promise class
class Promise {
    // The constructor
    constructor(executor) {
        // Save the promise state
        this.promiseState = 'pending';
        // Save the promise result
        this.promiseResult = null;
        // Used to store a list of asynchronous callback functions
        this.callbackList = [];
        const resolve = val= > {
            // The status can be changed only once
            if (this.promiseState ! = ='pending') return;
            This is very depressing. This is very depressing. This is very depressing
            this.promiseState = 'fulfilled';
            // 2. To change the state of the Promise object ([[promiseResult]]])
            this.promiseResult = val;
            setTimeout(() = > {
                // Call the successful callback
                for (let callback of this.callbackList) { callback.onResolved(val); }})}const reject = err= > {
            // The status can be changed only once
            if (this.promiseState ! = ='pending') return;
            ([[promiseState]]]); ([[promiseState]])
            this.promiseState = 'rejected';
            // 2. To change the state of the Promise object ([[promiseResult]]])
            this.promiseResult = err;
            setTimeout(() = > {
                // Call the failed callback
                for (let callback of this.callbackList) { callback.onRejected(err); }})}// Throw err, reject, reject, reject, reject, reject
        try {
            /* * Synchronously execute the executable function * The executable function takes two arguments, reject and resolve */
            executor(resolve, reject);
        } catch(err) { reject(err); }}/ / then method
    then(onResolved, onRejected) {
        const self = this;
        // Handle exception traversal and set the default values for onResolved, onRejected. Because you don't have to pass either argument
        if (typeofonRejected ! = ='function') {
            onRejected = err= > {
                throwerr; }}if (typeofonResolved ! = ='function') {
            onResolved = val= > val;
        }
        // The then method returns a Promise
        return new Promise((resolve, reject) = > {
            // Encapsulate the processing of the return value
            const handleCallback = (callback) = > {
                // Reject if an error is thrown in the callback function
                try {
                    // We need to determine the return value of the then method based on the return result of the callback
                    // Now this will point to a promise object that returns, so use self
                    const res = callback(self.promiseResult);
                    if (res instanceof Promise) {
                        // If the callback returns a Promise
                        res.then(val= > {
                            resolve(val);
                        }, err= >{ reject(err); })}else {
                        // The result is not a Promiseresolve(res); }}catch(err) { reject(err); }}// Call the callback function
            if (this.promiseState === 'fulfilled') {
                setTimeout(() = >{ handleCallback(onResolved); })}if (this.promiseState === 'rejected') {
                setTimeout(() = >{ handleCallback(onRejected); })}/* * If it is pending, the asynchronous task calls the callback function when it changes state * so save the callback function * since the promise instance is large enough to specify multiple callbacks, so use an array */
            if (this.promiseState === 'pending') {
                this.callbackList.push({
                    onResolved: () = > {
                        handleCallback(onResolved);
                    },
                    onRejected: () = >{ handleCallback(onRejected); }})}})/ / catch method
    catch(onRejected) {
        // We can use the then method directly
        return this.then(undefined, onRejected);
    }
    / / resolve method
    static resolve(val) {
        // The case for return values is described earlier and can be found in the Use of Promise chapter
        return new Promise((resolve, reject) = > {
            if (val instanceof Promise) {
                val.then(val= > {
                    resolve(val);
                }, err= > {
                    reject(err);
                });
            } else{ resolve(value); }})}/ / reject method
    static reject(err) {
        // The case for return values is described earlier and can be found in the Use of Promise chapter
        return new Promise((resolve, reject) = >{ reject(err); })}/ / all methods
    static all(promiseList) {
        let count = 0;
        let res = [];
        const length = promiseList.length;
        return new Promise((resolve, reject) = > {
            for (let i = 0; i < length; i++) {
                promiseList[i].then(val= > {
                    count++;
                    res[i] = val;
                    if(count === length) { resolve(res); }},err= >{ reject(err); }); }})}/ / race method
    static race(promiseList) {
        const length = promiseList.length;
        // The one who finishes first decides the result!
        return new Promise((resolve, reject) = > {
            for (let i = 0; i < length; i++) {
                promiseList[i].then(val= > {
                    resolve(val);
                }, err= >{ reject(err); }); }}}})Copy the code

Generator

primers

In fact, we wrote too many promises. In fact, we also found a problem. Although the Promise solved the problem of returning to hell, we as developers, such as me, a senior front-end engineer (manual dog head) with half a year’s development experience, actually encountered a lot of complicated situations. This results in a lot of hard-to-read nested structures caused by THEN methods in the code.

Ridicule: Of course, many of the reasons that make it difficult to understand are historical or arbitrary. As a result, I still didn’t like the idea of nested promise.prototype.then () asynchronous processing.

However, we would like a technique to solve the nested structure caused by then. By treating asynchronous code like synchronous code, the async/await I use most often in development is introduced in ES7. Async /await provides the ability to implement asynchronous tasks in synchronous code, making writing asynchronous code as clear as synchronous code.

However, before we look at async/await, we need to look at generators because async is the syntax-sugar of generators.

Brief Introduction to Generator

There are many ways to use a Generator on the Web, and you can read the documentation in more detail. I won’t go into the details here. Sorry

Generator is a specification proposed in ECMAScript 2015, or ES6. First of all, he is not determined.

This declaration (the function keyword followed by an asterisk) defines a generator function (generator function) that returns a generator object.

Let’s directly modify the example above for MDN:

function* generator(i) {
  console.log('First time')
  yield i;
  console.log('The second time')
  yield i + 10;
  console.log('The third time')}const c = generator(1);
Copy the code

For clarity, I’ll just take a screenshot of the printout of the execution process:

When we look closely at this picture, it’s not hard to see a few things:

  • The first isfunction*This declaratively defines a generator function that returns an object. One of the objects that we intuitively find is called[[GeneratorState]]Property, which represents the state of the generator object.
  • Generator.prototype.next()Method will return ayieldThe value generated by the expression and causes the function to execute to thatyieldAnd pause. The value is an object that hasvalueanddoneTwo properties,valueIs the returned result, i.eyieldThe value of the expression following the expression,doneIndicates whether the generator object has run out of gas, that is, whether the traversal of the generator object has finished. Guys, is that a nice word to use?

Since js is executed in a single thread, how does a generator pause a function and then resume it?

The Generator and coroutines

  1. What is a coroutine?

Coroutine is a more lightweight existence than thread, coroutine in the environment of threads, a thread can exist multiple coroutines, can be understood as a task in the thread. Unlike processes and threads, coroutines are not managed by the operating system but are controlled by specific application code.

  1. How does a generator function pause and then resume?

A thread can only execute one coroutine at a time. For example, if you want to execute A coroutine and A coroutine B, you must transfer control of the JS thread to B coroutine in A coroutine. Now B is executing, A is equivalent to being in A suspended state.

In short, this is the general process:

A->> CORoutine B: I'll take A break. Coroutine B-->> coroutine C: I'm exhausted, too! You do it! Coroutine C-) coroutine A: Oh, I can't either! A you!
  1. Coroutines a.Start to perform
  2. Coroutines a.Pause,Coroutines BStart to perform
  3. Coroutines BDone. Over toCoroutines Cperform
  4. Coroutines CAfter execution, the execution authority is returned toCoroutines a.Continue to perform

Generate automatic execution

Ok, so let’s do one thing. We use generator to encapsulate asynchronous tasks into a method, and then automatically call them in sequence (i.e., synchronously).

function* asyncFun() {
    let resA = yield PromiseA / / promise object
    let resB = yield PromiseB / / promise object
    let resC = yield PromiseC / / promise object
}
Copy the code

As shown in the above code, we have written the asynchronous tasks that we want to execute in sequence in the same way as the synchronous tasks. Now we need to write a method that automatically executes them in sequence

function asyncToSyncAndRun(gen){
  var g = gen(); // In this case g is the generator object
  
  function next(data){
    var result = g.next(data);
    Result is an object in which the value corresponds to the value returned by the yield expression
    // So result.value is a Promise object
    if (result.done) return result.value;// Return if the traversal is complete
    // Put the next next execution in the callback of the present Promise object before the traversal is complete
    result.value.then(function(data){
      next(data);
    });
  }
  next();// Trigger the next method ~
}

// Automatic execution
asyncToSyncAndRun(asyncFun)
Copy the code

Therefore, through the above tool method asyncToSyncAndRun, and with the aid of the generator, we can asynchronous task has synchronous task writing method series ~

async/await

Async/await usage

Here is the introduction and example of MDN:

Async functions are functions declared using the async keyword. The async function is an instance of the AsyncFunction constructor and allows the await keyword. The async and await keywords allow us to write promise-based asynchronous behavior in a more concise way, without having to intentionally chain calls to the Promise.

Usage:

function resolveAfter2Seconds() {
  return new Promise(resolve= > {
    setTimeout(() = > {
      resolve('resolved');
    }, 2000);
  });
}

async function asyncCall() {
  console.log('calling');
  const result = await resolveAfter2Seconds();
  console.log(result);
  // expected output: "resolved"
}

asyncCall();
/ / output
//"calling"
//"resolved"
Copy the code

Ok, let’s take a look at this example and introduce async/await by the way. First async declared functions can use the “await” keyword, followed by “await” by a Promise, thus completing the transition from asynchronous to synchronous. However, children may ask what happens if “await” is not followed by a Promise. Let’s try it.

const asyncFn1 = async() = > {let res = await 1;
    console.log(res,111111111111111);
}
asyncFn1()
/ / output
1 111111111111111
Copy the code

So, in this way, if the await is not followed by a Promise, the result of the subsequent expression execution is returned.

Ok, so let’s just rewrite this method.

//generator
function* asyncFun() {
    let resA = yield PromiseA / / promise object
    let resB = yield PromiseB / / promise object
    let resC = yield PromiseC / / promise object
    console.log([resA, resB, resC])
}
//asyn/await
const asyncFun = async() = > {let resA = await PromiseA / / promise object
    let resB = await PromiseB / / promise object
    let resC = await PromiseC / / promise object
    console.log([resA, resB, resC])
}
Copy the code

A comparison shows that async functions replace the asterisk (*) of Generator functions with async, yield with await, and nothing more.

Ok, now let’s look at the difference between async/await and generator. The difference between async/await and generator is not just the way they are written

Async /await is different from generator

The async function improves the Generator function in the following four aspects:

  • Built-in actuator. Generator functions must be executed by an actuator, hence the CO module, while async functions come with an actuator. In other words, async functions are executed exactly the same as normal functions.
  • Better semantics. Async and await have clearer semantics than asterisks and yields. 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.
  • Wider applicability. The co module convention is that the yield command can only be followed by a Thunk function or a Promise object, whereas the async function’s await command can be followed by a Promise object and a value of the primitive type (numeric, string, and Boolean, but this is equivalent to synchronous operations).
  • The return value is Promise. 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. Further, the async function can well be thought of as multiple asynchronous operations wrapped into a Promise object, while the await command is the syntactic sugar of the internal then command.

Expand the knowledge

Extending the knowledge here is an extension that refers to the problem where async/await differs from generator in the previous article

Thunk function

Before I said Thunk function, I think you do not understand this term, in fact, I do not understand, must pull you, ha ha ha. Detailed content can refer to ruan Yifeng’s Thunk function meaning and usage, here will only be a brief introduction to it.

Definition: It is an implementation strategy of “call by name” to replace an expression.

// Examples of called names
function f(m){
  return m * 2;     
}
f(x + 5);
/ / is equivalent to
var thunk = function () {
  return x + 5;
};

function f(thunk){
  return thunk() * 2;
}
Copy the code

JavaScript’s Thunk function: In JavaScript, the Thunk function replaces not an expression, but a multi-argument function, replacing it with a single-argument version that accepts only callback functions as arguments.

// Normal version of readFile (multi-parameter version)
fs.readFile(fileName, callback);

// Thunk version of readFile (single-argument version)
var readFileThunk = Thunk(fileName);
readFileThunk(callback);

var Thunk = function (fileName){
  return function (callback){
    return fs.readFile(fileName, callback); 
  };
};
Copy the code

Simple summary: Both Promise and Thunk functions are passed in a callback to automate the execution of the Generator. See Chapter 5 on the meaning and usage of the Thunk function for an example.

Co module introduction and source code

Previously we mentioned the CO module [here is the link source code, you can view ~], compared to everyone does not know about it, so here is a brief introduction to you ~

Co module: The CO module lets you not write an actuator with Generator functions. The Generator function is automatically executed as soon as the CO function is passed in

The usage is as follows:

var co = require('co');
var gen = function* () {
  var resA = yield PromiseA;
  var resB = yield PromiseB;
};
co(gen);
Copy the code

Ok, after we know how to use the co module, we can understand the source code of the CO module, I will only go to the main part of the source code, the purpose is to understand the co module developer thinking. Here first stick co method of the complete code, you can have a look, I will split in the back to explain ~

/**
 * Execute the generator function or a generator
 * and return a promise.
 *
 * @param {Function} fn
 * @return {Promise}
 * @api public* /

function co(gen) {
  var ctx = this;
  var args = slice.call(arguments.1);

  // we wrap everything in a promise to avoid promise chaining,
  // which leads to memory leak errors.
  // see https://github.com/tj/co/issues/180
  return new Promise(function(resolve, reject) {
    if (typeof gen === 'function') gen = gen.apply(ctx, args);
    if(! gen ||typeofgen.next ! = ='function') return resolve(gen);

    onFulfilled();

    / * * *@param {Mixed} res
     * @return {Promise}
     * @api private* /

    function onFulfilled(res) {
      var ret;
      try {
        ret = gen.next(res);
      } catch (e) {
        return reject(e);
      }
      next(ret);
      return null;
    }

    / * * *@param {Error} err
     * @return {Promise}
     * @api private* /

    function onRejected(err) {
      var ret;
      try {
        ret = gen.throw(err);
      } catch (e) {
        return reject(e);
      }
      next(ret);
    }

    /**
     * Get the next value in the generator,
     * return a promise.
     *
     * @param {Object} ret
     * @return {Promise}
     * @api private* /

    function next(ret) {
      if (ret.done) return resolve(ret.value);
      var value = toPromise.call(ctx, ret.value);
      if (value && isPromise(value)) return value.then(onFulfilled, onRejected);
      return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, '
        + 'but the following object was passed: "' + String(ret.value) + '"')); }}); }Copy the code

You can see that there are not many lines, so let’s take a look at the main part. Please pay attention to my comments and the description before the code.

First, the co function takes a Generator function as an argument and returns a Promise object.

function co(gen) {
  var ctx = this;
  return new Promise(function(resolve, reject) {}); }Copy the code

In the returned Promise object, co first checks that gen is a Generator function. If so, the function is executed and an internal pointer object is obtained. If not, return and change the Promise object’s state to Resolved.

function co(gen) {
  var ctx = this;
  return new Promise(function(resolve, reject) {
    if (typeof gen === 'function') gen = gen.call(ctx);
    // Note that the gen is already a Generator object, not a Generator function
    if(! gen ||typeofgen.next ! = ='function') return resolve(gen);
  });
}
Copy the code

Next, the onFulfilled function is executed. Read my notes

function co(gen) {
  var ctx = this;
  return new Promise(function(resolve, reject) {
    if (typeof gen === 'function') gen = gen.call(ctx);
    // Note that the gen is already a Generator object, not a Generator function
    if(! gen ||typeofgen.next ! = ='function') return resolve(gen);
    
    onFulfilled();
    function onFulfilled(res) {
      var ret;
      try {
        // The next method of the Generator object is executed for the first time, assigning to the ret variable (which acts as an internal pointer to the Generator object).
        ret = gen.next(res);
      } catch (e) {
        returnreject(e); } next(ret); }}); }Copy the code

Finally, there’s the crucial next function, which calls itself repeatedly.

function next(ret) {
  // Return if the traversal of the Generator object is complete
  if (ret.done) return resolve(ret.value);
  //toPromise is an internal method described as: Convert a 'yield' Ed value into a promise.
  // Let's just understand that it's a utility method that converts a value to a Promise
  var value = toPromise.call(ctx, ret.value);
  This can be fulfilled recursively by adding a callback function to the return value, and then calling the next function again with onFulfilled. This recursively allows the subsequent yield operations to be placed in the callback at the end of the previous Promise.
  if (value && isPromise(value)) return value.then(onFulfilled, onRejected);
  // If the parameters do not meet the requirements, change the state of the Promise object to Rejected, thus terminating execution.
  return onRejected(
    new TypeError(
      'You may only yield a function, promise, generator, array, or object, '
      + 'but the following object was passed: "'
      + String(ret.value)
      + '"')); }Copy the code

In fact, the overall logic and we in the previous automatic actuator is also consistent, so read carefully or very easy to understand ~

conclusion

And so, Promise’s two pieces were complete. Thank you for reading! You can comment in the comment section, you can also add my wechat and communicate with me in depth, if you are interested, you can read my previous articles.

Welcome to read and follow ~ also can add my wechat hancao97 and communicate with me

I’m 24 years old. What’s the outlook? [Simplified version] Browser Rendering mechanism (complete process overview) Browser rendering mechanism (1) Browser rendering mechanism (2)…

End with a chat

Stress: This is serious

background

Recently, an important partner of mine fell into a low ebb. I can feel that the partner is going through a difficult stage through the dialogue and communication. I also have many thoughts, which are recorded here. In fact, we just stepped into the society, must have found that after work and student life is really earth-shaking change. In fact, most of our college life was free. Pressure? Almost none. However, there are various kinds of pressure after we work. The source of pressure directly doubles many, many times. We will feel heavy responsibility, unhappy in work and all kinds of problems.

About how to deal with problems at work

However, we may say that we are under great pressure and unhappy, but we always need a way to solve the problem, to rely on a working methodology and make our work “happy”. After all, confronting and solving problems is a positive style of dealing with affairs. So here are a few of them, and I’ll give you my thoughts, and if you have any thoughts, you can add them in the comments section.

On communication style at work:

Concise, clear, straightforward, eliminate unnecessary links, should be said and said.

What do you do when you suddenly have several things to do at once?

First of all, we have a clear idea that people can deal with problems in parallel, not in parallel, and we have to deal with a lot of things one at a time. Then, we rank things according to their urgency and importance. Generally, the degree of urgency is more worthy of attention. We deal with problems in descending order of urgency, and consider the priority of equally urgent things according to their importance and duration. If things aren’t too urgent, prioritize tasks. And, in my eyes, once you’ve started something, try not to switch to another task in the middle of it unless there’s a blocking problem that’s hard to personally push, or something extremely urgent that needs to be addressed. Because it takes time to switch events.

How to solve the time conflict of participants:

First of all, the participants have priority, we should first to understand, which are the must attend, who can not attend, then we go to first arrange more key role in meetings, less important participants can also learn about the meeting conclusion by other means, such as meeting minutes or discussion document update related record.

What to do if you encounter problems at work that are beyond your scope:

To put it plainly, it’s still a matter of time, so I think it’s a priority to solve the problem, and if you can quickly Google a solution, just do it yourself and record the problem (preferably with your own markdown). If not, prior to ask around or those who have had previous experience technology bosses () if he have time and willing to take a reason you, don’t waste a long working time exploring problems for this matter, I can control my eyes this time in an hour, if less task, of course, I’m screwing, task time is tight, I take a look at the direct exposure, look for a person to solve quickly. Anyway, in terms of the amount of work, the intensity of the work, to measure a threshold for yourself. The amount of time left to explore and solve the problem. But, finally, we must record the problem! And try to do this week, this week, do not leave a tail, to figure out the problem, understand, this is the process of improvement.

Encouragement and Gratitude

I am a person always open mouth closed mouth rushed, always happy to say invincible, refueling refueling such words, of course, actually also led what colleagues and friends and I together to say the blood in two words, I actually relatively poor words, so repeatedly also this a few words.

Working here for more than half a year, I met a lot of friendly people, some of them showed me the way forward, and some gave me encouragement. In fact, I have been very happy in the past half a year. Thank you here:

  • Thanks to my mentor, who gave me a lot of guidance.
  • Thanks to my colleagues at work, as well as a few partners who are not even front end to support me in these immature articles. HHH, although every time I see a bigGerhardt's support clubShame on me, too.
  • Thanks to the important friends, and I encourage each other programmers.

So, partners, everyone refueling together, there are difficulties to overcome ~ onion!! You should know that as a person who is not good at words, onion is actually full of profound meaning ~ partner, you are also invincible, I wish you a happier life and work ~ Finally, the first picture and the last picture are yuyuantan night to see, nice!

Thanks for reading.