The purpose of the article
Unveil the mystery of gorouter of go, async/await of c#writing asynchronous code in synchronous writing, and prove that it is essentially a grammatical sugar
Why use js for asynchronous programming
Because js can implement async/await syntax through the programming language's own syntax features
js asynchronous bottom-most write promise
const promise = new Promise(function(resolve, reject) { xxxxx.asynchronous IO operation((res)=>{ if(res Success){ resolve(res) }else{ reject(res) } }) });
The callback function of promise in and out has certain requirements
- The resolve function changes the state of the Promise object from incomplete to successful (that is, from pending to resolved), calls when the asynchronous operation succeeds, and passes the result of the asynchronous operation as a parameter
- The reject function changes the state of the Promise object from incomplete to failed (that is, from pending to rejected), calls when an asynchronous operation fails, and passes the error reported by the asynchronous operation as a parameter.
After the Promise instance is generated, you can use the then method to specify the callback functions for the resolved and rejected states, respectively (to process the returned results).
promise.then(function(value) { // success }, function(error) { // failure });
Extension-Note: The promise object is very special in js, such as the following example
const p1 = new Promise(function (resolve, reject) { setTimeout(() => reject(new Error('fail')), 3000) }) const p2 = new Promise(function (resolve, reject) { setTimeout(() => resolve(p1), 1000) }) p2 .then(result => console.log(result)) .catch(error => console.log(error))
This result is failt because resolve in p2 returns a promise object, which will result in the state of p2 being upgraded to the state of p1 (standard)
The n-Chain Writing of promise
The promise then method will return a promise, so js supports chain asynchronization
var getJSON = function (url, callback) { var promise = new Promise(function (resolve, reject) { var client = new XMLHttpRequest(); client.open("GET", url); client.onreadystatechange = handler;//The readystatechange event is triggered when the value of the readyState property changes from one value to another client.responseType = "json"; client.setRequestHeader("Accept", "application/json"); client.send(); function handler() { if (this.readyState !== 4) { return; } if (this.status === 200) { callback(this.response); resolve(this.response); } else { reject(new Error(this.statusText)) } }; }); return promise; }; getJSON("./e2e-tests/get.json", function (resp) { console.log("get:" + resp.name); }).then(function (json) { getJSON("./e2e-tests/get2.json", function (resp) { console.log("get2:" + resp.name); }) }).catch(function (error) { console.log("error1: " + error); });
promise exception capture
p.then((val) => console.log('fulfilled:', val)) .catch((err) => console.log('rejected', err)); // Equivalent to p.then((val) => console.log('fulfilled:', val)) .then(null, (err) => console.log("rejected:", err));
This exception capture is the same as java, capturing exceptions generated in eventLoop
Note that this exception is different from java's try catch and will not appear in the main thread if an exception is generated
finally of promise
This is the same exception system as java, finally independent state, and will execute eventually
Promise.resolve(2).finally(() => {})
More convenient writing for asynchronous use of Promise.resolve(xxx)
Promise.resolve('foo') // Equivalent to new Promise(resolve => resolve('foo'))
Note: promise asynchronization results can only be obtained in callback functions, if too many asynchronous operations are performed, the call link will be tuned to be too long
How to solve the problem of promise asynchronous programming for js?
What's wrong with promise writing? - - The call link is too long
For example, use promise to implement asynchronous ajax requests
var getJSON = function (url, callback) { var promise = new Promise(function (resolve, reject) { var client = new XMLHttpRequest(); client.open("GET", url); client.onreadystatechange = handler;//The readystatechange event is triggered when the value of the readyState property changes from one value to another client.responseType = "json"; client.setRequestHeader("Accept", "application/json"); client.send(); function handler() { if (this.readyState !== 4) { return; } if (this.status === 200) { callback(this.response); resolve(this.response); } else { reject(new Error(this.statusText)) } }; }); return promise; }; getJSON("./e2e-tests/get.json", function (resp) { console.log("get:" + resp.name); }).then(function (json) { getJSON("./e2e-tests/get2.json", function (resp) { console.log("get2:" + resp.name); }) }).catch(function (error) { console.log("error1: " + error); });
Call chain too long, non-stop promise calls
How js Solves Callback Hell - Synchronous Method Write Asynchronous
Solution uses js protocol--Generator
Special syntax for generator:js, which uses the yield keyword to block functions, and then manually controls execution using traversers
Example:
function * gen(){ let a= 123; let b = yield a; let c = yield a+b; return a+b+c; } let start = gen(); console.log(start.next()); console.log(start.next(2)); console.log(start.next(3));
Essentially a function slice
js gets the expression of the current position each time yield ed, and then manually embeds it to achieve the effect of slicing control
How to use generator for asynchronization--yield with promise for asynchronization
Take a look at this method
function* asyncFn(value) { let a = yield promiseOne(value); let b = yield promiseTwo(a); return a + b; }
To allow him to execute asynchronously, simply let the result of the previous promise be the input to the next promise
There are two ways to write
how to write
Recursive equation: f (final result) = f (present result) +f (next result)
function promiseOne(xxx) { return new Promise((res, rej) => { res(xxx + 1); }) } function promiseTwo(xxx) { return new Promise((res, rej) => { res(xxx + 1); }) } function* asyncFn(value) { let a = yield promiseOne(value); let b = yield promiseTwo(a); return a + b; } function runAsync(fn,value) { let item = fn.next(value); return new Promise((res, rej) => { if (!item.done) { if (item.value instanceof Promise) { item.value.then((re)=>{ runAsync(fn,re).then(res); }) } else { runAsync(fn,fn.valueOf()).then(res); } } else { res(item.value);//This res method is really everyone's res method } }) } runAsync(asyncFn(12)).then(res=>{ console.log(res); });
Writing of the co Toolkit
function run (gen) { gen = gen() return next(gen.next()) function next ({done, value}) { return new Promise(resolve => { if (done) { // finish resolve(value) } else { // not yet value.then(data => { next(gen.next(data)).then(resolve) }) } }) } } function getRandom () { return new Promise(resolve => { setTimeout(_ => resolve(Math.random() * 10 | 0), 1000) }) } function * main () { let num1 = yield getRandom() let num2 = yield getRandom() return num1 + num2 } run(main).then(data => { console.log(`got data: ${data}`); })
Writing Two
Recursive equation f (final result) = f (all previous results) +f (result of last step)
//Synchronous Write Asynchronous function asyncRun(resf, fn, value) { let a = fn(value); go(value); function go(value) { let next = a.next(value); if (!next.done) { if (next.value instanceof Promise) { next.value.then((res) => { go(res); }); } else { return go(next.value); } } else { resf(next.value); } } } function* asyncFn(value) { let a = yield promiseOne(value); let b = yield promiseTwo(a); return a + b; } function show(item) { console.log(item) } asyncRun(show, asyncFn, 12); function promiseOne(xxx) { return new Promise((res, rej) => { res(xxx + 1); }) } function promiseTwo(xxx) { return new Promise((res, rej) => { res(xxx + 1); }) }
Simpler method async/await
What if the above complex code becomes async/await?
It's simple
// function* asyncFn(value) { // let a = yield promiseOne(value); // let b = yield promiseTwo(a); // return a + b; // } function promiseOne(xxx) { return new Promise((res, rej) => { res(xxx + 1); }) } function promiseTwo(xxx) { return new Promise((res, rej) => { res(xxx + 1); }) } async function asyncFn(value) { let a = await promiseOne(value); let b = await promiseTwo(a); return a + b; } asyncFn(12).then((res)=>{ console.log(res) });
From the example above, we can see that async/await is actually a grammatical sugar of generator in essence
await is yield, async's function is to program function grammar sugar
If you do, answer the two rules very briefly:
- await must be followed by a promise function
- async token promise returned after function execution
Asynchronization can be easily achieved in this way