当前位置:网站首页>Illustration Google V8 19: asynchronous programming (II): how does V8 implement async/await?
Illustration Google V8 19: asynchronous programming (II): how does V8 implement async/await?
2022-06-30 01:56:00 【Kaixiaomo】
explain
The illustration Google V8 Learning notes
Program history of front-end asynchronous programming

1、 What is callback hell ?
If you use too many asynchronous callback functions in your code , Will disrupt the entire code logic , This makes the code difficult to understand , This is the problem of hell .
var fs = require('fs')
fs.readFile('./src/kaimo555.txt', 'utf-8', function(err, data) {
if (err) {
throw err
}
console.log(data)
fs.readFile('./src/kaimo666.txt', 'utf-8', function(err, data) {
if (err) {
throw err
}
console.log(data)
fs.readFile('./src/kaimo777.txt', 'utf-8', function(err, data) {
if (err) {
throw err
}
console.log(data)
})
})
})
The above code sets an asynchronous request with an asynchronous request , An asynchronous request depends on the execution result of another , Use callbacks to nest with each other .
This leads to ugly code , Inconvenient for later maintenance .
2、 Use Promise Solve the problem of callback to hell
Use Promise It can solve the problem of non-linear coding in callback hell .
const fs = require("fs")
const p = new Promise((resolve, reject) => {
fs.readFile("./src/kaimo555.txt", (err, data) => {
resolve(data)
})
})
p.then(value => {
return new Promise((resolve, reject) => {
fs.readFile("./src/kaimo666.txt", (err, data) => {
resolve([value, data])
})
})
}).then(value => {
return new Promise((resolve, reject) => {
fs.readFile("./src/kaimo777.txt", (err, data) => {
value.push(data)
resolve(value)
})
})
}).then(value => {
let str = value.join("\n")
console.log(str)
})
3、 Use Generator Functions implement more linear logic
Although the use of Promise It can solve the problem of non-linear coding in callback hell , But this approach is full of Promise Of then() Method , If the process is complicated , Then the whole code will be filled with a lot of then, Asynchronous logic is still used then The method interrupts , Therefore, the semantics of this way is not obvious , The code doesn't represent the execution process very well .
So how can we write asynchronous code like synchronous code ?
Example :
function getResult(){
let id = getUserID(); // Asynchronous requests
let name = getUserName(id); // Asynchronous requests
return name
}
The feasible solution is When an asynchronous request is executed , Pause the current function , Wait until the asynchronous request returns the result , Restore the function .
Rough model diagram : The key is Implement function pause and function resume .

Generator function
Generator is designed to implement pause function and resume function , The generator function is a function with an asterisk , coordination yield You can pause and resume the function . Resume the execution of the generator , have access to next Method .
Example :
function* getResult() {
yield 'getUserID'
yield 'getUserName'
return 'name'
}
let result = getResult()
console.log(result.next().value)
console.log(result.next().value)
console.log(result.next().value)
V8 How to pause and resume the execution of generator functions ?
coroutines
A coroutine is a lighter existence than a thread . If from A Start the process B coroutines , We will take A The process is called B The father of Xie Cheng .
- There can be multiple coroutines on a thread , However, only one coroutine can be executed on a thread at the same time .
- The process is not managed by the operating system kernel , And it's completely controlled by the program , It doesn't consume resources like thread switching .
The flow chart of the above example is as follows :

