ES6 Promise -- Callback versus Promise, trust issues, error handling, Promise status, and common methods for Promise objects

How to use callbacks to solve asynchronous problems before:

function f(callback){
    setTimeout(function(){
        callback && callback();
    });    
}

f(function(){
    console.log(1);
    f(function(){
        console.log(2);    
        f(function(){
            console.log(3);    
            f(function(){
                console.log(4);    
                f(function(){
                    console.log(5);    
                    f(function(){
                        console.log(6);        
                    })    
                })        
            })    
        })    
    })
})

 

Use promise to achieve the same effect

//Use promise Achieve the same effect
function f2(){
    return new Promise(resolve=>{//Parameter passed in a callback function
        setTimeout(function(){
            //Execute function on time
            resolve();
        },1000)
    })
}

f2()//Only Return Promise Instance before.then
.then(function(){
    console.log(11);
    return f2();
})
.then(function(){
    console.log(22);
    return f2();
})
.then(function(){
    console.log(33);
    return f2();
})
.then(function(){
    console.log(44);
    return f2();
})
.then(function(){
    console.log(55);
    return f2();
})
.then(function(){
    console.log(66);
    return f2();
})

 

 

Contrast callback with Promise process control

First, callback

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
    <style>
        .box{
            width:100px;
            height:100px;
            background:lightgreen;
            transition:all 1s;
            color:#fff;
            text-align:center;
            line-height:100px;
            font-size:40px;
        }
    </style>
</head>
<body>

    <div class="box">Oh</div>
    <button id="btn">start</button>
<script>
//animation
function move(el,x,y,cb){
    el.style.transform=`translate(${ x }px, ${ y }px)`;
    setTimeout(function(){
        cb && cb();
    },1000);    
}

//Get Elements
let box=document.querySelector(".box");
let btn=document.querySelector("#btn");
//Binding Events
btn.addEventListener("click",e=>{
    //Complete animation using callbacks
    move(box,100,100,function(){
        move(box,200,200,function(){
            move(box,100,300,function(){
                move(box,0,0,function(){
                    console.log("Move over!");
                })
            })    
        })    
    })    
})

</script>
</body>
</html>

Effect achieved

 

Implement with Promise

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
    <style>
        .box{
            width:100px;
            height:100px;
            background:lightgreen;
            transition:all 1s;
            color:#fff;
            text-align:center;
            line-height:100px;
            font-size:40px;
        }
    </style>
</head>
<body>

    <div class="box">Oh</div>
    <button id="btn">start</button>
<script>
//animation
function move(el,x,y){
    return new Promise(resolve=>{
        el.style.transform=`translate(${ x }px, ${ y }px)`;
        setTimeout(function(){
            resolve();
        },1000);
    })        
}

//Get Elements
let box=document.querySelector(".box");
let btn=document.querySelector("#btn");
//Binding Events
btn.addEventListener("click",e=>{
    //Use Promise Finish Animation
    move(box,100,100)
    .then(function(){        
        return move(box,200,200);
    })
    .then(function(){        
        return move(box,100,300);
    })
    .then(function(){        
        return move(box,0,0);
    })
    .then(function(){
        console.log("Move over!");
    })
})

</script>
</body>
</html>

 

Implement a picture loading; set the first picture to load 1s and then the second picture

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
    <style>
        img{width:200px;}
    </style>
</head>
<body>


<script>

//Set a function to display the url Address as parameter
function createImg(url){
    //instantiation promise object
    return new Promise(resolve=>{
        let img=new Image();//Establishing image objects
        img.src=url;//Set the address of the picture
        document.body.appendChild(img);//Insert Picture Node into body in
        setTimeout(function(){
            resolve();//Execute after picture loading is complete resolve 
        },1000);
    })
}

createImg("1.jpg")
.then(function(){
    return createImg("2.jpg")
})
.then(function(){
    return createImg("3.jpg")
});

</script>
</body>
</html>

Trust issues

//Trust Issue Demo

//Callback
function method(cb){
    setTimeout(function(){
        cb && cb();
        //Because of some bug Causes a function to execute more than once
        cb && cb();
    },1000);
}

//promise
function method2(){
    return new Promise(resolve=>{
        setTimeout(function(){
            resolve();
            //resolve After a successful call, no further execution occurs
            resolve();
        },1000);        
    })
}

 

IoC

//Callback
function method(cb){
    setTimeout(function(){
        cb && cb.call({a:1,b:2});//Execute callback, but add oil and vinegar
    },1000);
}

//promise
function method2(){
    return new Promise(resolve=>{
        setTimeout(function(){
            resolve();//Called resolve Written by myself to improve control reversal
        },1000);        
    })
}

 

error handling

function fn(val){
    //The second parameter represents what you do when you fail
    return new Promise((resolve,reject)=>{
        if(val){
            resolve();
        }else{
            reject();
        }
    })
}

