preface

This article, the ninth in a series of detailed explanations of the V8 engine, focuses on the mechanics of generator functions and the concept of coroutines. There will be links to the finished series at the end of this article, which is still being updated.

Generator function

In Javascript’s original rules, once a function is executed, it runs to the end or ends when it hits a return, and no other code can interrupt it. The introduction of Generator functions in ES6 breaks this rule by handing over execution of functions (suspending execution), which is the biggest difference from normal functions. Here are some features of the Generator:

  • Calling the Generator returns an internal pointer (Iterator object)
  • Iterate over each state inside the Generator function by calling the next method of the Iterator object
  • Function keyword and function name add “*” to distinguish it from normal function
  • The iterator object uses the next iteration to return the current yield state

Take a look at the Generator function with a little code

function* gen() {
    yield 'first';
    yield 'second';
    yield 1 + 2;
    return 'end';
}

let g = gen();
g.next(); // {value: 'first'.done: 'false'};
g.next(); // {value: 'second'.done: 'false'};
g.next(); // {value: '3'.done: 'false'};
g.next(); // {value: 'end'.done: 'true'};
Copy the code

It is also very simple to use, by building the function yiled to build the phase state, and by calling next to return the current state information (value) and done. It was the combination of Generator functions and promises that completely solved the problem of callback hell and introduced the official syntactic sugar async/await in the ES7 specification. This article focuses on what a Generator function is.

Processes and threads

To understand coroutines, you need to understand the concept of process and thread (these concepts in computers are relatively abstract concepts and there is no unified standard definition, so the following is only my personal opinion and understanding).

process

  • The computer’s core CPU does all the computing (not to mention the GPU).
  • Operating system management computer, responsible for task scheduling, resource allocation and management.
  • A set of programs that operate on an operating system and perform certain functions.
  • A process is a dynamic execution process for a data set in order to achieve a certain function of the program.
  • Process is an independent unit (entity) of the operating system for resource allocation and scheduling, as well as the basic unit of the operating system execution. The program is a lifeless entity. Only when the processor gives the program life (the operating system execution), it can become an active entity, we call it process.

thread

The basic ability of a process is to be scheduled by the operating system and to allocate and schedule resources. It is a basic unit of resource scheduling. The basic unit for scheduling resources wants to be able to do more than one thing at a time, hence the concept of threads.

Threads have the following features to help processes do more than one thing at a time:

  • Threads are the smallest unit of program execution, while processes are the smallest unit of resources allocated by the operating system
  • A process consists of one or more threads, which are different execution paths of code in a process
  • Processes are independent of each other, but threads in the same process share the program’s memory space (including code segments, data sets, heaps, etc.) and some process-level resources (such as open files and signals). Threads in one process are invisible to other processes
  • Thread context switches are much faster than process context switches

These are the basic concepts of processes and threads. If you find what I’m saying abstract, please refer to ruan’s simple explanation of processes and threads to help you understand.

Coroutines and generator functions

A Generator function is essentially an implementation of a coroutine, and you can easily understand a Generator function if you understand what a coroutine is.

What exactly is a coroutine

Coroutines are a much lighter form of existence than threads. You can think of coroutines as tasks running on threads, where multiple coroutines can exist on a thread, but only one coroutine can be executed on a thread at a time.

The concept of coroutines was developed earlier in the single-cpu scenario. It provides a suspend and resume interface to realize the concurrent function of interprocessing multiple tasks on a single CPU. In essence, the switch of different task stacks is added on the basis of a thread. By suspending and resuming different task stacks, the code fragments running alternately in the thread can realize the function of concurrency. (Note concurrency not parallelism)

Advantages of coroutines

  • Avoid lock contention

Contention occurs when multiple threads call resources, leading to contention for locks, because coroutines themselves operate on a single CPU (only one coroutine can be executed on one thread at a time), so there is no contention.

  • Coroutines consume far fewer resources than threads

Each stack of coroutines takes up much less memory space than threads. In high concurrency scenarios, too many threads can also result in OOM

  • Switching costs are extremely low

Switching (suspend and resume) of coroutines is completely controlled by the user, requires no system switching, and costs are extremely low.

Coroutines in javascript

The generator functions introduced in ES6 provide the user with an entry point to the features of the coroutine. These features make the program more suitable for high-concurrency I/O operations, making it easier to really solve the problem of callback hell.

conclusion

This article focuses on the operation mechanism of generator functions and the concept of coroutines. If you feel that you have not understood generator functions before, you will find that generator functions are not difficult to understand in essence after reading this article. Once you understand the concept of coroutines, you will understand why generator functions appear. If there are any mistakes, please discuss them with the author in the comments. If you found this article helpful, please give it a thumbs up.

series

V8 Engine Details (1) — Overview V8 engine details (2) — AST V8 engine details (3) — Bytecode evolution V8 engine details (4) — Bytecode execution V8 engine details (5) — Inline caching V8 engine details (6) — Memory structure V8 engine details (7) – Garbage collection mechanism V8 engine details (8) – message queue V8 engine details (9) – coroutines & generator functions