There are always many helpless in life as long as you persevere, you will find that you will be more helpless. The author hope: whether you are being cut leek, hope you lie to win!
ES2015 is short for ECMAScript 2015, which in turn is the European Computer Manufacturers Association. ECMAScript stands for the specification that the language JavaScript follows. After ECMAScript 5.1 was released in 2011, work began on version 6.0, and it wasn't until 2015 that ES6.0 was officially released. Therefore, the original meaning of the word ES6 refers to ES6.0, the next version of the JavaScript language after ES5.1.Copy the code
In-depth study of ES6 apis
Symbol
ES6 introduces a new primitive data type, Symbol, that represents unique values. It is the seventh data type in JavaScript, following undefined, NULL, Boolean, String, Number, and ObjectCopy the code
1. Direct callSymbol
The function generates a SymbolSymbol
Cannot be used before a functionnew
Command, otherwise an error will be reported.
2.Symbol
The function can take a string as an argument representing a description of Symbol, mainly for display on the console or for easy differentiation when converted to a string.
let s1 = Symbol('foo');
let s2 = Symbol('bar');
s1 // Symbol(foo)
s2 // Symbol(bar)
Copy the code
Pay attention to,Symbol
The argument to the function only represents the description of the current Symbol value, so the same argumentSymbol
The return values of the function are not equal.
// No arguments
let s1 = Symbol(a);let s2 = Symbol(a); s1 === s2// false
// With parameters
let s1 = Symbol('foo');
let s2 = Symbol('foo');
s1 === s2 // false
Copy the code
3.Symbol
Values can be used as identifiers for the property names of objects, as per eachSymbol
The values are not equal. This means that you are guaranteed not to have a property with the same name, preventing a key from being accidentally overwritten or overwritten.
Note that inside an object, when defining an attribute using the Symbol value, the Symbol value must be placed in square brackets.
let mySymbol = Symbol(a);// The first way
let a = {};
a[mySymbol] = 'Hello! ';
// The second way
let a = {
[mySymbol]: 'Hello! '
};
// The third way
let a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello! ' });
// All the above methods give the same result
a[mySymbol] // "Hello!"
Copy the code
Tip: Symbol is the attribute name, which does not appear in thefor... in
,for... of
It’s not in the loopObject.keys()
,Object.getOwnPropertyNames()
,JSON.stringify()
To return. But there is oneObject.getOwnPropertySymbols
Method to get all Symbol attribute names for the specified object.
Symbol.for
Sometimes, we want to reuse the same Symbol value. The symbol.for method can do this. It takes a string as an argument and searches for a Symbol value named with that parameter. If so, it returns the Symbol value. Otherwise, it creates and returns a Symbol value named with that string.Copy the code
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1 === s2 // true
Copy the code
Built-in Symbol
In addition to defining the Symbol values you use, ES6 provides 11 built-in Symbol values that point to methods used within the language.Copy the code
Symbol.hasInstance
Symbol.isConcatSpreadable
Symbol.species
Symbol.match
Symbol.replace
Symbol.search
Symbol.split
Symbol.toPrimitive
Symbol.toStringTag
Symbol.unscopables
Symbol.iteratorSymbol of the object.iteratorProperty that points to the default generated traverser method for the object.Copy the code
The Set and WeakSet
ES6 provides a new data structure, Set. It is similar to an array, but the values of the members are unique and there are no duplicate values. You can use Set when you need to record different members and you don't want to duplicate recordsCopy the code
How to generate a set
let set1 = new Set(a)let set2 = new Set([1.2.3])
Copy the code
Set instance attributes:
Set. Prototype. Size: returnSetThe total number of members of an instance.Copy the code
The methods of a Set instance fall into two broad categories: operation methods (for manipulating data) and traversal methods (for traversing members).
Four operation methods:
- Set.prototype.add(value) : Adds a value, returnsSetThe structure itself. -Set.prototype.delete(value) : Deletes a value and returns a Boolean value indicating whether the deletion was successful. -Set.prototype.has(value) : Returns a Boolean value indicating whether the value isSetA member of. -Set.prototype.clear() : Clears all members, no return value.Copy the code
Four traversal methods:
- Set.prototype.keys() : returns key name traverser -Set.prototype.values() : returns key value traverser -Set.prototype.entries() : Returns key value pair traversal -Set.prototype.foreach () : Use the callback function to iterate over each memberCopy the code
Note: The key and value in a Set instance are the same, sokeys()
andvalues()
The result of both methods is the same
WeakSet structure is similar to Set, which is also a collection of non-repeating values. However, it differs from Set in two ways.
-
WeakSet members can only be objects, not other types of values.
-
Objects in a WeakSet are weak references
If an object has no references, the object is garbage collected as soon as possible, freeing up its memory.
That is, garbage collection mechanism does not consider WeakSet’s reference to the object, that is, if other objects no longer reference the object, garbage collection mechanism will automatically recover the memory occupied by the object, not considering the object still exists in WeakSet.
WeakSet structure has the following three methods.
WeakSet.prototype.add(value)
: Adds a new member to the WeakSet instance.WeakSet.prototype.delete(value)
: Clears the specified member of the WeakSet instance.WeakSet.prototype.has(value)
: Returns a Boolean value indicating whether a value is inWeakSet
In an instance.
WeakSet cannot be traversed, because members are weak references and may disappear at any time.
Example:
let div = document.querySelector('div')
let set = new Set()
set.add(div)
/ /... some code
document.body.removeChild(div)
div = null // The DOM object is still in memory because it is still referenced in the Set
Copy the code
let div = document.querySelector('div')
let weakset = new WeakSet()
weakset.add(div)
/ /... some code
document.body.removeChild(div)
div = null // The DOM object has no reference and will be collected by garbage collection
Copy the code
Map and WeakMap
Map
JavaScript objects are essentially collections of key-value pairs (Hash structures), but traditionally strings can only be used as keys. This puts a great limit on its use.
To solve this problem, ES6 provides Map data structures. It is a collection of key-value pairs similar to objects, but the scope of “keys” is not limited to strings. Values of all types (including objects) can be used as keys, which is a more complete implementation of Hash structures.
Generate Map instance:
const map1 = new Map(a);const map2 = new Map([['name'.'Joe'],
['title'.'Author']]);Copy the code
Map instance attributes:
Map.prototype.size
Returns theMap
The total number of members of an instance.
Methods for Map instances fall into two broad categories: operation methods (for manipulating data) and traversal methods (for traversing members).
Four operation methods:
Map.prototype.set(key,value)
: Sets the key namekey
The corresponding key value isvalue
, and return to the entire Map structure. ifkey
If there is already a value, the key value is updated, otherwise the key is generated.Map.prototype.get(key)
Reading:key
Corresponding key value, if can’t findkey
To return toundefined
.Map.prototype.has(key)
: Returns a Boolean value indicating whether a key is in the current Map object.Map.prototype.delete(key)
: Deletes a keytrue
. If the deletion fails, returnfalse
.Map.prototype.clear()
: Clears all members with no return value.
Four traversal methods:
Map.prototype.keys()
: Returns the key name traverserMap.prototype.values()
: returns the key value traverserMap.prototype.entries()
: returns the key value pair traverserMap.prototype.forEach()
: Iterates through each member using the callback function
Example 1: Extension object
When we have a list of objects, we want to record one property per object. Suppose you have 100 chickens and you need to record the weight of each chicken. There are two ideas:
- Find a way to write on the chicken
- Record it in a book
class Chicken {}/ / 100 chickens
let chickenList = []
for (let i = 0; i < 100; i++) {
chickenList.push(new Chicken())
}
// Method 1: Record on chicken
chickenList.forEach(function(chicken, index){
chicken.weight = getWeight(chicken);
});
// Method 2: Record it in a notebook
let notebook = [];
chickenList.forEach(function(chicken, index){
notebook[index] = getWeight(chicken);
});
Copy the code
The first approach has the following problems:
- Destroy the appearance of the chicken, sometimes this is very serious, for example, you want to sell a 5 kg chicken as 6 kg, the result of the chicken directly write “I only 5 kg” (modify the original object, may lead to unexpected behavior)
- You may encounter some battle chickens that can’t write a word (objects are frozen or have unoverwritable properties)
- It is possible to write something that is already written, so that it is not visible at all (conflicts with the object’s original properties).
The second method has the following problems:
- The book does not have an exact one-to-one correspondence with the chickens, but relies on indexes or markers (such as giving each chicken a name) to record the correspondence (which cannot be accurately compared to which object).
At this point, you can use maps to extend objects
// Record to another book
let notebook = new Map(a); chickenList.forEach(function(chicken, index){
notebook.set(chicken, getWeight(chicken));
});
Copy the code
Example 2: Improving the implementation of private attributes
Looking back at the previous version of Symbol’s private property implementation, there are still defects that can be traversed by special apis.
Solution based on Map:
Each generated object is extended with a Map inside a closure
var Person = (function() {
var map = new Map(a);function Person(name) {
map.set(this,name);
}
Person.prototype.getName = function() {
return map.get(this);
};
returnPerson; } ());Copy the code
WeakMap
Similar to WeakSet introduced earlier, there are two differences between WeakMap and Map.
WeakMap
The key can only be an object, not another type of value.WeakMap
References to keys in are weak references
Similarly, WeakMap cannot traverse because the members are weak references and could disappear at any time.
WeakMap has only four methods available: get(), set(), has(), and delete().
Note: WeakMap weakly references only the key name, not the key value. Key values are still normal references.
const wm = new WeakMap(a);let key = {};
let obj = {foo: 1};
wm.set(key, obj);
obj = null;
wm.get(key)
Copy the code
Example: Improving the implementation of private attributes
There is another problem with the previous Map-based implementation:
When the external references to the Person instance are removed, the Map in the closure will still have a Reference to the Person instance as the key. The Person instance will not be garbage collected until all external references to the Person instance are removed and the closure in which the Map is located is removed
To solve this problem, WeakMap is used to further improve:
var Person = (function() {
var wm = new WeakMap(a);function Person(name) {
wm.set(this,name);
}
Person.prototype.getName = function() {
return wm.get(this);
};
returnPerson; } ());Copy the code
Proxy
Before ES6, Object.defineProperty could intercept the reading and modification of Object attributes, and Proxy could be understood as more powerful than this API, erecting a layer of “interception” in front of the target Object. All external access to the Proxy object must pass this layer of interception. Therefore, the Proxy provides a mechanism for filtering and rewriting external access. The word Proxy is used to mean that it acts as a Proxy for certain operations.
Note: Interception only works on generated Proxy instance operations
Generate Proxy instance:
var proxy = new Proxy(target, handler);
Copy the code
- Target: the object to be proxied
- Handler: Collection of intercepting functions
If handler is an empty object, it means that no operation is intercepted
let obj = {}
/* Handler is empty object */
let proxy = new Proxy(obj, {});
proxy.a = 1
//obj.a //1
Copy the code
Intercepting reads of attributes:
var proxy = new Proxy({}, {
get: function(target, property) {
return 35; }}); proxy.time/ / 35
proxy.name / / 35
proxy.title / / 35
Copy the code
The following is a list of 13 interception operations supported by Proxy.
- get(target, propKey, receiver): intercepts the reading of object properties, such as
proxy.foo
andproxy['foo']
. - set(target, propKey, value, receiver): Intercepts the setting of object properties, such as
proxy.foo = v
orproxy['foo'] = v
, returns a Boolean value. - has(target, propKey)Intercept:
propKey in proxy
Returns a Boolean value. - deleteProperty(target, propKey)Intercept:
delete proxy[propKey]
Returns a Boolean value. - ownKeys(target)Intercept:
Object.getOwnPropertyNames(proxy)
,Object.getOwnPropertySymbols(proxy)
,Object.keys(proxy)
,for... in
Loop to return an array. This method returns the property names of all of the target object’s own properties, andObject.keys()
The return result of the object contains only the traversable properties of the target object itself. - getOwnPropertyDescriptor(target, propKey)Intercept:
Object.getOwnPropertyDescriptor(proxy, propKey)
Returns the description object of the property. - defineProperty(target, propKey, propDesc)Intercept:
Object. DefineProperty (proxy, propKey propDesc)
,Object.defineProperties(proxy, propDescs)
, returns a Boolean value. - getPrototypeOf(target)Intercept:
Object.getPrototypeOf(proxy)
, returns an object. - setPrototypeOf(target, proto)Intercept:
Object.setPrototypeOf(proxy, proto)
, returns a Boolean value. If the target object is a function, there are two additional operations that can be intercepted. - apply(target, object, args): Intercepts operations called by Proxy instances as functions, such as
proxy(... args)
,proxy.call(object, ... args)
,proxy.apply(...)
. - construct(target, args): intercepts operations called by Proxy instances as constructors, such as
new proxy(... args)
. - isExtensible(target)Intercept:
Object.isExtensible(proxy)
, returns a Boolean value. - preventExtensions(target)Intercept:
Object.preventExtensions(proxy)
, returns a Boolean value.
Proxy gives developers permission to intercept the default behavior of the language and can be easily used in many scenarios without changing the original object or function. For example: counting function calls, implementing responsive data observation (Vue 3.0), implementing Immutable data, and so on
Reflect
Reflect is a new API that ES6 provides for manipulating objects. ES6 focuses much of the language-level API of the previous version, such as Object.defineProperty delete in, on static methods for Reflect.
(1) Put some methods of Object that are clearly internal to the language (such as Object.defineProperty) on Reflect. At this stage, some methods are deployed on both Object and Reflect objects, and future new methods will only be deployed on Reflect objects. That is, from the Reflect object you can get the methods inside the language.
(2) Modify the return result of some Object methods to make them more reasonable.
/ / the old way
try {
Object.defineProperty(target, property, attributes);
// success
} catch (e) {
// failure
}
/ / a new way
if (Reflect.defineProperty(target, property, attributes)) {
// success
} else {
// failure
}
Copy the code
(3) Convert imperative operations into function calls to avoid more reserved word occupation. Reflect.has(obj, name) and reflect.deleteProperty (obj, name)
/ / the old way
'assign' in Object // true
/ / a new way
Reflect.has(Object.'assign') // true
Copy the code
(4) Reflect object method and Proxy object method one to one correspondence, want to call the default behavior, directly call the same method on Reflect, simple and reliable, eliminating the need to manually write the default behavior code.
let proxy = new Proxy({}, {
set: function(target, name, value, receiver) {
var success = Reflect.set(target, name, value, receiver);
if (success) {
console.log('property ' + name + ' on ' + target + ' set to ' + value);
}
returnsuccess; }});Copy the code
There are 13 static methods on the Reflect object.
- Reflect.apply(target, thisArg, args)
- Reflect.construct(target, args)
- Reflect.get(target, name, receiver)
- Reflect.set(target, name, value, receiver)
- Reflect.defineProperty(target, name, desc)
- Reflect.deleteProperty(target, name)
- Reflect.has(target, name)
- Reflect.ownKeys(target)
- Reflect.isExtensible(target)
- Reflect.preventExtensions(target)
- Reflect.getOwnPropertyDescriptor(target, name)
- Reflect.getPrototypeOf(target)
- Reflect.setPrototypeOf(target, prototype)
The actions of the above methods correspond to those of the Proxy object handler.
Iterator
An Iterator is an object. The Iterator needs to contain a next method that returns an object with two attributes, one value indicating the current result and one done indicating whether the iteration can continue
let it = makeIterator();
function makeIterator() {
let nextIndex = 0;
return {
next: function() {
return nextIndex < 5 ?
{value: nextIndex++, done: false}, {value: undefined.done: true}; }}; }Copy the code
ES6 states that a data structure is considered “iterable” if its symbol. iterator property is a method that returns an iterator object.
interface Iterable {
[Symbol.iterator]() : Iterator,
}
interfaceIterator { next(value? :any) : IterationResult,
}
interface IterationResult {
value: any.done: boolean,}Copy the code
Example:
let obj = {
[Symbol.iterator]:makeIterator
}
Copy the code
The Iterator interface (symbol. Iterator method) is invoked by default in ES6 in the following situations:
for... of
cycle- An array of deconstruction
- Extended operator
yield*
- Where other implicit calls are used, for example
new Set(['a','b'])
.Promise.all()
Etc.
The following data structures in ES6 are traversable objects by default, that is, the symbol.iterator property is deployed by default
- Array
- Map
- Set
- String
- The arguments object for the function
- The NodeList object
The Generator function
The basic concept
Generator functions are an asynchronous programming solution provided by ES6 and behave completely differently from traditional functions.
Defining Generator functions
function* f() {}Copy the code
Formally, a Generator function is an ordinary function, but has two characteristics. There is an asterisk between the function keyword and the function name. Second, you can use the yield keyword inside the function body to define different internal states (yield means “output” in English).
Executing Generator functions
The Generator does not execute itself. Instead, it returns an iterator object that is also iterable because it has symbol. iterator methods on its prototype chain and returns the iterator object itself
function* f() {
console.log(1)}let a = f()
a[Symbol.iterator]() === a // true
Copy the code
Therefore, an object returned by a Generator function can also be iterated, equivalent to calling the value of the object next() each time as the result of the iteration
The Generator will execute only if the next() method of the traverser object is executed:
function* f() {
console.log(1)}let a = f()
a.next() / / print 1 returns {value: undefined, done: true}
Copy the code
Yield and yield
The yield keyword can be used in Generator functions to define the value after each next() of the iterator object returned by the function
function* f() {
yield 1
}
let a = f()
a.next() {value: 1, done: false}
Copy the code
And each time A executes next(), it pauses at the next yield until there is no yield keyword following, then executes the rest of the code and returns done:true:
function* f() {
console.log('step1')
yield 1
console.log('step2');
yield 2
console.log('step3');
}
let a = f()
a.next() Step1 returns {value: 1, done: false}
a.next() // Print step2 return {value: 2, done: false}
a.next() Return {value: undefined, done: true}
Copy the code
Yield itself does not return a value; the yield return is the value passed in by the next() function.
So the next() method does two things
- To perform the
yield
To the nextyield
Code between - Pass the value of the parameter to this
yield
The return value of the
Next () and yield transfer control inside and outside the function.
function* f() {
console.log('start');
let result = yield 1
console.log('result:',result);
}
let a = f()
Copy the code
Yield * is equivalent to iterating over an object and yield each result
function* f() {
yield 'start'
yield* [1.2.3]
/* is the same as */
// for(let value of [1,2,3]){
// yield value
// }
yield 'end'
}
let a = f()
a.next() {value: 'start', done: false}
a.next() {value: 1, done: false}
a.next() {value: 2, done: false}
a.next() {value: 3, done: false}
a.next() {value: 'end', done: false}
a.next() {value: undefined, done: true}
Copy the code
Generator functions with automatic actuators
Problems with direct loops
The Generator function is a new asynchronous programming solution, but calling next() manually every time is cumbersome. What if we wrote a loop to execute next()?
function* f() {
yield 1
console.log('1');
yield 2
console.log(Completed '2');
}
let it = f()
let done = false
while(! done){ done = it.next().done }Copy the code
This may seem fine, but if the yield itself is an asynchronous operation, it can be
function* f() {
yield readFile(file1)
console.log('Yeah, that's one.');
yield readFile(file2)
console.log('Yeah, that's two.');
}
let it = f()
let done = false
while(! done){ done = it.next().done }// Complete 1
// Yes, done 2
Copy the code
If the requirement is to execute the code after yield after the asynchronous operation completes, then this order of execution would not be appropriate. Validation:
function* f() {
yield readFile(file1,function (err,data) {
console.log('Read data 1:' + data)
})
console.log('Yeah, that's one.');
yield readFile(file2,function (err,data) {
console.log('Read data 2:' + data)
})
console.log('Yeah, that's two.');
}
let it = f()
let done = false
while(! done){ done = it.next().done }// Complete 1
// Yes, done 2
// Read data 1:111
// Read data 2:222
Copy the code
Thunk function
In the JavaScript language, a Thunk function is a function that takes multiple arguments and replaces it with a single-argument function that takes only a callback as an argument.
// Thunk readFile (single-argument version)
const {readFile} = require('fs')
const path = require('path')
const file1 = path.join(__dirname,'./text/1.txt')
const file2 = path.join(__dirname,'./text/2.txt')
let Thunk = function (fileName) {
return function (callback) {
return readFile(fileName, callback);
};
};
let readFileThunk = Thunk(file1);
readFileThunk(function(err,data){
console.log(String(data));
});
Copy the code
There is a Thunkify library that makes it easy to turn apis into Thunk functions
autoactuator
Write an auto-executor run function that wraps the logic of it.next() into nextStep() each time and passes nextStep as a callback to the thunk-formatted file-reading function.
// Thunk readFile (single-argument version)
const {readFile} = require('fs')
const path = require('path')
const file1 = path.join(__dirname, './text/1.txt')
const file2 = path.join(__dirname, './text/2.txt')
let Thunk = function (fileName) {
return function (callback) { //result.value
return readFile(fileName, callback);
};
};
function* f() {
let data1 = yield Thunk(file1)
console.log('Yeah, we're done 1, the data is' + data1);
let data2 = yield Thunk(file2)
console.log('Yeah, we're done with 2, the data is' + data2);
}
function run(f) {
let it = f();
function nextStep(err, data) {
var result = it.next(data);
if (result.done) return;
result.value(nextStep); // Execute readFile and pass nextStep as a callback
}
nextStep();
}
run(f)
Copy the code
As a result, writing asynchronous logic is as simple in form as writing synchronous logic, based on the autoexecutor, as long as the asynchronous operation is a Thunk function or returns a Promise.
Co module
The CO module is a better autoexecutor for a wrapper, supporting yield types, including not only thunk functions, but also Promise objects, arrays, objects, and even Generator functions
const { promisify } = require("util");
const path = require('path')
const file1 = path.join(__dirname, './text/1.txt')
const file2 = path.join(__dirname, './text/2.txt')
const readFileP = promisify(readFile)
let Thunk = function (fileName) {
return function (callback) { //result.value
return readFile(fileName, callback);
};
};
/*Thunk*/
function* f() {
let data1 = yield Thunk(file1)
console.log('Yeah, we're done 1, the data is' + data1);
let data2 = yield Thunk(file2)
console.log('Yeah, we're done with 2, the data is' + data2);
}
/*Promise*/
function* f() {
let data1 = yield readFileP(file1)
console.log('Yeah, we're done 1, the data is' + data1);
let data2 = yield readFileP(file2)
console.log('Yeah, we're done with 2, the data is' + data2);
}
/* Array (concurrent) */
function* f() {
let data = yield [readFileP(file1),readFileP(file2)]
console.log('Yeah, we're done. The data is.' + data);
}
/* Object (concurrent) */
function* f() {
let data = yield {data1:readFileP(file1),data2:readFileP(file2)}
console.log('Yeah, we're done. The data is.' + JSON.stringify(data));
}
/ * * / Generator function
function* f() {
function* f1() {
return yield {data1:readFileP(file1),data2:readFileP(file2)}
}
let data = yield f1()
console.log('Yeah, we're done. The data is.' + JSON.stringify(data));
}
co(f)
Copy the code
Generator after execution by a CO module returns a Promise object:
co(f).then(() = >{
console.log('CO completed');
})
Copy the code
Async function
The basic concept
What is async function? In short, it is the syntactic sugar of Generator functions.
Change the code from the previous chapter to the async function version:
const { promisify } = require("util");
const path = require('path')
const file1 = path.join(__dirname, './text/1.txt')
const file2 = path.join(__dirname, './text/2.txt')
const readFileP = promisify(readFile)
function* f() {
let data1 = yield readFileP(file1)
console.log('Yeah, we're done 1, the data is' + data1);
let data2 = yield readFileP(file2)
console.log('Yeah, we're done with 2, the data is' + data2);
}
// Version of async function
async function f() {
let data1 = await readFileP(file1)
console.log('Yeah, we're done 1, the data is' + data1);
let data2 = await readFileP(file2)
console.log('Yeah, we're done with 2, the data is' + data2);
}
Copy the code
The comparison shows that the version of async replaces the asterisk (*) of Generator functions with async and yields with await.
Define async functions
Define an async function using the async keyword:
async function f() {
let data1 = await readFileP(file1)
console.log('Yeah, we're done 1, the data is' + data1);
let data2 = await readFileP(file2)
console.log('Yeah, we're done with 2, the data is' + data2);
}
Copy the code
Execute async functions
An async function executes a Generator function that runs automatically. If an async function returns a result other than a Promise, it returns the result wrapped as a Promise:
async function f() {
console.log(1);
}
f().then(() = >{
console.log(2);
})
async function f() {
console.log(1);
return 'done'
}
f().then(value= > {
console.log(value);
})
Copy the code
The await keyword
Similar to yield, async functions can use the await keyword. After the await keyword, a Promise instance will be written. Each time an async function executes an await keyword, control will be transferred back to the external environment.
- if
await
If the Promise instance is resolved, the Promise instance will be resolvedawait
The next timeawait
Between the code pushed toMircoTask (microtask)
Is waiting for execution, andawait
Is the value of the Promise instance resolve - if
await
If it is not followed by a Promise instance, this will be immediately changedawait
The next timeawait
Between the code pushed toMircoTask (microtask)
Is waiting for execution, andawait
Is equal toawait
The value of the following expression:
async function f() {
let data = await new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('a')},2000)})console.log(data);
}
//f()
//console.log('end')
Copy the code
If await is not followed by a Promise instance
async function f() {
let data = await 'a'
console.log(data);
}
f()
console.log('end');
//end
//a
Copy the code
Error handling of async functions
If a Promise is rejected or thrown, the code after await will not execute, so try.. To catch an error with await:
async function f() {
try {
let data = await new Promise((resolve, reject) = > {
setTimeout(() = > {
reject('123')},2000)})// Subsequent code cannot be executed
console.log('done');
}catch (e) {
console.log('Error:',e);
}
}
f()
Copy the code
Async functions handle concurrent asynchronous tasks
If each await in an async function is executed after the preceding await resolve, use promise.all if you want to execute concurrently:
/* Concurrent processing asynchronous */
async function f() {
let time1 = new Date(a)let [data1,data2] = await Promise.all([
new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('123')},2000)}),new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('123')},3000)})])console.log(data1,data2,'Time:'+ (new Date() - time1));
}
f()
Copy the code
Async function vs. Promise
Using async functions to write asynchronous logic is more concise than Promise, dealing with different asynchronous results interdependence, error handling, if… Else branches are much easier:
const {readFile} = require('fs')
const { promisify } = require("util");
const path = require('path')
const file1 = path.join(__dirname, './text/1.txt')
const file2 = path.join(__dirname, './text/2.txt')
const file3 = path.join(__dirname, './text/3.txt')
const readFileP = promisify(readFile)
function f1() {
readFileP(file1).then(data1= >{
console.log('Yeah, we're done 1, the data is' + data1);
return readFileP(file2)
}).then(data2= > {
console.log('Yeah, we're done 1, the data is' + data2);
return readFileP(file3)
}).then(data3= > {
console.log('Yeah, we're done 1, the data is'+ data3); })}async function f2() {
let data1 = await readFileP(file1)
console.log('Yeah, we're done 1, the data is' + data1);
let data2 = await readFileP(file2)
console.log('Yeah, we're done with 2, the data is' + data1 + data2);
let data3 = await readFileP(file3)
console.log('Yeah, we're done with 2, the data is' + data1 + data2 + data3);
}
f()
Copy the code