Written in the beginning
- ES6 common but ignored methods series of articles, sorting out the author thinks that some daily development may use some methods, use skills and some application scenarios, details please see related content links, welcome to supplement exchange.
Related articles
- Common but overlooked methods for ES6 (Destruct assignments and values first)
- ES6 Common but ignored methods (second bullet functions, arrays, and objects)
- ES6 common but ignored methods (third bullet Symbol, Set, and Map)
- ES6 commonly used but overlooked methods (fourth bullet Proxy and Reflect)
- ES6 common but ignored methods (# 5 Promise and Iterator)
- Common but ignored methods for ES6 (Generator 6)
- ES6 Common but ignored methods (eighth bullet Class)
- ES6 common but ignored methods (Module 9)
- Common but ignored methods of ES6 (Development specification of the Tenth Bullet Project)
- ES6 common but ignored method (eleventh bullet Decorator)
- Common but overlooked approaches to ES6 (End game – Latest Proposal)
Async function
- ES6 – async function
introduce
async
The function isGenerator
Function syntax sugar.
const fs = require('fs'); const readFile = function (fileName) { return new Promise(function (resolve, reject) { fs.readFile(fileName, function(error, data) { if (error) return reject(error); resolve(data); }); }); }; // Generator const gen = function* () {const f1 = yield readFile('/etc/fstab'); const f2 = yield readFile('/etc/shells'); console.log(f1.toString()); console.log(f2.toString()); }; // async const asyncReadFile = async function () {const f1 = await readFile('/etc/fstab'); const f2 = await readFile('/etc/shells'); console.log(f1.toString()); console.log(f2.toString()); };Copy the code
async
Function ofGenerator
Function improvement:Generator
Function execution must depend on the executor, hence the existence ofco
Module (based onES6
的Generator
和yield
, allowing us to write asynchronous code in synchronous form), andasync
Functions come with their own actuators.(async
Function execution, as normal functions, as long as one line.
asyncReadFile(); Copy the code
Generator
Function, need to be callednext
Method, or useco
Module, can really execute, get the final result.
const gg = gen(); gg.next() Copy the code
- Better semantics.
async
andawait
Compared to*
andyield
, the semantics are clearer.async
It means that there are asynchronous operations in the function,await
Indicates that the following expression needs to wait for the result. - Wider applicability.
co
Module convention,yield
Command can only be followed byThunk
functionorPromise
Object, andasync
Function of theawait
After the command, it can bePromise
Object and primitive type values (numeric, string, and Boolean, but this is automatically converted to immediateresolved
的Promise
Object). - The return value is
Promise
.async
The return value of the function isPromise
Object, this is more thanGenerator
The return value of the function isIterator
Objects are much more convenient.
use
- The base is held
async
The function returns aPromise
Object that can be usedthen
Method to add a callback function.async
Function of the internalreturn
The value returned by the statement becomesthen
Method to call the argument to the function.async
The function throws an error internally, which will result in a returnPromise
Object toreject
State. The thrown error object will be removedcatch
The method callback function receives.
async function getName() { return 'detanx'; } getName().then(val => console.log(val)) // "detanx" async function f() {throw new Error(' Error '); } f().then(v => console.log(v), e => console.log(e)) // Error: Error occurredCopy the code
- use
// async function foo() {} const foo = async function () {}; Let obj = {async foo() {}}; obj.foo().then(...) // Arrow function const foo = async () => {}; // Class method Class Storage {constructor() {this.cachePromise = caches. Open ('avatars'); } async getAvatar(name) { const cache = await this.cachePromise; return cache.match(`/avatars/${name}.jpg`); } } const storage = new Storage(); Storage. GetAvatar (' jake). Then (...). ;Copy the code
- Change of state
async
Function returnedPromise
Object,Must wait inside allawait
After commandPromise
A state change does not occur until the object is executed, unless encounteredreturn
Statement or throw an error.
await
The command- Under normal circumstances,
await
The command is followed by onePromise
Object that returns the result of that object. If it is notPromise
Object directly returns the corresponding value.
async function getName() { return 'detanx'; } getName().then(val => console.log(val)) // "detanx" Copy the code
- On the other hand,
await
The command is followed by onethenable
Object (definedthen
Method object), thenawait
It’s going to be equal toPromise
Object.
class Sleep { constructor(timeout) { this.timeout = timeout; } then(resolve, reject) { const startTime = Date.now(); setTimeout( () => resolve(Date.now() - startTime), this.timeout ); } } (async () => { const sleepTime = await new Sleep(1000); console.log(sleepTime); }) (); / / 1000Copy the code
- Any one
await
After the statementPromise
Object toreject
State, so the wholeasync
The function breaks execution.Async function f() {await promise.reject (' error '); await Promise.resolve('hello world'); // do not execute}Copy the code
- If the previous asynchronous operation failed, do not interrupt subsequent asynchronous operations.
await
On thetry... catch
inside
Async function f() {try {await promise.reject (' error '); } catch(e) { } return await Promise.resolve('detanx'); } f() .then(v => console.log(v)) // detanxCopy the code
await
At the back of thePromise
Object followed by onecatch
Method to handle errors that may have occurred earlier.
Async function f() {await promise.reject (' error '). Catch (e => console.log(e)); async function f() {await promise.reject (' error '). return await Promise.resolve('detanx'); } f().then(v => console.log(v)Copy the code
- Under normal circumstances,
- Use caution points
await
After commandPromise
Object, the result of which might berejected
So it’s better toawait
Command intry... catch
Code block.- multiple
await
Asynchronous operations following a command, if there is no secondary relationship, should be fired at the same time.
// let [foo, bar] = await Promise. All ([getFoo(), getBar()]); // let fooPromise = getFoo(); let barPromise = getBar(); let foo = await fooPromise; let bar = await barPromise;Copy the code
await
Commands can only be used whenasync
Function, if used in ordinary functions, will report an error. The correct way to write it is to usefor
Looping or using arraysreduce
Methods. If you want multiple requests to be executed concurrently, you can usePromise.all
orPromise.allSettled
Methods.
async function dbFuc(db) { let docs = [{}, {}, {}]; Async function docs.forEach(function (doc) {await db.post(doc); }); => for loop for (let doc of docs) {await db.post(doc); } => array reduce method await docs. Reduce (async (_, doc) => {await _; await db.post(doc); }, undefined); }Copy the code
async
The function can preserve the run stack.
const a = () => { b().then(() => c()); }; Copy the code
-
In the above code, function A runs an asynchronous task b() inside. When b() runs, function A () does not interrupt, but continues execution. By the time b() finishes running, it is possible that A () has long since finished running and the context in which B () exists has disappeared. If b() or c() reports an error, the error stack will not include a().
-
Now change this example to an async function.
const a = async () => { await b(); c(); }; Copy the code
- In the code above,
b()
When it runs,a()
It’s a pause, the context is saved. Once theb()
orc()
Error, the error stack will containa()
.
implementation
async
And the way that functions are implemented is that theGenerator
Function and autoexecutor, wrapped in one function.
async function fn(args) { // ... Function fn(args) {return spawn(function* () {//... }); }Copy the code
- All of the
async
Functions can be written in the second form above, wherespawn
The function is the autoexecutor. The followingspawn
Function implementation, is basically the previous version of the autoexecutor.
function spawn(genF) {
return new Promise(function(resolve, reject) {
const gen = genF();
function step(nextF) {
let next;
try {
next = nextF();
} catch(e) {
return reject(e);
}
if(next.done) {
return resolve(next.value);
}
Promise.resolve(next.value).then(function(v) {
step(function() { return gen.next(v); });
}, function(e) {
step(function() { return gen.throw(e); });
});
}
step(function() { return gen.next(undefined); });
});
}
Copy the code
Comparison of asynchronous processing methods
-
Traditional methods, prior to ES6, there were roughly four methods of asynchronous programming.
- The callback function
- Event listeners
- Publish/subscribe
Promise
object
-
Through an example, mainly look at the Promise, Generator function and async function comparison, others are not familiar with you can look up the relevant information.
-
Suppose a series of animations are deployed on a DOM element, and the first animation ends before the next one begins. If one of the animations fails, it does not proceed further and returns the return value of the last successfully executed animation.
Promise
The writing of
Function chainAnimationsPromise(elem, animations) {// The variable ret is used to keep the return value of the previous animation let ret = null; // create an empty Promise let p = promise.resolve (); For (let anim of animations) {p = p. Chen (function(val) {ret = val; return anim(elem); }); Function (e) {/* ignore the error, continue */}). Then (function() {return ret; }); }Copy the code
- At first glance, the code is all
Promise
的API
(then
,catch
And so on), the semantics of the operation itself are not easy to see.
Generator
The way you write a function.
function chainAnimationsGenerator(elem, animations) { return spawn(function*() { let ret = null; try { for(let anim of animations) { ret = yield anim(elem); }} catch(e) {return ret; }); }Copy the code
- Semantic than
Promise
Written more clearly, the user – defined actions all appear inspawn
The inside of the function. The problem is that you have to have a task runner that does it automaticallyGenerator
Function of the code abovespawn
The function is the autoexecutor, and it returns onePromise
Object, and must be guaranteedyield
The expression following the statement must return onePromise
.
async
The way you write a function.
async function chainAnimationsAsync(elem, animations) { let ret = null; try { for(let anim of animations) { ret = await anim(elem); }} catch(e) {return ret; }Copy the code
Async
The function implementation is the most concise and semantically compliant, with almost no semantically irrelevant code.
-
All asynchronous processing methods exist as reasonable, there is no best, only the most appropriate, in dealing with different practical situations, we can choose the most suitable processing method.
The instance
- In real life development, you often encounter a set of asynchronous operations that need to be done sequentially. For example, reading a group remotely in turn
URL
, and output the results in the order they were read.Promise
In the writing.
Function logInOrder(urls) {const textPromises = urls.map(URL => {return fetch(URL). Then (response =>) response.text()); }); TextPromises. Reduce ((chain, textPromise) => { return chain.then(() => textPromise) .then(text => console.log(text)); }, Promise.resolve()); }Copy the code
- The above code uses
fetch
Method while reading a group remotelyURL
. eachfetch
All operations return onePromise
Object, put intextPromises
The array. And then,reduce
Method handles each in turnPromise
Object, and then usethen
And all thePromise
Objects are linked together so that results can be output in sequence.
async
Function implementation.
Async function logInOrder(urls) {// Async function logInOrder(urls) {const textPromises = urls.map(async URL => {const response = await fetch(url); return response.text(); }); // Output for (const textPromise of textPromises) {console.log(await textPromise); }}Copy the code
- In the code above, although
map
The argument to the method isasync
Function, but it is executed concurrently because onlyasync
The internal execution of a function is secondary, and the external execution is unaffected. At the back of thefor.. of
The loop is used internallyawait
, so the sequential output is realized.
topawait
- now
await
Commands can only appear inasync
Function inside, otherwise an error will be reported. There is aGrammar proposal(The bill is currently inStatus: Stage 3
), allowing independent use at the top level of the moduleawait
Command so that the above line of code does not report an error.The purpose of this proposal is to borrowawait
Solve the problem of asynchronous module loading.- The module
awaiting.js
The output value ofoutput
Depending on the asynchronous operation.
// awaiting.js let output; (async function1 main() { const dynamic = await import(someMission); const data = await fetch(url); output = someProcess(dynamic.default, data); }) (); export { output };Copy the code
- loading
awaiting.js
The module
// usage.js import { output } from "./awaiting.js"; function outputPlusValue(value) { return output + value } console.log(outputPlusValue(100)); setTimeout(() => console.log(outputPlusValue(100), 1000); Copy the code
outputPlusValue()
The result of the execution depends entirely on the execution time. ifawaiting.js
The asynchronous operation in it is not finished. It is loaded inoutput
The value isundefined
.
- The module
- The current solution is to have the original module output one
Promise
Object, from thisPromise
The object determines whether an asynchronous operation has ended.// usage.js import promise, { output } from "./awaiting.js"; function outputPlusValue(value) { return output + value } promise.then(() => { console.log(outputPlusValue(100)); setTimeout(() => console.log(outputPlusValue(100), 1000); }); Copy the code
- In the code above, will
awaiting.js
The output of the object is placed inpromise.then()
In order to ensure that the asynchronous operation is complete before readingoutput
. - This is cumbersome, requiring the user of the module to follow an extra protocol to use the module in a particular way. Once you forget to use it
Promise
Load, using only normal load methods, code that relies on this module may fail. And if the topusage.js
And then there’s the external output, which is equal to all the modules in the dependency chainPromise
Load.
- In the code above, will
- The top-level await command guarantees that the module will output the value only after the asynchronous operation has completed.
// awaiting.js const dynamic = import(someMission); const data = fetch(url); export const output = someProcess((await dynamic).default, await data); // usage.js import { output } from "./awaiting.js"; function outputPlusValue(value) { return output + value } console.log(outputPlusValue(100)); setTimeout(() => console.log(outputPlusValue(100), 1000); Copy the code
- In the above code, both asynchronous operations are added to the output
await
Command. The module will not output values until the asynchronous operation is complete.
- In the above code, both asynchronous operations are added to the output
- At the top
await
Some usage scenarios for.// the import() method loads const strings = await import(' /i18n/${navigator.language} '); // Database operation const connection = await dbConnector(); // rely on rollback let jQuery; try { jQuery = await import('https://cdn-a.com/jQuery'); } catch { jQuery = await import('https://cdn-b.com/jQuery'); }Copy the code
- If more than one contains the top layer
await
The load command is executed synchronously.// x.js console.log("X1"); await new Promise(r => setTimeout(r, 1000)); console.log("X2"); // y.js console.log("Y"); // z.js import "./x.js"; import "./y.js"; console.log("Z"); Copy the code
- The code above has three modules, the last one
z.js
loadingx.js
andy.js
, the printed result isX1
,Y
,X2
,Z
. This shows,z.js
There was no waitingx.js
Load, load againy.js
. - The top of the
await
Commands are a bit like handing over execution of code to other modules to load, then taking it back after the asynchronous operation is complete and continuing.
- The code above has three modules, the last one