前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Promise是什么?Promise怎么使用?回调地狱[通俗易懂]

Promise是什么?Promise怎么使用?回调地狱[通俗易懂]

作者头像
全栈程序员站长
发布2022-09-05 15:04:09
5060
发布2022-09-05 15:04:09
举报
文章被收录于专栏:全栈程序员必看

大家好,又见面了,我是你们的朋友全栈君。

1、Promise的概念

Promise是ES6提供的原生的类(构造函数), 用来传递异步操作的消息。它代表了某个未来才会知道结果的事件(通常是一个异步操作)

2、Promise的两个特点:

1)、对象的状态不受外界影响。

Promise 有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和 Rejected(已失败)。

2)、一旦状态改变,就不会再变

状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected

3、Promise的作用

解决回调地狱的问题。

回调地狱的代码(使用setTimeout):

代码语言:javascript
复制
function fn1(cb){
    console.log("fn1开始");
    setTimeout(function(){
        console.log("fn1的异步操作");
        cb();
    },1000);
    console.log("fn1结束");    
}
​
function fn2(cb){
    console.log("fn2开始");
    setTimeout(function(){
        console.log("fn2的异步操作");
        cb();
    },1000);
    console.log("fn2结束");    
}
function fn3(cb){
    console.log("fn3开始");
    setTimeout(function(){
        console.log("fn3的异步操作");
        cb();
    },1000);
    console.log("fn3结束");    
}
​
​
function fn4(){
    console.log("fn4开始");
    console.log("fn4结束");    
}
​
// 把fn1 里的代码全部(包括异步操作)执行完毕后,执行fn2,fn2的异步操作执行完毕,再执行fn3;
fn1(function(){
    fn2(function(){
        fn3(fn4);
    })
});
​

Promise 对象可以将异步操作以同步操作的流程表达出来(使用链式的写法),避免了层层嵌套的回调函数。

如:函数fn1和fn2,当我们需要在fn1(fn1函数里有异步操作)调用结束后调用fn2,一般的解决方案是fn1(fn2)。而promise的做法是 fn1().then(fn2);即Promise将回调模式的主从关系调换了一个位置,变成了同等的只是顺序的关系

代码语言:javascript
复制
fn1().then(fn2).then(fn3).then(fn4)

4、Promise类的方法

console.dir(Promise)查看一下。

1、promise构造函数的参数是个函数 2、该函数(Promise的参数)的参数有两个:resolve,reject resolve 表示异步操作成功时,要调用的函数。是then函数的第一个参数 reject 表示异步操作失败时,要调用的函数。是then函数的第二个参数

代码语言:javascript
复制
new Promise(function(resolve, reject){
    
    
    // 异步操作的代码
​
    // 如果异步操作成功,调用resolve;如果失败,调用reject;
    
});

1)、 对象方法:then、catch

then方法:

功能:把then方法的参数传给resolve和reject。 promise对象.then(resolve回调函数,reject回调函数);

参数:

then方法的第一个参数是resolve

then方法的第二个参数是reject。

返回值:promise对象本身,所以,then调用完毕后,还可以继续调用then(即:链式调用)

then方法的基本使用:

代码语言:javascript
复制
let p1 = new Promise(function(resolve,reject){
    resolve();
    reject();
});
​
​
p1.then(function(){
    console.log("then方法的第一个参数");
},function(){
    console.log("then方法的第二个参数");
});

带上异步操作

