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

Promise是什么?Promise怎么使用?回调地狱[通俗易懂]1、Promise的概念Promise是ES6提供的原生的类(构造函数),用来传递异步操作的消息。它代表了某个未来才会知道结果的事件(通常是一个异步操作)2、Promise的两个特点:1)、对象的状态不受外界影响。Promise有三种状态:Pending(进行中)、Resolved(已完成,又称Fulfilled)和Rejected(已失败)。2)、一旦状态改变,就不会再变状态改变,只有两种可能:从Pending变为Resolved和从Pending变为Reje

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

1、Promise的概念

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

2、Promise的两个特点:

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

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

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

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

3、Promise的作用

解决回调地狱的问题。

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

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将回调模式的主从关系调换了一个位置,变成了同等的只是顺序的关系

fn1().then(fn2).then(fn3).then(fn4)

4、Promise类的方法

console.dir(Promise)查看一下。

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

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方法的基本使用:

let p1 = new Promise(function(resolve,reject){
    resolve();
    reject();
});
​
​
p1.then(function(){
    console.log("then方法的第一个参数");
},function(){
    console.log("then方法的第二个参数");
});

带上异步操作

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的回调,

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的参数(输入)

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的参数(数组形式)。

//示例一:
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)时,就调用方法了。即:多个异步操作,同时执行,谁快就用谁的结果,所以,结果不再是数组。

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

​
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;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Win10 桌面美化

    Win10 桌面美化Win10桌面美化最近发现了几款Win10界面美化的软件,看了看别人家的Win10操作界面,瞬间觉得自己的low了,关键是赏心悦目啊!废话不多说,先看看我原来桌面和美化后的桌面对比图原始桌面美化桌面1.安装RocketDockRocketDock可以提供类似macos的操作系统图标特效,打开安装包进行安装,完毕后启动得到效果如下:可以发现切换效果与mac类似,他默认的主题是C…

  • 通达OA 公共文件柜二次开发添加管理信息(图文)[通俗易懂]

    通达OA 公共文件柜二次开发添加管理信息(图文)

  • idea插件Tabnine激活码_在线激活

    (idea插件Tabnine激活码)这是一篇idea技术相关文章,由全栈君为大家提供,主要知识点是关于2021JetBrains全家桶永久激活码的内容https://javaforall.cn/100143.htmlIntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,上面是详细链接哦~MLZPB5EL5Q-eyJsaWNlb…

  • malloc函数的用法(超级白话版)[通俗易懂]

    malloc函数的用法(超级白话版)[通俗易懂]malloc函数的用法在这里,我不讲什么原理性的东西,我就单纯讲讲怎么用。首先malloc()函数返回的是void*类型,所以用的时候要进行强制类型转换malloc函数用完后,记得使用free()函数来释放空间,不然只分配不释放会出问题例L=(int*)malloc(sizeof(int));我们看到了先用int*进行了强制类型转换,说明L的类型为int*,⚠️如果你不进行强制类型转换,分配空间会报错sizeof(int)的意思是分配的字节数,分配和int类型一样的字节数,当然,

  • mqtt支持加密通讯

    mqtt支持加密通讯1.mqtt第三方库支持openssla,编译openssl库(我使用的是1.0.1),在mqtt源码目录下创建openssl文件夹,并拷贝编译完成的库文件与头文件到此文件夹下。b,修改mqtt(源码从git上获取https://github.com/eclipse/paho.mqtt.c.git)编译选项,PAHO_WITH_SSL,OPENSSL_SEARCH_PATH…

  • BootstrapVue使用入门

    BootstrapVue使用入门网站:https://www.npmjs.com/package/bootstrap-vuehttps://bootstrap-vue.js.org/docs入门开始使用BootstrapVue,它基于世界上最流行的框架-Bootstrapv4,用于使用Vue.js构建响应迅速,移动优先的站点。Vue.jsv2.6是必需的,v2.6.10建议 引导v4.3是必需的,…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号