Welcome to my personal blog: suilfly.github. IO /
Asynchronous programming
Because JS is a single thread, it is a bad experience for users if the thread is blocked when running. In order to solve this problem, asynchronous programming appears: when a task needs to be executed for a long time, the task is given to a module to manage, and put into the task queue after completion. When the main thread has finished executing its synchronized code (in sequence), it continuously asks if there are any completed tasks in the task queue
- Experience task operations by asynchronously loading images
let img = new Image();//imgDOM
let img = new Image();//imgDOM
function loadImg(src,resolve,reject){
img.src = src;
img.onload = resolve;
img.onerror = reject;
}
loadImg("1.jpg".() = >{
console.log('Image load completed');
},() = >{
console.log('Image load failed');
});// It takes some time to load an image through a path, so asynchrony
console.dir(img);
Copy the code
The end result
- Experience asynchronous task operations through timers
// Encapsulate a timer
function interval(callback,delay){
let id = setInterval(() = >callback(id),delay)
}
interval((id) = >{
/* Implements div right shift */
let div = document.querySelector('div');
/ / Window. GetComputedStyle () method returns the style is a real-time CSSStyleDeclaration object, when the elements of style changes, it will automatically update itself.
let left = Number.parseInt(getComputedStyle(div).left);
div.style.left = left+100+'px';
if(left > 300) {clearInterval(id);// Stop moving
interval((id) = >{// Let div fade away
let width = Number.parseInt(getComputedStyle(div).width);
div.style.width = width-10+'px';
if(width == 0)
clearInterval(id)
},100)}},600)
Copy the code
The end result
But when you do that, the nested timers make the code look messy, so later promises make the code cleaner, but the underlying principles remain the same
Task arrangement
As the name suggests: task queue. A queue is a first-in, first-out data structure, so the order in which tasks are called depends on the order in which they are called
- Experience the task order through file loading
/* 1.js */
function first(){
console.log("first");
}
/* 2.js */
function second(){
first();
console.log("second");
}
Copy the code
// Now I have to load two files (loading files requires asynchronous operation), but 2.js depends on 1.js
function fileLoad(src,resolve = null){
let script = document.createElement('script');
script.src = src;
document.body.appendChild(script);
script.onload = resolve;
}
/* the 1.js task is queued */
fileLoad("1.js");
fileLoad("2.js".() = >{
second();
});
Copy the code
However, sometimes 2.js will be loaded first, resulting in
To solve this problem, I can
function fileLoad(src,resolve = null){
let script = document.createElement('script');
script.src = src;
document.body.appendChild(script);
script.onload = resolve;
}
/* Execute onload event */ after loading 1.js
fileLoad("1.js".() = >{
/* 1.js onload event: load 2.js */
fileLoad("2.js".() = >{
second();
});
});
Copy the code
The results of
But as we’ll see, the problem was solved, but there was a lot of nesting, messy code, and callback hell, so later promises made the code cleaner
Promise the task
The tasks performed using Promise are put into the microtask queue. The tasks executed by setTimeout and setInterval are put into the macro task queue. In terms of priority, the microtask has a higher priority than the macro task
/* Three states of a Promise: pending: an initial state in which neither the operation succeeded nor the Promise was rejected. This is a big pity: which means that the operation is completed successfully. Rejected: Indicates that the operation fails. * /
let promise = new Promise((resolve,reject) = >{});
console.log(promise);Pending: Pending, because resolve or reject are not executed in the Promise constructor
Copy the code
let promise = new Promise((resolve,reject) = >{ resolve(); });
console.log(promise);// pity, because the Promise constructor executes the resolve method
Copy the code
let promise = new Promise((resolve,reject) = >{ reject(); });
console.log(promise);// Reject, because the Promise constructor executes reject
Copy the code
Promise – Chain call
/* Order of execution: the code inside the Promise constructor executes synchronously, so console.log(' inside the constructor ') is executed first; Log ("console"); Finally, after the synchronization codes of the main thread are all executed, the tasks in the microtask queue are polled and then*/ is executed
let promise = new Promise((resolve,reject) = >{
reject('error');// When this method is called, the next then task is added to the task queue
console.log('Inside the constructor');
}).then((resolve) = >{
console.log('Now execute the successful business operation'+resolve);
},(reject) = >{ console.log('Now execute the business operation after failure:'+reject) });
console.log("console");
Copy the code
Chain calls
- Promise.then() returns a Promise object again
let p1 = new Promise((resolve,reject) = >{
resolve();
})
let p2 = p1.then(a= >{ console.log('success')},b= >{ console.log(b) })
/* According to the code execution order analysis: P1 status is successful, the small task +1 p1: Promise {< depressing >: undefined} p2: Promise {
}*/
console.log(p1,p2);
/* Consider the following case */
setTimeout(() = >{
console.log(p1,p2);
})
/* Code execution order: 1. Resolve of p1, microtask +1 (so p1. Then wait to execute) 2. Synchronization code in main thread: console.log(p1,p2); When both the microtask queue and the macro task queue have tasks (and their tasks are not dependent on each other), poll the microtask queue: execute p1. Then => Output: success, microtask -1 5. SetTimeout: console.log(p1,p2); The final output after setting the timer: success 28538(timer number) Promise {< depressing >: this is a big pity. undefined} Promise {
: undefined} */
Copy the code
When p1 is in the rejected state
let p1 = new Promise((resolve,reject) = >{
reject('failure');
})
let p2 = p1.then(a= >{ console.log('success')},b= >{ console.log(b) })
/* p1:rejected p2:fulfilled */
Copy the code
- Chain call summary: The latter then is the processing of the previous Promise
let p1 = new Promise((resolve,reject) = >{
resolve('success');
}).then(a= >{
return 'Success - Task -1';// The return value string is used to pass arguments to the next microtask
}).then(a= >{
console.log(a);
})
/* Output: success - task -1 */
let p1 = new Promise((resolve,reject) = >{
resolve('success');
}).then(a= >{
return new Promise((resolve,reject) = >{});/* Returns a new Promise, state pending, so the second then waits for this promise state to change before executing */
}).then(a= >{
console.log(a);
})
/* No output */
Copy the code
The final output order is:
Microtasks and macro tasks
/* Order of execution: 1. Place setTimeout in macro task queue 2.console.log(' inside constructor '); 3.console.log("console"); 4.1 Adding a task to the microtask 4.2 console.log('setTimeout'); Resolve */ in 4.3 then
let promise = new Promise((resolve,reject) = >{
setTimeout(() = >{
resolve('sucess');// Add a task to the microtask queue
console.log('setTimeout');
},0)
console.log('Inside the constructor');
}).then((resolveMsg) = >{
console.log('Now execute the successful business operation'+resolveMsg);
},(rejectMsg) = >{ console.log('Now execute the business operation after failure:'+rejectMsg) });
console.log("console");
Copy the code
Promise state transfer
let p1 = new Promise((resolve,reject) = >{
resolve('p1 success');
}).then();
let p2 = new Promise((resolve,reject) = >{
resolve(p1);// Notice that a Promise object is passed in, so what does that mean?
}).then();
console.log(p1,p2);
/* This is a big pity. Promise {< big pity >: "P1 success "} */
let p1 = new Promise((resolve,reject) = >{
reject('p1 failure');
})
let p2 = new Promise((resolve,reject) = >{
resolve(p1);// The second callback of THEN is executed because p1 is rejected
}).then(msg= >{ console.log(msg); },rejectmsg= >{ console.log(rejectmsg+'error'); });
console.log(p1);
/* this is a big pity; /* P1 :Promise (< rejectmsg+'error') =>{console.log(rejectmsg+'error'); Output: P1 failed error */
/* This means that p2 passes p1's state as a Promise, and p2 executes the corresponding callback */ based on p1's state
Copy the code