当前位置:网站首页>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
边栏推荐
- Local page floating animation is realized with the help of scroll wheel
- [graph neural network] summary of graph classification study [3]: evaluation of graph classification methods and future research directions
- 207. curriculum - graph theory, depth traversal
- Varnish foundation overview 6
- Unity2d-- add keys to animation and bind events
- 006_ radio
- [machine learning Q & A] cosine similarity, cosine distance, Euclidean distance and the meaning of distance in machine learning
- Unity2D--给动画添加关键帧并绑定事件
- Using face_ Recognition library reports an error reason: cudnn_ STATUS_ NOT_ SUPPORTED
- 【机器学习Q&A】数据抽样和模型验证方法、超参数调优以及过拟合和欠拟合问题
猜你喜欢
随机推荐
Chiffrement des cookies 8
How to deal with occasional bugs?
013_ slider
Unity2D--给动画添加关键帧并绑定事件
Method of converting songs from DTS to MP3
Varnish foundation overview 4
GeoTools WKT坐标系转换
【MySQL 04】使用MySQL Workbench 8.0 CE 备份及恢复Linux中的MySQL数据库
搞透AQS原理(流程图及同步队列图解)
AI landing manufacturing: intelligent robots should have these four abilities
Cookie encryption 8
【机器学习Q&A】准确率、精确率、召回率、ROC和AUC
018_ rate
What is idempotency? Detailed explanation of four interface idempotence schemes!
MySQL monitoring
Conjecture of prime pairs in C language
scp远程拷贝命令记录
Add a second network card (network interface NIC) for the virtual machine in azure portal in 2 minutes
209. minimum length subarray - sliding window
Conversion between opencv and image (valid for pro test)




![[pytorch actual combat] generate confrontation network Gan: generate cartoon character avatars](/img/8f/c0cc1c8d19060a60d92c0d72f8b93d.png)



![Scala basics [introduction and installation]](/img/c5/9e62070719e1e0db29b0e44b0f0bc1.png)