fn(false)
.then(()=>{
    console.log("Success");
},()=>{
    console.log("fail");
})

 

 

Error handling callbacks can pass in parameters

function fn(val){
    //The second parameter represents what you do when you fail
    return new Promise((resolve,reject)=>{
        if(val){
            resolve();
        }else{
            reject("404");
        }
    })
}

fn(false)
.then(()=>{
    console.log("Success");
},e=>{
    console.log(e);
})

 

 

resolve can also pass parameters, but only one, not two

function fn(val){
    //The second parameter represents what you do when you fail
    return new Promise((resolve,reject)=>{
        if(val){
            resolve({a:1},{b:2});
        }else{
            reject("404");
        }
    })
}

fn(true)
.then((obj1,obj2)=>{
    console.log(obj1);
    console.log(obj2);
},e=>{
    console.log(e);
})

 

 

Using the instance's catch method, errors can be caught

If an error is returned, the error must be captured below or the code will not execute and will be skipped

function fn(val){
    //The second parameter represents what you do when you fail
    return new Promise((resolve,reject)=>{
        if(val){
            resolve("This is the data");
        }else{
            reject("404");
        }
    })
}

fn(true)
.then(data=>{
    console.log(data);
    return fn(false);//Fail, throw error
})
.then(()=>{
    console.log("There is no error handling, so it will not be performed");
})
.catch(e=>{//Capture errors, execute code
    console.log(e);
})

 

 

If there is error handling before the error is captured, the catch will not execute

function fn(val){
    //The second parameter represents what you do when you fail
    return new Promise((resolve,reject)=>{
        if(val){
            resolve("This is the data");
        }else{
            reject("404");
        }
    })
}

fn(true)
.then(data=>{
    console.log(data);
    return fn(false);//Fail, throw error
})
.then(()=>{
    console.log("There is no error handling, so it will not be performed");
})
.then(()=>{
    
},e=>{
    console.log("Errors are handled here, and the following catch Will not be executed");
})
.catch(e=>{//Capture errors, execute code
    console.log(e);
})

 

 

After catch, you can continue then, and if you throw an error again, you will need to handle it later

function fn(val){
    //The second parameter represents what you do when you fail
    return new Promise((resolve,reject)=>{
        if(val){
            resolve("This is the data");
        }else{
            reject("404");
        }
    })
}

fn(true)
.then(data=>{
    console.log(data);
    return fn(false);//Fail, throw error
})
.then(()=>{
    console.log("There is no error handling, so it will not be performed");
})
.catch(e=>{//Capture errors, execute code
    console.log(e);
    return fn(false);//Throw an error again
});

The last error thrown was not captured and therefore an error was reported

 

 

 

finally executes regardless of success or failure

function fn(val){
    //The second parameter represents what you do when you fail
    return new Promise((resolve,reject)=>{
        if(val){
            resolve("This is the data");
        }else{
            reject("404");
        }
    })
}

fn(true)
.then(data=>{
    console.log(data);
    return fn(false);//Fail, throw error
})
.catch(e=>{//Capture errors, execute code
    console.log(e);
})
.finally(()=>{
    console.log("finally Do some finishing work");
})

 

Status of Promise

panding in progress

fulfilled successfully

reject failed

 

 

Promise.all()

Wrap multiple promise instances into a new one

If all promise results are successful, the returns are successful, and the data returned by all promises is uniformly returned as an array in a one-to-one order

If a promise resolution fails, the failure is returned, and the failure information is returned

If it's an empty array, decide immediately to succeed

//Simulation requires multiple requests for data to proceed to the next step
function data1(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log("data1 Loading succeeded");
            resolve("data1");//Pass-through parameters
        },1000)
    })
}

function data2(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log("data2 Loading succeeded");
            resolve("data2");//Pass-through parameters
        },1000)
    })
}    

function data3(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log("data3 Loading succeeded");
            resolve("data3");//Pass-through parameters
        },1000)
    })
}    

function data4(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log("data4 Loading succeeded");
            resolve("data4");//Pass-through parameters
        },2000)
    })
}    

//All Successes
let res=Promise.all([data1(),data2(),data3(),data4()]);
res
.then(data=>{
    console.log(data);//Receive all parameters passed above
})

 

 

//Simulation requires multiple requests for data to proceed to the next step
function data1(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log("data1 Loading succeeded");
            resolve("data1");//Pass-through parameters
        },1000)
    })
}

function data2(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            reject("data2 err");//Data 2 request failed
        },1000)
    })
}    

function data3(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log("data3 Loading succeeded");
            resolve("data3");//Pass-through parameters
        },1000)
    })
}    

function data4(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log("data4 Loading succeeded");
            resolve("data4");//Pass-through parameters
        },2000)
    })
}    