Coroutines and Promise The general process of cooperating with each other :
function* getResult() {
let id_res = yield fetch(id_url);
let id_text = yield id_res.text();
let new_name_url = name_url + "?id=" + id_text;
let name_res = yield fetch(new_name_url);
let name_text = yield name_res.text();
}
let result = getResult()
result.next().value.then((response) => {
return result.next(response).value
}).then((response) => {
return result.next(response).value
}).then((response) => {
return result.next(response).value
}).then((response) => {
return result.next(response).value
actuator
Encapsulate the code of the execution generator into a function , This function drives the generator function to continue execution , We call this function that executes the generator code actuator .
You can refer to the famous co frame

function* getResult() {
let id_res = yield fetch(id_url);
let id_text = yield id_res.text();
let new_name_url = name_url + "?id=" + id_text;
let name_res = yield fetch(new_name_url);
let name_text = yield name_res.text();
}
co(getResult())
co Source code implementation principle : In fact, it is through constant calls generator Functional next() function , To achieve automatic execution generator The effect of the function ( similar async、await Automatic self-determination of functions ).
/** * slice() reference. */
var slice = Array.prototype.slice;
/** * Expose `co`. */
module.exports = co['default'] = co.co = co;
/** * Wrap the given generator `fn` into a * function that returns a promise. * This is a separate function so that * every `co()` call doesn't create a new, * unnecessary closure. * * @param {GeneratorFunction} fn * @return {Function} * @api public */
co.wrap = function (fn) {
createPromise.__generatorFunction__ = fn;
return createPromise;
function createPromise() {
return co.call(this, fn.apply(this, arguments));
}
};
/** * 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 || typeof gen.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) + '"'));
}
});
}
/** * Convert a `yield`ed value into a promise. * * @param {Mixed} obj * @return {Promise} * @api private */
function toPromise(obj) {
if (!obj) return obj;
if (isPromise(obj)) return obj;
if (isGeneratorFunction(obj) || isGenerator(obj)) return co.call(this, obj);
if ('function' == typeof obj) return thunkToPromise.call(this, obj);
if (Array.isArray(obj)) return arrayToPromise.call(this, obj);
if (isObject(obj)) return objectToPromise.call(this, obj);
return obj;
}
/** * Convert a thunk to a promise. * * @param {Function} * @return {Promise} * @api private */
function thunkToPromise(fn) {
var ctx = this;
return new Promise(function (resolve, reject) {
fn.call(ctx, function (err, res) {
if (err) return reject(err);
if (arguments.length > 2) res = slice.call(arguments, 1);
resolve(res);
});
});
}
/** * Convert an array of "yieldables" to a promise. * Uses `Promise.all()` internally. * * @param {Array} obj * @return {Promise} * @api private */
function arrayToPromise(obj) {
return Promise.all(obj.map(toPromise, this));
}
/** * Convert an object of "yieldables" to a promise. * Uses `Promise.all()` internally. * * @param {Object} obj * @return {Promise} * @api private */
function objectToPromise(obj){
var results = new obj.constructor();
var keys = Object.keys(obj);
var promises = [];
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var promise = toPromise.call(this, obj[key]);
if (promise && isPromise(promise)) defer(promise, key);
else results[key] = obj[key];
}
return Promise.all(promises).then(function () {
return results;
});
function defer(promise, key) {
// predefine the key in the result
results[key] = undefined;
promises.push(promise.then(function (res) {
results[key] = res;
}));
}
}
/** * Check if `obj` is a promise. * * @param {Object} obj * @return {Boolean} * @api private */
function isPromise(obj) {
return 'function' == typeof obj.then;
}
/** * Check if `obj` is a generator. * * @param {Mixed} obj * @return {Boolean} * @api private */
function isGenerator(obj) {
return 'function' == typeof obj.next && 'function' == typeof obj.throw;
}
/** * Check if `obj` is a generator function. * * @param {Mixed} obj * @return {Boolean} * @api private */
function isGeneratorFunction(obj) {
var constructor = obj.constructor;
if (!constructor) return false;
if ('GeneratorFunction' === constructor.name || 'GeneratorFunction' === constructor.displayName) return true;
return isGenerator(constructor.prototype);
}
/** * Check for plain object. * * @param {Mixed} val * @return {Boolean} * @api private */
function isObject(val) {
return Object == val.constructor;
}
4、async/await: Asynchronous programming “ ultimate ” programme
The generator still needs to use additional co Function to drive the execution of generator functions , For this reason ,ES7 Introduced async/await, This is a JavaScript A major improvement in asynchronous programming , It improves the disadvantages of the generator , Provides the ability to access resources asynchronously using synchronous code without blocking the main thread .
async/awaitNo generator promise The grammar sugar of , It is a complete system from design to development , It's just the use of a coroutine and promiseasync/awaitSupport try catch It is also the underlying implementation of the engine
async function getResult() {
try {
let id_res = await fetch(id_url);
let id_text = await id_res.text();
let new_name_url = name_url+"?id="+id_text;
let name_res = await fetch(new_name_url);
let name_text = await name_res.text();
} catch (err) {
console.error(err)
}
}
getResult()
async
async Is an asynchronous execution and an implicit return Promise As a function of the result .

V8 How to deal with await Later ?
await You can wait for two types of expressions :
- Any ordinary expression
- One Promise The expression of the object
If await Waiting for one Promise object , It pauses the execution of the generator function , until Promise The state of the object becomes resolve, Will resume execution , Then get resolve Value , As await The result of an expression .
Expand information
边栏推荐
- If you want to install a set of monitoring, what is the process? How much is it?
- ES6 one line code for array de duplication
- Geotools: common tools for mutual conversion of wkt, geojason, feature and featurecollection
- Yyds dry inventory consistent and smooth zoom type and spacing
- DTW learning (dynamic time warping) -- Thought and code implementation
- 【PyTorch实战】生成对抗网络GAN:生成动漫人物头像
- C语言 数组元素循环右移问题
- The (3n+1) conjecture that C language kills people without paying for their lives
- (4) Blender source code analysis flash window display process
- MySQL monitoring 5
猜你喜欢

cookie加密8

Understand AQS principle (flow chart and synchronous queue diagram)

Embedded test template

Matlab 2012a 绘制带箭头的线段

cookie加密11

002_ container

Want to change careers, but don't know what you want to do?
![[graph neural network] summary of graph classification study [3]: evaluation of graph classification methods and future research directions](/img/b1/2afa73a14b2f41b7a65c4c2d261e6a.png)
[graph neural network] summary of graph classification study [3]: evaluation of graph classification methods and future research directions
![[MRCTF2020]Ezpop-1|php序列化](/img/65/9b7a3ae3552d8784b0c77a1130d762.png)
[MRCTF2020]Ezpop-1|php序列化

Unity2D--给动画添加关键帧并绑定事件
随机推荐
C language output integer in another format
Is it safe to open an account in Sinosteel futures?
C语言 成绩排名
Design and implementation of spark offline development framework
【二叉树】最大二叉树 II
js Array. Five convenient applications of from()
Spark 离线开发框架设计与实现
If you want to install a set of monitoring, what is the process? How much is it?
搞透AQS原理(流程圖及同步隊列圖解)
What to remember about the penalty for deduction of points in Item 1
If mybaits cannot query the data, it can query how to change it in the database
图解 Google V8 # 19 :异步编程(二):V8 是如何实现 async/await 的?
Geotools wkt coordinate system conversion
207. curriculum - graph theory, depth traversal
C语言 害死人不偿命的(3n+1)猜想
What are the payment and distribution systems?
[protection mode] segment descriptor
Comprendre le principe AQS (organigramme et schéma de file d'attente synchrone)
Difference between test plan and test plan
Mobaihe cm201-2-ch-hi3798mv300-300h-emmc and NAND_ Infrared Bluetooth voice_ Brush firmware package