Why is JS single threaded
The characteristic of a single thread is that only one task can be executed at a time. Because of the interaction with the user and manipulation of the DOM and other related operations, js must use a single thread, otherwise multithreading will cause synchronization problems. If one thread is modifying the DOM and another thread wants to delete the DOM, the shared resource needs to be locked, making the task tedious.
Single thread problem
The single thread will cause the blocking problem, and the next task can be executed only after the previous task is completed. In this way, the page will be stuck and the page will not respond, affecting the user experience. Therefore, the solution of synchronous task and asynchronous task appears.
Synchronous task: a task that is queued on the main thread can be executed only after the first task is completed. Asynchronous task: In the task queue, only when the task queue notifies the main thread that an asynchronous task is ready will it enter the main thread to call.
Specific operation mechanism:
- All synchronization tasks are executed on the main thread, forming oneExecution stack.
- There is one outside the main threadTask queueWhenever an asynchronous task has a result, an event is placed in the task queue.
- When all the synchronous tasks in the execution stack are finished, the event in the task queue will be read, and the asynchronous task corresponding to the event will end the wait state and the execution stack will start.
Event Loop
The main thread continuously reads events from the task queue in a Loop, so the whole operation mechanism is also called an Event Loop.
Macro task
- The code inside script
- setTimeout
- setInterval
- setImmediate(Node)
- I/O (ajax request)
Micro tasks
- Promise(When creating a Promise instance object, the code executes sequentially, if
When the · THEN operation is executed, the task is dispatched to the microtask queue.
- Process.nexttick (will be executed before promise)
- MutationObserver
The operation of the loop mechanism
-
- Script content is a macro task that starts with a script tag and is placed on the execution stack when a function call occurs.
- 2. If you encounter a macro task during this process, put it in a macro task queue.
- 3. If you encounter a microtask, place the microtask in the microtask queue of the current macro task (each macro task has a microtask queue).
- 4. After the current macro task is executed, all the callback functions in the microtask queue are executed before exiting the execution stack. (If a new microtask is encountered, the system continues to join the end of the current microtask queue.) After the execution, clear the microtask queue and unstack the microtask.
- 5. Perform requestAnimationFrame callback, event handling, and page refresh.
- 6. Fetch the next macro task from the macro task queue and start executing (back to 1).
In short: Perform one macro task, perform a team of microtasks
Test 1
console.log('1');
setTimeout(() = > {
console.log('2')},1000);
new Promise((resolve, reject) = > {
console.log('3');
resolve();
console.log('4');
}).then(() = > {
console.log('5');
});
console.log('6');// 1,3,4,6,5,2
Copy the code
Test 2
console.log('1');
setTimeout(function() {
console.log('2');
new Promise(function(resolve) {
console.log('3');
resolve();
}).then(function() {
console.log('4')})setTimeout(function() {
console.log('5');
new Promise(function(resolve) {
console.log('6');
resolve();
}).then(function() {
console.log('7')})})console.log('14');
})
new Promise(function(resolve) {
console.log('8');
resolve();
}).then(function() {
console.log('9')})setTimeout(function() {
console.log('10');
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')})})console.log('13')
/ / 1,8,13,9,2,3,14,4,10,11,12,5,6,7
https://juejin.cn/post/6913368493035356167
Copy the code
Nodejs the eventloop
Juejin. Cn/post / 691336…
Hejialianghe. Making. IO/jsadvanced /…
How do you implement asynchronous programming
The callback function
Asynchronous tasks must specify callback functions, which are not called directly but are executed when a specific event or condition occurs and are used to respond to that event. AJAX’s onload event, for example, is followed by a callback function, but the constant nesting of callback functions creates callback hell.
ajax("./test1.json".function(data){
console.log(data);
ajax("./test2.json".function(data){
console.log(data); . })})Copy the code
Callback hell shortcomings
- Nested functions have coupling properties and will pull the whole body once they are changed.
- Callbacks cannot use try catch to catch errors. (Because asynchronous tasks are executed when synchronous tasks in the execution stack have already exited, and functions to catch exceptions have also been introduced)
- Callbacks cannot return directly. (Only callback functions can be terminated, not external code.)
Event publish/subscribe
const pbb = new PubSub();
ajax("./test1.json".function(data){
Publish test1Success and the requested data on the first ajax request success
pbb.publish("test1Success",data);
})
// Subscribing to test1Success will be triggered
pbb.subscribe("test1Success".function(data){
console.log(data);
// Make a second Ajax request
ajax("./test2.json".function(data){
// The second Ajax request successfully published the message
pbb.publish("test2Success",data); })})/ / subscribe test2Success
pbb.subscribe("test2Success".function(data){
console.log(data); . })Copy the code
The realization of the PubSub
class PubSub{
constructor(){
// Event queue
this.events = {};
}
// Publish events
publish(eventName, data){
if(this.events[eventName]){
this.events[eventName].forEach(cb= > {
cb.apply(this, data);// Once the event is successfully published, the callback function in the corresponding queue is executed}); }}// Subscribe to events
subscribe(eventName, callback){
if(this.events[eventName]){
this.events[eventName].push(callback);
}else{
this.events[eventName] = [callback]; }}// Unsubscribe
unSubcribe(eventName, callback){
if(this.events[eventName]){
this.events[eventName] = this.events[eventName].filter(
cb= >cb ! == callback ); }}}Copy the code
Encapsulation in NodeJS (Event)
let events = require("events");
const pbb = new events.EventEmitter();// Create a publish subscription object
ajax("./test1.json".function(data){
Publish test1Success and the requested data on the first ajax request success
pbb.emit("test1Success",data);
})
// Subscribing to test1Success will be triggered
pbb.on("test1Success".function(data){
console.log(data);
// Make a second Ajax request
ajax("./test2.json".function(data){
// The second Ajax request successfully published the message
pbb.emit("test2Success",data); })})/ / subscribe test2Success
pbb.on("test2Success".function(data){
console.log(data);
});
Copy the code
Generator
Juejin. Cn/post / 684490…
State change when using:
- The generator function is called first, and the internal code is suspended instead of being executed immediately.
- Calling next() wakes up the generator, performs its current yield, returns an object, and continues to suspend.
- Until there is no executable code, it returns a result object {value: undefined, done: true}.
function request(url) {
makeAjaxCall(url, function(response) {
it.next(response);// The second call returns the result})}function *foo() {
var data = yield request('http://api.example.com');
console.log(JSON.parse(data));
}
var it = foo();
it.next();// The first call executes request
Copy the code
Promise
Promise can solve callback hell (promise chain calls) and handle parallel tasks (promise.all).
PromiseA + specification
The use of the promise
Promise is a constructor that takes as an argument a function (which the executor function executes immediately) that takes resolve,reject (also a function).
The attribute of promise
After calling new, p is a Promise instance object, and each instance object has two properties: state and result
There are three possible states
- Pending (prepare)
- This is a big pity.
- Rejected (= rejected)
Perform resolve(STR) to make the state pending-> depressing, and the current promise value is STR
Reject (STR) makes the state pending-> Rejected, and the current promise value is STR
And the state change is one-off (it can only be changed once)
let p = new Promise((resolve,reject) = >{
resolve("Successful outcome");
//reject(" reject ");
})
console.log(p);
Copy the code
Promise. Prototype. Then method
The then method has two parameters, both of which are functions. The first function is executed when the state is fulfilled (and the parameter is the promise value), and the second method is executed when the state is Rejected (ibid.).
let p = new Promise((resolve,reject) = >{
resolve("Successful outcome");
//reject(" reject ");
})
let ret = p.then((value) = > {
console.log("Called on success"+ value);
},(err) = > {
console.log("Call on failure"+ err);
})
Copy the code
The then method returns a new Promise, and the current state is pending. The final return value of then is determined by the result of the execution of the callback function in THEN.
- If an exception is thrown, the new promise state is Rejected, and Reason is the exception.
- This is a pity if an arbitrary value is returned that is not a promise, the state of the new promise will be fulfilled, and the value will be the return value
- If you return a promise, that’s the promise
Because then returns a promise, he can also call THEN, which makes chained calls (solving callback hell/cascading execution tasks) possible.
new Promise((resolve,reject) = >{
}).then((value) = >{
console.log("The first promise succeeds.")
//return 123; // After returning, the state of the promise will be fulfilled.
console.log(a);// But if this code fails, it will change the state of the current Promise to Rejected
},(reason) = >{
console.log("The first promise fails.")
}).then((value) = >{
console.log("The second promise succeeds.")},(reason) = >{
console.log("The second Promises fail"+reason);// Can capture the cause of the failure
})
Copy the code
Then is not executed when the state is pending.
This is called when a promise has more than one THEN.
Promise. Prototype. Catch method
Catch, catch, catch A catch catches an error in all three cases (Reject, error, or throw).
const p = new Promise((resolve,reject) = > {
//reject();
//console.log(a);
throw new Error('Wrong')})let t = p.catch((reason) = >{
console.log('failure'+reason);
})
Copy the code
The most common way to write promise
new Promise((resolve,reject) = >{
}).then((value) = >{
console.log('success'+value);
}).catch((reason) = >{
console.log('failure'+reason);
})
Copy the code
Method of use
function fn(){
return new Promise((resolve, reject) = >Resolve (data), reject(error)})} fn(). Then (success1, fail1). Then (Success2, fail2)Copy the code
Promise.all/Promise.race
// Wrap multiple Promises into a Single Promise instance object, and only call Success1 if they all succeed
Promise.all([promise1, promise2]).then(success1, fail1)
const p1 = Promise.resolve(1);// Return a Promise object with a success value of 1
const p2 = Promise.reject(2);
const p3 = Promise.resolve(3);
const pAll = Pomise.all([p1,p2,p3]);
pAll.then(
(value) = > {
console.log('success'+value)/ / [1, 3]
},
(reason) = > {
console.log('failure'+reason)/ / 2})Copy the code
// Then is called by the first state-determined promise in the array
Promise.race([promise1, promise2]).then(success1, fail1)
Copy the code
Write a Promise
Promise constructor, then, catch
//1. Define structure without writing concrete implementation
//ES5 custom module
(function(window){
// The constructor passes an executor function
function Promise(executor){
let _this = this;
_this.status = 'pending';// Store the current state
_this.data = undefined;// Store the current value
_this.callbacks = [];// Each object has two callback functions onResolved onRejected
function resolve(value){
if(_this.status ! = ='pending') return;// State can only be changed from pending
_this.status = 'fulfilled';/ / state
_this.data = value;/ / value
if(_this.callbacks.length){// Execute each onResolved asynchronously and pass the vaule value if there is already a callback
setTimeout(() = >{
_this.callbacks.forEach((callbackObj) = >{ callbackObj.onResolved(value); })},0); }}function reject(reason){
if(_this.status ! = ='pending') return;
_this.status = 'rejected';
_this.data = reason;
if(_this.callbacks.length){
setTimeout(() = >{
_this.callbacks.forEach((callbackObj) = >{ callbackObj.onRejected(reason); })},0); }}try{
executor(resolve,reject);Execute executor immediately.
}catch(err){
reject(err);// Call rejecte if an error occurs}}Promise.prototype.then = function(onResolved, onRejected){
let _this = this;// Save the Promise object that calls Then
onResolved = typeof onRejected === 'function'? onRejected : value= > value;// Pass a function if it is not a callback
onRejected = typeof onRejected === 'function'? onRejected : reason= > {throw reason};// The transmission is abnormal
return new Promise((resolve, reject) = >{
// Executes the specified callback and changes the state that returns promise
function handle(callback){
try{
const result = callback(self.data);
if(result instanceof Promise) {//3.返回的是一个promise, 返回promise就是这个promise
result.then(resolve,reject);// If result succeeds, resolve, which returns a promise, is called
}else{
resolve(result);//2. The return is not a Promise, and the return Promise is a pity}}catch(err){
reject(err);//1. Throw an exception and return the promise (Rejected)}}// Determine the status of the caller
if(_this.status === 'rejected') {// Asynchronously execute onRejected and pass the parameter if the caller fails
setTimeout(() = >{ handle(onRejected); })}else if(_this.status === 'fulfilled') {// If the caller succeeds, execute onResolved and pass the parameter
setTimeout(() = >{ handle(onResolved); })}else{// The caller state is Pending and saves onResolved and onRejected
self.callbacks.push({
onResolved(value){
handle(onResolved);
},
onRejected(reason){ handle(onRejected); }})}})}Promise.prototype.catch = function(onRejected){
return this.then(undefined,onRejected);
}
// Return a successful Promise
Promise.resolve = function(value){
return new Promise((resolve,reject) = >{
if(value instanceof Promise) {// A promise is passed in
value.then(resolve,reject);
}else{// An ordinary value is passed inresolve(value); }})}// Return a failed Promise
Promise.reject = function(reason){
return new Promise((resolve,reject) = >{ reject(reason); })}Promise.all = function(promises){
const values = [];// Define the return value of the array saved successfully
let count = 0;
return new Promise((resolve, reject) = >{// Return a new promise
// Iterate over the results of each promise
promises.forEach((p, index) = >{
if(! pinstanceof Promise) {// If there is a non-promise object in the array, consider it a success
values[index] = value;
count++;
}else{
p.then(
value= >{
values[index] = value;// If p is successful, save it in the same order as Promises
count++;
if(count === promises.length){
resolve(values);// Return promise as success and pass in the array}},reason= >{// If one fails, return a promisereject(reason); })})})}// Returns the first completed/failed result
Promise.race = function(promises){
return new Promise((resolve, reject) = >{
promises.forEach((p) = >{
p.then((value) = >{
resolve(value);
},(reason) = >{ reject(reason); })})})}window.Promise = Promise;// Mount it to window}) ()// Execute the function immediately anonymously
Copy the code
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<body>
<script src="./newPromise.js"></script>
<script>
new Promise((resolve, reject) = > {
setTimeout(() = >{
console.log("Delay completed for 1s")
resolve(1);
},1000);
console.log("State change successful")
}).then((value) = >{
console.log('onResolved1()'+value);
return new Promise((resolve,reject) = >{
setTimeout(() = >{
resolve(2);
console.log('Finish two seconds late')},2000)})},(reason) = >{
console.log("onRejected()" + reason);
}).then((value) = >{
console.log('onResolved2()'+ value);
throw 3;
},(reason) = >{
console.log("onRejected2()" + reason);
}).catch((reason) = >{
console.log("onRejected3()" + reason);
})
/* Status change succeeded test.html:15 delay for 1s to complete test.html:21 onResolved1()1 test.html:25 Delay for 2 seconds to complete test.html:32 onResolved2()2 test.html:37 onRejected3()3 */
</script>
</body>
</html>
Copy the code
// ES6 writing style
(function(Window){
class Promise{
constructor(exector){}function reject(reason){}// Defined on the prototype
then(onResolved, onRejected){}catch(onRejected){
}
// Defined on class objects
// Return a successful Promise
static resolve = function(value){}// Return a failed Promise
static reject = function(reason){}static all = function(promises){}// Returns the first completed/failed result
static race = function(promises){
}
Window.Promise = Promise;// Mount it to window}) ()// Execute the function immediately anonymously
Copy the code
test
setTimeout(() = >{
console.log("0");
})
// 1 2 3 3 4 6 5 0
new Promise((resolve, reject) = >{
console.log("1");
resolve();
}).then(() = >{
console.log("2");
new Promise((resolve, reject) = >{
console.log("3");
resolve();
}).then(() = >{
console.log("4");
}).then(() = >{
console.log("5");
})
}).then(() = >{
console.log("6");
})
new Promise((resolve, reject) = >{
console.log("Seven");
resolve();
}).then(() = >{
console.log("8");
})
Copy the code
async await
The async and await keywords provide a more concise way to write asynchronous behavior based on promises without intentionally chain-calling promises.
The return value of async is a Promise object, and the expression to the right of await is usually a Promise, but may not be.
Await will return the fulfilled value, so you need to use try{}catch(){} to get the fulfilled value.
function fn1(){
return new Promise((resolve,reject) = >{
setTimeout(() = >{
resolve(1);
},1000)})}async function fn2(){
let result = await fn1();
console.log(result);
return new Promise((resolve,reject) = >{
setTimeout(() = >{
reject(2);
},1000)})}async function fn3(){
try{
let result = await fn2();
console.log(result);
}catch(err){
console.log(err);
}
}
fn3();
Copy the code
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");
}
async function async2() {
console.log("async2");
}
console.log("script start");
setTimeout(function () {
console.log("settimeout");
}, 0);
async1();
new Promise(function (resolve) {
console.log("promise1");
resolve();
}).then(function () {
console.log("promise2");
});
console.log("script end");
/*
script start
async1 start
async2
promise1
script end
async1 end
promise2
settimeout
*/
Copy the code
AJAX
Juejin. Cn/post / 684490…
AJAX is asynchronous javascript and XML that can exchange data with the server and update parts of the web without reloading the page.
Four steps
- Create an Ajax instance object using new XMLHttpRequest.
- Use the open method to set the address and mode of request.
- Use send() to send data
- ResponseText gets the data returned by the server
A get request
let btn = document.getElementById('btn');
let username = document.getElementById('username');
let age = document.getElementById('age');
btn.onlick = function(){
let xhr = new XMLHttpRequest();
let name = username.value;
let age = username.value;
let params = 'username='+name+'&age='+age;
xhr.open('get'.'https://localhost:3000/get? '+params);
xhr.send();
xhr.onload = function(){
console.log(xhr.responseText); }}Copy the code
Post request (request format: Attribute name = attribute value)
let btn = document.getElementById('btn');
let username = document.getElementById('username');
let age = document.getElementById('age');
btn.onlick = function(){
let xhr = new XMLHttpRequest();
let name = username.value;
let age = username.value;
let params = 'username='+name+'&age='+age;
xhr.open('post'.'https://localhost:3000/post');
xhr.setRequestHeader('Content-Type'.'application/x-www-form-urlencoded');
xhr.send(params);
xhr.onload = function(){
console.log(xhr.responseText); }}Copy the code
Post request (request format is JSON)
let xhr = new XMLHttpRequest();
xhr.open('post'.'http://localhost:3000/json');
xhr.setRequestHeader('Content-Type'.'application/json');
xhr.send(JSON.stringify({name:'tom'.age:19}));
xhr.onload = function(){
console.log(xhr.responseText);
}
Copy the code
Ajax status code
- 0 is initialized and Open is not called
- 1 Start. Open is called, but send is not called
- 2 Send. The message has been sent, but no response has been received
- 3 Receive: Some data has been received
- 4 Completed, and fully received data can be used in the client.
let xhr = new XMLHttpRequest();
xhr.open('get'.'http://localhost:3000/readystate');
console.log(xhr.readyState);/ / 1
xhr.onreadystatechange = function(){
console.log(xhr.readyState);
if(xhr.readyState === 4) {console.log(xhr.responseText);
}
}
xhr.send();
Copy the code
Encapsulation AJAX
<script type="text/javascript">
function ajax (options) {
// Stores default values
var defaults = {
type: 'get'.url: ' '.data: {},
header: {
'Content-Type': 'application/x-www-form-urlencoded'
},
success: function () {},
error: function () {}};// Override properties in the defaults object with properties in the Options object
Object.assign(defaults, options);
// Create ajax objects
var xhr = new XMLHttpRequest();
// Concatenate the variables of the request parameters
var params = ' ';
// Loop over the object format parameters passed in by the user
for (var attr in defaults.data) {
// Convert arguments to string format
params += attr + '=' + defaults.data[attr] + '&';
}
// Truncate the & at the end of the argument
// Reassign the truncated result to the params variable
params = params.substr(0, params.length - 1);
// Determine the request type
if (defaults.type == 'get') {
defaults.url = defaults.url + '? ' + params;
}
// Configure the Ajax object
xhr.open(defaults.type, defaults.url);
// If the request is POST
if (defaults.type == 'post') {
// The type of request parameters that the user wants to pass to the server
var contentType = defaults.header['Content-Type']
// Sets the type of request parameter format
xhr.setRequestHeader('Content-Type', contentType);
// Determine the type of request parameter format the user wants
// If type is json
if (contentType == 'application/json') {
// Pass json data format parameters to the server
xhr.send(JSON.stringify(defaults.data))
}else {
// Pass the normal type of request parameters to the serverxhr.send(params); }}else {
// Send the request
xhr.send();
}
// Listen for the onload event under the XHR object
Emitted when the XHR object has received the response data
xhr.onload = function () {
// xhr.getResponseHeader()
// Get the data in the response header
var contentType = xhr.getResponseHeader('Content-Type');
// Data returned by the server
var responseText = xhr.responseText;
// If the response type contains applicaition/json
if (contentType.includes('application/json')) {
// Convert json strings to JSON objects
responseText = JSON.parse(responseText)
}
// When the HTTP status code is 200
if (xhr.status == 200) {
// The request was successfully invoked to handle the success of the function
defaults.success(responseText, xhr);
}else {
// Request failure calls the function that handles the failure case
defaults.error(responseText, xhr);
}
}
}
ajax({
type: 'post'.// Request an address
url: 'http://localhost:3000/responseData'.success: function (data) {
console.log('Here is the success function');
console.log(data)
}
})
</script>
Copy the code
Fetch (modern browsers come with it, IE doesn’t)
fetch("http://localhost:91/", {method:"POST".headers: {"content-type":"application/x-www-form-urlencoded"},
body:"a=12&b=77"
}).then(
res= > res.json()
).then(
data= > {console.log(data)}
)
Copy the code
Axios (default JSON format)
axios({
url:'http://localhost:90? b=12'.method:'POST'.data: {a:1.b:12}
}).then(res= >{console.log(res.data)})
Copy the code