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