Think about it
- What is JavaScript asynchronous?
- Why asynchronous JavaScript?
- How to implement JavaScript asynchronous?
- How does JavaScript asynchrony work?
When game of Thrones fans came to the end of the last two episodes of its eighth season, they were left wondering: What would you think or do on the eve of your battle with the White Walkers? It has to be said that the director of the drama characters on the eve of the war their psychological activities and performance of the description is just right, every frame is worth savor.
Coming back to writing articles, I have been thinking about how to list the knowledge points I want to summarize in a simple way in an article. Welcome your valuable suggestions.
JavaScript asynchronous
The so-called “asynchrony” simply means that a task is not completed consecutively. It can be understood that the task is artificially divided into two parts. The first part is performed, then the other part is performed, and the second part is performed when the task is ready.
The Javascript language executes in a “single thread” environment. “Single-threaded” execution can also be understood as JavaScript code being interpreted (compiled) from top to bottom. Any program that needs to be executed at a future point in time (such as setTimeout,callback, etc.) will be put aside (message queue) and the following program will continue to execute. Those programs that are controlled to execute at some point in the future form JavaScript’s asynchronous execution mechanism.
function add(a, b) {
return a + b;
}
function sub(c, d) {
return c - d;
}
function multiply(e, f) {
return e * f;
}
console.log(add(1.2));
setTimeout(function() {
console.log(sub(2.1));
}, 1000);
console.log(multiply(1.2));
// 3 console.log(add(1, 2))
// 2 console.log(multiply(1, 2))
// 1 console.log(sub(2, 1))
Copy the code
Without this asynchronous execution mechanism, when a task takes a long time, subsequent tasks have to wait in line, which will delay the execution of the entire program. The common browser non-response (suspended animation) is often due to a piece of Javascript code running for a long time (such as an infinite loop), resulting in the entire page stuck in this place, other tasks can not be performed.
JavaScript single threaded with tasks
1. JavaScript programs running in a browser are single-threaded
- Js programs are always executed on one thread, which is the Js engine thread.
- There is only one Js engine thread per browser.
- Single thread, that is, THE Js engine can only execute one task at a time, other tasks to execute, need to queue.
- The Js engine thread and UI thread are mutually exclusive, because Js manipulation of the DOM causes Js execution to affect the rendering of the page.
- HTML5 tests the Web Worker standard and runs Js scripts to create multiple threads, but the child threads are completely under the control of the main thread and cannot manipulate DOM elements, so it does not change the single-threaded nature of Js.
Web Workers will be covered in a future article
2. Browsers are multi-threaded
- Js engine thread: executes JavaScript programs
- UI render thread: Render the page
- Browser event-triggered thread: controls the interaction, and the corresponding user fires the event
- Web request thread: Handling web requests, Ajax is delegated to a newly opened HTTP thread in the browser
- EventLoop Processing thread: Processes polling message queues
There will be a future article on how browsers work
JavaScript task is actually a code block (execution unit) or a line of code in the program. Due to the single-thread execution mechanism of JavaScript engine, the code that is executed sequentially in the JavaScript engine in the program is synchronous task, and the code that is executed at a certain point in the future is asynchronous task.
What are the synchronization tasks? What are the asynchronous tasks?
All but asynchronous tasks are synchronous (a bit of nonsense). Synchronous tasks are too common, such as add(a, b) math, document.getelementById (‘main’).style.fontsize = ’12px dom, QuickSort (ARR) Array quickSort, etc. However, the number of code ways that JavaScript provides for asynchronous tasks is relatively limited, with the main ones listed below.
JavaScript creates asynchronous tasks
JavaScript native event handler
Functions triggered by Js events are themselves asynchronous tasks.
What are JavaScript native events?
Onclick, onMouseover, onMouseout, onMouseDown, onMouseUp, ondblClick, onKeyDown, onkeyPress, onKeyUp, onresize Scroll bar onScroll, resource load onLoad, network request onReadyStatechange
// DOM0 event model
var btn = document.getElementById("myBtn");
btn.onclick = function() {
alert(this.id);
}
// DOM2 event model
btn.addEventListener('click'.function() {
alert('hello '+this.id);
}, true)
Copy the code
2. Timer
SetImmediate (),setTimeout(), and setInterval(), three JavaScript functions that mediate the scheduled execution of certain programs, are asynchronous tasks.
SetImmediate (fn) inserts events to the end of the event queue, and immediately executes the callback function specified by setImmediate as soon as the main thread and the event queue are done, which has the same effect as setTimeout(fn,0), but when they’re both in the same event loop at the same time, The order of execution is uncertain.
// Note: setImmediate() is a function of the node environment
setImmediate(function() {
console.log('run setImmediate');
});
setTimeout(function() {
alert('run setTimeout');
}, 0);
// run setImmediate -> run setTimeout
// It could be
// run setTimeout -> run setImmediate
Copy the code
The execution of asynchronous tasks is covered in detail in a later article, “Understanding JavaScript Concept Series –Event Loop.
3, MessageChannel
Follow up with related content
4, Promise
Promise objects are used to represent the final state (completion or failure) of an asynchronous operation, as well as the resulting value of the asynchronous operation.
Let’s take a look at two examples of Promise, one that unconditionally triggers an asynchronous function and the other that simply simulates the implementation of the GET method in AXIos.
// Triggers the asynchronous result functions resolve and reject unconditionally
console.log('before promise run');
var promise = new Promise(function(resolve, reject) {
console.log('promise is running');
resolve('promise is resolved');
});
promise.then(result= > console.log(result));
console.log('I am a line of reference');
// before promise run
// promise is running
// I am a line of reference
// promise is resolved
// Triggers the async result functions resolve and reject under certain conditions
var axios = {};
axios.get = function(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.send();
// Asynchronous events
xhr.onreadystatechange = function() {
if(xhr.readyState == 4) {
if(xhr.status == 200) {
try {
var response = JSON.parse(xhr.responseText);
resolve(response);
}catch(e) { reject(e); }}else {
reject(new Error(xhr.statusText)); }}}}); } axios.get('/userInfo').then(res= > res.data)
Copy the code
Promise is a native solution to asynchronous programming provided in JavaScript. In general, the call to the final asynchronous phase of the program requires an external event or an additional asynchronous unit such as a timer to trigger. If the asynchronous result function is triggered unconditionally, The result response function should also wait for the JS engine main thread after all synchronization task execution.
5, the Generator
A generator object is returned by a generator function, and it conforms to the iterable protocol and the iterator protocol.
function* gen() {
yield 1;
yield 2;
yield 3;
}
let g = gen();
console.log(g); // Generator { }
console.log(g.next()); // Object { value: 1, done: false }
console.log(g.next()); // Object { value: 2, done: false }
console.log(g.next()); // Object { value: 3, done: false }
console.log(g.next()); // Object { value: undefined, done: true }
Copy the code
In the above code, a call to the Generator function returns an internal pointer (that is, the iterator) g. This is another difference between a Generator function and a normal function: it does not return a result when executed; instead, it returns a pointer object. Calling the next method on pointer G moves the internal pointer (that is, the first paragraph of the asynchronous task to be executed) to the first yield statement encountered, as in the example above, until yield 3.
In other words, the next method executes the Generator function in stages. Each time the next method is called, an object is returned representing information about the current phase (the value and done properties). The value attribute is the value of the expression following the yield statement, which represents the value of the current phase; The done attribute is a Boolean that indicates whether the Generator function has completed execution, that is, whether there is a next stage.
// The generator function encapsulates asynchronous tasks
var fetch = require('node-fetch');
function* gen() {
var url = 'https: //api.xxx.users';
var result = yield fetch(url);
console.log(result);
}
var g = gen(); // g is the traverser object
var result = g.next(); // Fetch (URL) returns a Promise object
result.value.then(
data= >data.json; ) .then(data= > g.next(data); // Next time, jump out of the current traversal
)
Copy the code
In the above code, we first execute the Generator function to get the iterator object, and then use the next method (second line) to perform the first phase of the asynchronous task. Since the Fetch module returns a Promise object, the next method is called with the THEN method.
As you can see, while the Generator functions represent the asynchronous operations cleanly, the process management (that is, when to execute phase 1 and when to execute phase 2) is not convenient.
The asynchronous task created by the Generator must trigger next to complete the asynchronous phase of the task, otherwise the asynchronous result will not be returned.
6. Async function
The async function is a syntactic sugar for Generator functions.
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);
});
});
}
// The Generator function reads the file process
const gen = function* () {
const f1 = yield readFile('.. /etc/text');
const f2 = yield readFile('.. /etc/xml');
console.log(f1.toString());
console.log(f2.toString());
}
// Rewrite gen as async function
const asyncReadFile = async function() {
const f1 = await readFile('.. /etc/text');
const f1 = await readFile('.. /etc/xml');
console.log(f1.toString());
console.log(f2.toString());
}
Copy the code
The async function replaces the asterisk (*) of Generator functions with async and yields with await. The async function improves the Generator function in the following four aspects.
- Built-in actuator
- Better semantics
- Wider applicability
- The return value is Promise
For more detailed introduction, please read Ruan Yifeng teacher’s summary “Async function”. Now take a look at the core of the async function – the return Promise object
async function fn() {
return 'hello async'; Return await 'hello async'
}
var p = fn();
console.log(p); // Promise { <state>: "fulfilled", <value>: "hello async" }
p.then(value= > console.log(value)); // hello async
Copy the code
Normally, the await command is followed by a Promise object that returns the result of that object. If it is not a Promise object, the corresponding value is returned.
Process. NextTick (node environment)
The Node.js server environment is also single-threaded, except for system I/O, and only one event is processed at a time (point) during its time polling process. In an I/O application, define callbacks for each input and output, and they are automatically added to the processing queue for time polling. These callbacks are fired and executed when the I/O operation is complete. Process. nextTick means to define an (asynchronous) action that will be executed at the next polling point in time.
function f() {
console.log('foo')
}
process.nextTick(f);
setTimeout(function() {
console.log('bar');
}, 0);
process.nextTick(f);
console.log('I am the first, although at the end of the code');
// I am the first, although at the end of the code
// foo
// foo
// bar
Copy the code
NextTick creates an asynchronous task, but it executes before setTimeout.
Now go back to the first few questions. Do you have the answers in mind?
conclusion
This article summarizes some ways to create asynchronous tasks using native Js (i.e. minimal asynchronous task creation unit). Note that it is not asynchronous programming. Asynchronous programming has callbacks, publish/subscribe, and other methods.
Refer to the article
This time, understand the JavaScript execution mechanism thoroughly JS evolution, single thread, asynchronous task understanding the JavaScript mechanism on the browser side asynchronous application of Generator functions