//All Successes
let res=Promise.all([data1(),data2(),data3(),data4()]);
res
.then(data=>{
    console.log(data);//Receive all parameters passed above
},e=>{
    console.log(e);//Error executing this sentence and returning error message immediately, correct data will not be returned
})

 

 

//Simulation requires multiple requests for data to proceed to the next step
function data1(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log("data1 Loading succeeded");
            resolve("data1");//Pass-through parameters
        },1000)
    })
}

function data2(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            reject("data2 err");//Data 2 request failed
        },1000)
    })
}    

function data3(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log("data3 Loading succeeded");
            resolve("data3");//Pass-through parameters
        },1000)
    })
}    

function data4(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log("data4 Loading succeeded");
            resolve("data4");//Pass-through parameters
        },2000)
    })
}    

//All Successes
let res=Promise.all([]);
res
.then(()=>{
    console.log("Resolution Success");//Empty Array Direct Resolution Success
},e=>{
    console.log(e);//Error executing this sentence and returning error message immediately, correct data will not be returned
})

 

 

The same functionality, using pre-ES6 syntax, does not use promise.all() to achieve:

//Do not use promise.all()

let count=0;

function fn(){
    if(count<4) return;
    console.log("All data received successfully");
}

function data1(){
    setTimeout(()=>{            
        console.log("data1 Loading succeeded");
        count++;
        fn();
    },2000)
}

function data2(){
    setTimeout(()=>{            
        console.log("data2 Loading succeeded");
        count++;
        fn();
    },2000)
}    

function data3(){
    setTimeout(()=>{            
        console.log("data3 Loading succeeded");
        count++;
        fn();
    },2000)
}    

function data4(){
    setTimeout(()=>{            
        console.log("data4 Loading succeeded");
        count++;
        fn();
    },2000)
}    

data1();
data2();
data3();
data4();

 

 

If data receive fails

//Do not use promise.all()

let count=0;
let err=false;

function fn(){
    if(err) {
        console.log("Failed to receive data");
        return;
    }
    if(count<4) return;
    console.log("All data received successfully");
}

function data1(){
    setTimeout(()=>{            
        console.log("data1 Loading succeeded");
        count++;
        fn();
    },2000)
}

function data2(){
    setTimeout(()=>{            
        console.log("data2 Loading failed");
        err=true;
        fn();
    },2000)
}    

function data3(){
    setTimeout(()=>{            
        console.log("data3 Loading succeeded");
        count++;
        fn();
    },2000)
}    

function data4(){
    setTimeout(()=>{            
        console.log("data4 Loading succeeded");
        count++;
        fn();
    },2000)
}    

data1();
data2();
data3();
data4();

 

 

Promise.race()

As long as one of the resolutions in the array is successful, the immediate resolution is successful and the values are passed in

//promise.race()
function data1(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{    
            console.log("data1 Success")    ;    
            resolve("data1");
        },1000)
    })
}

function data2(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{    
            console.log("data2 Success")    ;            
            resolve("data2");
        },500)
    })
}    

function data3(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log("data3 Success")    ;                
            resolve("data3");
        },1000)
    })
}    

function data4(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{    
            console.log("data4 Success")    ;            
            resolve("data4");
        },1000)
    })
}    

let res=Promise.race([data1(),data2(),data3(),data4()]);
res
.then(data=>{
    console.log(data);//Output the earliest successful data
},e=>{
    console.log(e);
})

 

 

If there are errors, the error information will be output immediately

//promise.race()
function data1(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{    
            console.log("data1 Success")    ;    
            resolve("data1");
        },1000)
    })
}

function data2(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{    
            console.log("data2 fail")    ;            
            reject("err2");
        },500)
    })
}    

function data3(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log("data3 Success")    ;                
            resolve("data3");
        },1000)
    })
}    

function data4(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{    
            console.log("data4 fail")    ;            
            resolve("err4");
        },1000)
    })
}    

let res=Promise.race([data1(),data2(),data3(),data4()]);
res
.then(data=>{
    console.log(data);//Output the earliest successful data
},e=>{
    console.log(e);
})

 

 

If an empty array is passed in, the program is suspended

//promise.race()
function data1(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{    
            console.log("data1 Success")    ;    
            resolve("data1");
        },1000)
    })
}

function data2(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{    
            console.log("data2 fail")    ;            
            reject("err2");
        },500)
    })
}    

function data3(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log("data3 Success")    ;                
            resolve("data3");
        },1000)
    })
}    

function data4(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{    
            console.log("data4 fail")    ;            
            resolve("err4");
        },1000)
    })
}    

let res=Promise.race([]);
res
.then(data=>{
    console.log(data);//Output the earliest successful data
},e=>{
    console.log(e);
})

 

 

If ES6 promise.race() is not used, the result is as follows