代码语言:javascript
复制
function fn(){
    var p = new Promise(function(resolve, reject){
        
        //做一些异步操作
        setTimeout(function(){
            console.log(‘异步执行完成');
             resolve(‘姥姥的话就是你长大听不到的那些话');//这是then函数的参数;
        }, 2000);
        
    });
    return p;
}
​
fn().then((str)=>{
    console.log(str);
},()=>{})
​

catch方法:

它和then的第二个参数一样,用来指定reject的回调,

代码语言:javascript
复制
function fn(){
    var p = new Promise(function(resolve, reject){
        //做一些异步操作
        setTimeout(function(){
            console.log(‘异步执行完成');
             resolve(‘姥姥的话就是你长大听不到的那些话');//这是then函数的参数;
        }, 2000);
    });
    return p;
}
​
fn()
.then(()=>{})
.catch(()=>{})

Promise中then方法的数据传递

上一个then的返回值(结果)是下一个then的参数(输入)

代码语言:javascript
复制
function fn1(){
    console.log("fn1开始");
    let p = new Promise(function(resolve,reject){
        setTimeout(function(){            
            console.log("fn1的异步操作");
            resolve(3)
        },1000);
    });
    console.log("fn1结束");  
    return p;
}
​
​
fn1().then(function(num){
    console.log("第一次",num);//3
    return num+1;
}).then(function(num){
    console.log("第二次",num);//4
    return num+1;
}).then(function(num){
    console.log("第三次",num);//5
    return num+1;
});
​

2)、类方法: all , race

all方法:

功能: Promise.all可以并行执行多个异步操作,并且在一个回调中处理所有的返回数据。返回的数据与传的参数数组的顺序是一样的。当所有的异步操作都成功才表示成功 。

参数:数组。数组里是若干个返回promise对象的函数(异步操作);

返回值:promise对象。promise对象的then方法的回调函数的参数是 所有promise对象的resolve的参数(数组形式)。

代码语言:javascript
复制
//示例一:
function fn1(num){
    console.log("fn1开始",num);
    let p = new Promise(function(resolve,reject){
        setTimeout(function(){            
            console.log("fn1的异步操作",num);
            resolve("fn1异步的结果:"+num)
        },1000);
    });
    console.log("fn1结束",num);    
    return p;
}
​
​
Promise.all([fn1(1),fn1(2)]).then(function(result){
    // 这个函数要执行,必须保证,fn1(1)和fn1(2)都成功,才调用。
    // 参数result是数组,保存着多次异步操作的结果,也就是把多个异步操作中resolve函数的参数放到了result里
    console.log("result",result);
});
​
​
示例二:
​
function fn1(){
    console.log("fn1开始");
    let p = new Promise(function(resolve,reject){
        setTimeout(function(){            
            console.log("fn1的异步操作");
            resolve("fn1异步的结果")
        },1000);
    });
    console.log("fn1结束");    
    return p;
}
​
​
function fn2(str){
    console.log("fn2开始");
    let p = new Promise(function(resolve,reject){
        setTimeout(function(){
            console.log("fn2的异步操作");
            resolve("fn2异步的结果");
        },3000);
    });    
    console.log("fn2结束");    
    return p;
}
​
Promise.all([fn1(),fn2()]).then(function(result){
    console.log("result",result); //["fn1异步的结果","fn2异步的结果"]
});
​

用Promise.all来执行,all接收一个数组参数,两个异步操作是并行执行的,等到它们都执行完后才会进到then里面。而两个异步操作返回的数据都在then里面,all会把所有异步操作的结果放进一个数组中传给then,就是上面的results

race方法:

功能:也是并发,但是,与all不同之处时,当一个异步操作完成(resolve或reject)时,就调用方法了。即:多个异步操作,同时执行,谁快就用谁的结果,所以,结果不再是数组。

代码语言:javascript
复制
function fn1(){
    console.log("fn1开始");
    let p = new Promise(function(resolve,reject){
        setTimeout(function(){            
            console.log("fn1的异步操作");
            resolve("fn1异步的结果")
        },1000);
    });
    console.log("fn1结束");    
    return p;
}
​
​
function fn2(str){
    console.log("fn2开始");
    let p = new Promise(function(resolve,reject){
        setTimeout(function(){
            console.log("fn2的异步操作");
            resolve("fn2异步的结果");
        },3000);
    });    
    console.log("fn2结束");    
    return p;
}
​
Promise.race([fn1(),fn2()]).then(function(result){
    console.log("result",result); //"fn1异步的结果"
});

总结Promise的使用步骤

1、找到(曾经的)异步操作的代码,放在Prmoise构造函数的参数(函数)里 2、参数(函数)的第一个参数resolve是成功时调用的函数,对应then方法(函数)的第一个参数 3、参数(函数)的第二个参数reject是失败时调用的函数,对应then方法(函数)的第二个参数

5、 Promise封装AJAX

代码语言:javascript
复制
​
function ajaxUsePromise(obj){
     let p = new Promise(function(resolve,reject){
        let defaultObj = {
            url:"#",
            method:"get",
            params:"",
            isAsync:true
        }
​
        for(let key in defaultObj){
            if(obj[key]!=undefined){
                defaultObj[key] = obj[key];
            }
        }
​
        let xhr =new XMLHttpRequest();
​
        let urlAndParams = defaultObj.url;
​
        if(defaultObj.method.toLowerCase()=="get"){
            urlAndParams += "?"+ defaultObj.params;
        }
​
        xhr.open(defaultObj.method,urlAndParams,defaultObj.isAsync);    
       
            xhr.onreadystatechange = function(){
                if(xhr.readyState==4){
                    if(xhr.status==200){
                        resolve&&resolve(xhr.responseText);
                    }else{
                        reject&&reject("服务器出错了");
                    }
                }
            }  
        });
​
        if(defaultObj.method.toLowerCase()=="post"){
            xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
            xhr.send(defaultObj.params);
        }else{
            xhr.send();
        }
​
        return p;
}

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/135592.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年6月4,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档