Shiv ENOW large front end
Company official website: CVTE(Guangzhou Shiyuan Stock)
Team: ENOW team of CVTE software Platform Center for Future Education
The author:
preface
At the beginning of the interview, was asked the classic question ES6 what, young I searched full brain, in addition to water is water.
So what does ES6 have? You’ll soon have lets and const, template strings, deconstructed assignments, expansion operators, arrow functions, and so on. That may be enough to get the interviewer going, but how could the great Nuggets stop there?
To impress the interviewer, the ES6 also has these new features: Modularization, Symbol, Set and Map data structure, Proxy and Reflect reflection, Generator, etc., after saying that the interviewer’s eyes are beginning to light up, then you need to understand, so you are not afraid of being asked by the interviewer. Although it is a little cold, as the saying goes, more skills are not pressure. Take a look at Generator today!
What is the generator
Generator generator is a new feature of the ES6 specification that allows us to pause a function wherever it is executing and continue it later when it is appropriate to use the function. In the past, functions have been executed in one go, but the characteristic of a Generator is to “brake” a function in the middle and continue execution when needed. Let’s take a look at the basic usage of generator from an example.
Common javascript functions:
function fun() {
console.log(1)
console.log(2)
console.log(3)}function run() {
console.log(4)
}
fun()
run()
/ / the result:
1
2
3
4
Copy the code
Using the generator function:
function* funG() {
yield console.log(1)
yield console.log(2)
yield console.log(3)}function run() {
console.log(4)}const iter = funG()
iter.next()
run()
iter.next()
iter.next()
iter.next()
/ / the result:
1
4
2
3
{value: undefined.done:true}
Copy the code
Writing:
- Generator adds an * after function relative to normal functions.
- We use yield to control function execution before each statement we want to interrupt.
According to the printed results:
- Ordinary functions print 1,2,3,4 in one go.
- The generator prints significantly differently. Instead of executing immediately when a generator function is called, it returns an internal generator pointer object called iter, moves the pointer object to the next yield by calling the.next() method, executes the expression, returns the result of the expression, and pauses itself. Each execution returns an object containing both value and done. Value is the value of the current expression, and done is a Boolean value. When done is true, the generator is complete.
Now that we know the basic uses of generator, but not enough, we can start by talking about coroutines from the point of view of generator design.
The generator and coroutines
Since we want to talk about coroutines, first you have to know what coroutines are!
To put it simply, coroutines are like wang, A single programmer, typing code. The boss gives him A project A, and Wang immediately opens the code when he receives it.
Xiao Wang finished half of project A, and the boss said that there was A deadline for project B, so he would hurry to work on project B.
So Wang stopped developing project A and began to work on project B.
After the development of project B for some time, Xiao Wang came back to work on project A.
So that’s the coroutine, so project B is done? Probably not.
After reading the coroutines example, you are smart enough to think about the relationship between coroutines and generators! Yes, generator is an implementation of a coroutine on JS. With generator, we can use coroutines in single-threaded JavaScript!
Feature usage of the generator
The Generator itself acts as a solution for asynchronous programming and can be used to solve asynchronous tasks. There are more flexible ways to use it! That is, passing in arguments during the execution of the function and getting the output of the expression!
As mentioned above, each time generator executes next(), it returns an object: {value, done}. With value, we can get the result of that expression. Next also accepts arguments, which we can pass in at any time!
function* run(name) {
let who = yield name + ' Allen';
return who
}
let flashMan = run('Barry')
flashMan.next() // { value: 'Barry Allen', done: false }
// Pass in parameters
flashMan.next('Arrow') // { value: 'Allow', done: true }
Copy the code
On the first next() call, no arguments are passed in. By default, the name parameter values ‘Barry’ and ‘Allen’ are combined as strings, and this value is returned by yield.
On the second next() call, the argument ‘Arrow’ is passed in, and this value is received by the variable who, so the value attribute is returned with the value ‘Arrow’, which is the value of who.
Furthermore, the Generator can catch errors thrown outside the function while it is running.
function* gen(x){
try {
var y = yield x + 2;
} catch (e){
console.log(e);
}
return y;
}
var g = gen(1); g.next(); G.t hrow ('error');// error
Copy the code
A simple implementation of the generator
The principle of the generator is converted to switch-case. Start with a simple case.
function* funG() {
yield 1
yield 2
yield 3
}
const iter = funG()
iter.next() // {value: 1, done: false}
iter.next() // {value: 2, done: false}
iter.next() // {value: 3, done: false}
iter.next() // {value: undefined, done: true}
Copy the code
The implementation of the generator requires a function that can be called multiple times, returning a result and passing in arguments, so switch-case is a good choice.
function funGen(count) {
switch(count) {
case 1:
return {value: 1.done: false};
case 2:
return {value: 2.done: false};
case 3:
return {value: 3.done: false};
case 'done':
return {value: undefined.done: true}
}
}
funGen(1) // {value: 1, done: false};
funGen(2) // {value: 2, done: false};
funGen(3) // {value: 3, done: false};
funGen('done') // {value: undefined, done: true}
Copy the code
The result looks like what we want, but we are far from a generator. Next, create a function that returns an object and calls this object to help us execute lines 14 to 17.
function funGen(count) {
switch(count) {
case 1:
return {value: 1.done: false};
case 2:
return {value: 2.done: false};
case 3:
return {value: 3.done: false};
case 'done':
return {value: undefined.done: true}}}const gen = function() {
let count = 0
return {
next: function() {
++count
count = count > 3 ? 'done' : count
return funGen(count)
}
}
}
const test = gen()
test.next() // {value: 1, done: false}
test.next() // {value: 2, done: false}
test.next() // {value: 3, done: false}
test.next() // {value: undefined, done: true}
Copy the code
So far, we’ve had to manually handle the change in the value of count in the function context, so we need an object to hold the value of count in the function context.
function example(context) {
while(1) {
context.pre = context.next
switch(context.pre) {
case 1:
context.next = 2
return 1;
case 2:
context.next = 3
return 2;
case 3:
context.next = 'done'
return 3;
case 'done':
return context.end()
}
}
}
const gen = function() {
return {
next: function() {
value = context.done ? undefined : funGen(context)
done = context.done
return {
value,
done
}
}
}
}
const context = {
pre: 1.next: 1.done: false.end: function end() {
this.done = true}}const test = gen()
test.next() // {value: 1, done: false}
test.next() // {value: 2, done: false}
test.next() // {value: 3, done: false}
test.next() // {value: undefined, done: false}
Copy the code
A new object context is used to record whether the initial state of the function context, Pre, and the next state, next, done, have reached the final point. End changes done to the end state true.
After each run of next(), funGen saves the running state to the context for the next run.
conclusion
As a new feature of ES6, Gernerator was later replaced by the more convenient async await, but the unique feature of Generator allows us to pass parameters to obtain results during function execution, making function calls more flexible. As a developer, it is necessary for us to understand the basic usage and simple implementation principle of Gernerator, which is convenient for solving problems in special scenarios.