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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • SQL 分页查询 返回总条数

    SQL 分页查询 返回总条数分页查询返回总数SELECTSQL_CALC_FOUND_ROWS*FROMtbWHERExxxlimitM,N;SELECTFOUND_ROWS();

    2022年6月26日
    35
  • ICE初识

    ICE初识
    ICE:InternetCommunicationsEngine
    一种适用于异种环境的面向对象中间件平台
    他为我们提供了除DCOM,CORBA,JAVARMI,.NETRemoting,WebService,SOAPRPC以外的一种远程调用方式。
    更重要的是ICE是一种跨操作系统跨语言的远程调用方式(支持.NET1.1MONO1.0)。

    主页在:http://www.zeroc.com/index.html

    2022年6月1日
    31
  • c语言rand函数生成随机数,详解C语言生成随机数rand函数的用法[通俗易懂]

    说到rand函数,大家是不是会和EXCEL中的rand函数混淆,当小编第一次接触的时候也以为是EXCEL的函数,本文是爱站技术频道小编为大家带来的详解C语言生成随机数rand函数的用法,一起来看看吧!函数rand()是真正的随机数生成器,而srand()会设置供rand()使用的随机数种子。如果你在第一次调用rand()之前没有调用srand(),那么系统会为你自动调用srand()。而使用同种子…

    2022年4月18日
    45
  • L2-026 小字辈(dfs深搜)「建议收藏」

    L2-026 小字辈(dfs深搜)「建议收藏」原题链接本题给定一个庞大家族的家谱,要请你给出最小一辈的名单。输入格式:输入在第一行给出家族人口总数 N(不超过 100 000 的正整数) —— 简单起见,我们把家族成员从 1 到 N 编号。随后第二行给出 N 个编号,其中第 i 个编号对应第 i 位成员的父/母。家谱中辈分最高的老祖宗对应的父/母编号为 -1。一行中的数字间以空格分隔。输出格式:首先输出最小的辈分(老祖宗的辈分为 1,以下逐级递增)。然后在第二行按递增顺序输出辈分最小的成员的编号。编号间以一个空格分隔,行首尾不得有多余空格。

    2022年8月8日
    2
  • ListNode示例

    ListNode*partition(ListNode*head,intx){ListNoderes(0),mid(0);if(!head)returnNULL;ListNode*small=&res;ListNode*big=∣while(head){if(head->val<

    2022年4月8日
    40
  • PAT乙级题目答案汇总 PAT (Basic Level) Practice (中文)[通俗易懂]

    PAT乙级题目答案汇总 PAT (Basic Level) Practice (中文)[通俗易懂]题目列表:标号题目链接分数博客链接完成时间1001害死人不偿命的(3n+1)猜想151001害死人不偿命的(3n+1)猜想(15分)2020/8/01

    2022年5月29日
    35

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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