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:
Promise
introducePromise
The characteristics ofPromise
usePromise
handwritten
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 PromiseGenerator
: | Generator is introduced and the usage of the Generator and coroutines | the Generate automatically perform (actuators)async/await
Usage: the async/await | contrast improvement of the GeneratorKnowledge supplement
: | co Thunk function module is introduced and the source codebootleg
: 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 States
The state of the PromiseThe then Method
Then methodThe Promise Resolution Procedure
That 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:
Promise
It 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
->Fulfilled
或Pending
->Rejected
.then
Method receives two optional parameters, one for the callback that is triggered when the state changes.then
Method returns apromise
.then
The method can be the samepromise
Call 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 is
function*
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 ayield
The value generated by the expression and causes the function to execute to thatyield
And pause. The value is an object that hasvalue
anddone
Two properties,value
Is the returned result, i.eyield
The value of the expression following the expression,done
Indicates 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
- 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.
- 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!
Coroutines a.
Start to performCoroutines a.
Pause,Coroutines B
Start to performCoroutines B
Done. Over toCoroutines C
performCoroutines C
After 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 big
Gerhardt's support club
Shame 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.