//Do not use promise.race()
let flag=false;
function fn(data){
    if(flag) return;
    flag=true;//Return on request true
    console.log(data);
}

function data1(){
    setTimeout(()=>{    
        console.log("data1 Success")    ;    
        fn({name:1})
    },500)
}

function data2(){
    setTimeout(()=>{    
        console.log("data2 Success")    ;
        fn({name:2})    
    },600)
}    

function data3(){
    setTimeout(()=>{    
        console.log("data3 Success")    ;
        fn({name:3})    
    },1000)
}    

function data4(){
    setTimeout(()=>{    
        console.log("data4 Success")    ;    
        fn({name:4})
    },2000)
}    

data1();
data2();
data3();
data4();

 

 

Promise.resolve() wraps up a promise instance regardless of what value is passed in

//promise.resolve()

//Pass a common value
let p1=new Promise(resolve=>{
    console.log("p1 Resolution Success");
})

let p2=Promise.resolve("p2 Success");//Pass a common value, direct resolution is success

//Pass one promise Example
let p11=new Promise(resolve=>{
    console.log("p11 Resolution Success");
})

let p22=Promise.resolve(p11);//Pass one promise Instance, enabling p11 and p22 Equal
p11.then(data=>void console.log(data));
console.log(p11===p22);


//Define a thenable object obj
let obj={
    then(cb){
        console.log("Success")
        cb("Success")
    },
    oth(){
        console.log("fail")
    }
}
//Promise.resolve(obj) Pass one thenable object
Promise.resolve(obj).then(data=>{
    console.log(data)
})

 

 

 

Promise.reject()

Whatever value is passed in, what you get is the incoming value, which is not manipulated or processed

//promise.reject()

//Pass one thenable object obj
Promise.reject({then(){console.log("err")}})
.then(function(){
    console.log("I will not be executed");
},e=>{
    console.log(e)
})

 

 

resolve is an asynchronous task and executes when all synchronous tasks are completed

console.log(1);

let p=new Promise(resolve=>{
    console.log(2);
    resolve();//call resolve Equal to call.then,Is asynchronous, executed after all synchronizations are complete
    console.log(3);
})

console.log(4);

p.then(()=>{
    console.log(5);
})

console.log(6);

 

 

Turn synchronous tasks into asynchronous tasks

function fn(cb){
    //Returns an instance of a resolution's success and executes it asynchronously
    return Promise.resolve(cb).then(cb=>cb());
}

fn(()=>{
    console.log("I changed from synchronous to asynchronous");
    return 1+1;
}).then(res=>{
    console.log(res);//Get it return Value of
})

console.log("I'm synchronous");

 

 

Small Case

There are several sections on the page that need to be loaded before all pictures are displayed

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>es6 promise</title>
</head>
<style>
    img{height:100px;}
</style>
<body>
<script>



const loadImg=(src)=>{
    return new Promise((resolve,reject)=>{
        let img=new Image();
        img.src=src;
        //Pictures loaded successfully
        img.onload=()=>{
            resolve(img)
        }
        //Picture loading failed
        img.onerror=(e)=>{
            reject(e)
        }
        //Note that this is incorrect because the assignment is called directly, and you have not yet waited for the picture loading to complete
        // img.onload=resolve(img)
        // img.onerror=reject(e)
    })
}

const imgs=["1.jpg","2.jpg","3.jpg"];
// map By traversing src Passed in as a parameter, called circularly loadImg,Get to Returned image object
Promise.all(imgs.map(src=>loadImg(src)))
.then(res=>{
    console.log(res);
    //Traversal Insert DOM
    res.forEach(item=>{
        document.body.appendChild(item)
    })
})

</script>
</body>
</html>

 

 

 

Failure

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>es6 promise</title>
</head>
<style>
    img{height:100px;}
</style>
<body>
<script>



const loadImg=(src)=>{
    return new Promise((resolve,reject)=>{
        let img=new Image();
        img.src=src;
        //Pictures loaded successfully
        img.onload=()=>{
            resolve(img)
        }
        //Picture loading failed
        img.onerror=(e)=>{
            reject(e)
        }
        //Note that this is incorrect because the assignment is called directly, and you have not yet waited for the picture loading to complete
        // img.onload=resolve(img)
        // img.onerror=reject(e)
    })
}

const imgs=["1.jpg","22.jpg","3.jpg"];
// map By traversing src Passed in as a parameter, called circularly loadImg,Get to Returned image object
Promise.all(imgs.map(src=>loadImg(src)))
.then(res=>{
    console.log(res);
    //Traversal Insert DOM
    res.forEach(item=>{
        document.body.appendChild(item)
    })
})
.catch(e=>{
    console.log(e)
})

</script>
</body>
</html>

Tags: Javascript

Posted on Fri, 27 Mar 2020 02:42:58 -0400 by wildncrazyath3rt