博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JavaScript---Promise
阅读量:5152 次
发布时间:2019-06-13

本文共 11063 字,大约阅读时间需要 36 分钟。

  什么是Promise?

     Promise是ES6新增的对象。他是构造函数,通过构造实例来使用他的方法。 var p = new Promise();

 

   Promise是干什么用的

    用来传递异步操作的消息(如ajax请求),它代表了某个未来才会知道结果的事件(通常是一个异步操作)

 

   Promise的3种状态:

       1.Pending(未完成)---译为‘即将发生的’,可以理解为Promise对象创建实例的初始状态;

        2. Resolved(成功)---译为‘已解决的’,可以理解为成功的状态;

        3.Rejected(失败)--译为‘拒绝的’,可以理解为失败的状态。

 

   Promise对象的特点

        1.Promise的状态不受外界影响。只有异步操作的结果,才可以决定当前是什么状态,其他任何操作都无法改变他的状态。

        2.一旦状态发生改变,就不会再变,任何时候都可以得到这个结果。Promise对象的的状态改变,只有两种情况:1.Pending变为Resolved, 2.Pending变为Rejected。只要这两种情况发生其中一个,另一个是不会发生的。因为状态会凝固,即使你还想添加回调函数试图改变结果,也不起作用。

    什么时候用promise?函数回调多层嵌套(有依赖关系)

      来看一个demo:多个ajax的请求(存在依赖)

 

      常用的方式:使用函数嵌套

 

$.ajax({                url:'http://localhost/api/req1.php',                success:function(str1){                    console.log(str1);                    $.ajax({                        url:'http://localhost/api/req2.php',                        success:function(str2){                            console.log(str2);                            $.ajax({                                url:'http://localhost/api/req3.php',                                success:function(str3){                                    console.log(str3);                                    document.body.innerHTML = str1 + str2 + str3                                }                            })                        }                    })                }            })

 

 

 

  ajax的多层嵌套会造成阻塞,只有前一个请求成功了,下一个请求才会开始执行,万一前一个请求执行失败,下一个请求永远无法执行,造成页面‘假死’。

  再来看promise是如何处理的?

    Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve 方法和 reject 方法。

    如果异步操作成功,则用 resolve 方法将 Promise 对象的状态,从「未完成」变为「成功」(即从 pending 变为 resolved)。

    如果异步操作失败,则用 reject 方法将 Promise 对象的状态,从「未完成」变为「失败」(即从 pending 变为 rejected)。

 

 

var p1 = new Promise(function(resolve,reject){            // 这时的状态:pending            $.ajax({                url:'http://localhost/api/req1.php',                success:function(str1){                    // console.log(str1);                                                            //把promise对象的状态改成resolved                    //只要状态被修改成resolved,就不会再改变                    resolve(str1);                }            })        });        var p2 = new Promise(function(resolve,reject){            $.ajax({                url:'http://localhost/api/req2.php',                success:function(str2){                    // console.log(str2);                    resolve(str2);                }            })        });        var p3 = new Promise(function(resolve,reject){            $.ajax({                url:'http://localhost/api/req3.php',                success:function(str3){                    // console.log(str3);                    resolve(str3)                }            });        });        // 等3个请求都成功后        // 把数据写入页面        var pAll = Promise.all([p1,p2,p3]);        pAll.then(function(data){            console.log('所有:',data);        });        // 返回第一个完成的数据        var pFast = Promise.race([p1,p2,p3]);        pFast.then(function(data){            console.log('手速最快:',data);        });

 

    再来看具体的实例:

      比如:获取当前城市的天气预报API-->获取当前城市API-->获取当前城市的ip地址API

    
多个ajax请求

 

  在chrome中显示:

 

  补充:Promise对象的内置方法

    Promise.all(p1,p2,p3...)---将多个Promire 实例包装成一个新的Promise实例 注:所有的参数中的promise状态都为resolved时,新的promise状态才为

resolved,一个是rejected,新的promise状态为rejected。

    Promise.race()---竞速模式  返回最先执行完的resolved结果。

    原型方法:Promise.prototype.then(successFn[,failFn]) ---Promise实例生成以后,可以用then方法分别指定Resolved状态和Rejected状态的回调函数。并根据Promise对象的状态来确定执行的操作:

        1.resolved时执行第一个函数successFn。

        2.rejected时执行第二个函数failFn。

var p = new Promise(function(resolve, reject){    //ajax请求    ajax({        url:'xxx.php',        success:function(data){            resolve(data)        },        fail:function(){            reject('请求失败')        }    });});//指定Resolved状态和Rejected状态的回调函数//一般用于处理数据p.then(function(res){    //这里得到resolve传过来的数据},function(err){    //这里得到reject传过来的数据})

      Promise对象就暂告一段落, 细节以后慢慢补充         

                                       2017-3-27   15:20

---------------------------------------------------------------------------------更新!!!!----------------------------------------------------------------------------

前天面试的时候,面试官有问到promise用法,但是好久没用了。竟然忘了!!!!! 这充分说明了,回顾知识是多么重要!!! 你永远不知道,你下一秒会不会用到。

  回到正题:

    前面说道,创建一个promise对象,只需“new”一个就好了。

var p1 = new Promise(function(resolve,reject){            setTimeout(function () {                alert('666');            },2000);        })

  试着执行这一段代码,2秒后弹出框“666”。 感觉有点怪怪的,我只是“new”出来一个promse对象而已,并没有调用啊,他怎么自动执行了?注意这个细节。一般地,promise对象放到一个函数里面,不要让他自动执行。

  

function runAsync() {            var p1 = new Promise(function (resolve, reject) {
          // 异步操作的代码 setTimeout(function () { alert('666'); }, 2000); }); return p1 } runAsync();

 

  上面的写法,返回实例promise。然后直接可以调用then() 方法了。 then方法接收一个函数作为参数,并且会拿到我们在runAsync中调用resolve时传的的参数。

来,感受一下:

  

function runAsync() {            var p1 = new Promise(function (resolve, reject) {                setTimeout(function () {                   console.log('666');                    var obj = {                        name:'jjk',                        age:18                    }                    resolve(obj)                }, 2000);            });            return p1        }        runAsync().then(function(data){            console.log(data);        })

  在chrome中显示:

  

 then里面的函数就跟我们平时的回调函数一个意思,能够在runAsync这个异步任务执行完成之后被执行。这就是Promise的作用了,简单来讲,就是能把原来的回调写法分离出来,在异步操作执行完后,用链式调用的方式执行回调函数。看到这里,疑问就来了,回调函数不是也可以做到这一点么?

function runAsync(callback){             setTimeout(function () {                    console.log('666');                    var obj = {                        name:'jjk',                        age:18                    }                   callback(obj);                }, 2000);        }        runAsync(function(data){            console.log(data);        })

  看来Promise不怎么样啊。别急,试想一下,有多层回调该怎么办?如果callback也是一个异步操作,而且执行完后也需要有相应的回调函数,该怎么办呢?总不能再定义一个callback2,然后给callback传进去吧。而Promise的优势在于,可以在then方法中继续写Promise对象并返回,然后继续调用then来进行回调操作。从表面上看,Promise只是能够简化层层回调的写法,而实质上,Promise的精髓是“状态”,用维护状态、传递状态的方式来使得回调函数能够及时调用,它比传递callback函数要简单、灵活的多。所以使用Promise的正确场景是这样的:

function runAsync1() {            var p1 = new Promise(function (resolve, reject) {                setTimeout(function () {                    console.log('111');                    resolve('第一次')                }, 2000);            });            return p1        };        function runAsync2() {            var p2 = new Promise(function (resolve, reject) {                setTimeout(function () {                    console.log('222');                    resolve("第二次")                }, 2000);            });            return p2        };        function runAsync3() {            var p3 = new Promise(function (resolve, reject) {                setTimeout(function () {                    console.log('333');                    resolve("第三次")                }, 2000);            });            return p3        };        runAsync1().then(function (data) {            console.log(data);            return runAsync2()        })        .then(function (data) {                console.log(data);                return runAsync3()            })        .then(function (data) {                console.log(data);            })

  在chrome中显示:

    

  在then方法里面直接返回promise实例,然后继续链式调用。那么,如果我不返回实例,而是直接返回数据,还能链式调用吗?

  

function runAsync1() {            var p1 = new Promise(function (resolve, reject) {                setTimeout(function () {                    console.log('111');                    resolve('第一次')                }, 2000);            });            return p1;        };        function runAsync2() {            var p2 = new Promise(function (resolve, reject) {                setTimeout(function () {                    console.log('222');                    resolve("第二次")                }, 2000);            });            return p2;        };        function runAsync3() {            var p3 = new Promise(function (resolve, reject) {                setTimeout(function () {                    console.log('333');                    resolve("第三次")                }, 2000);            });            return p3;        };        runAsync1().then(function (data) {            console.log(data);            return '直接返回数据看看'        })        .then(function (data) {                console.log(data);                return runAsync3()            })        .then(function (data) {                console.log(data);            })

  在chrome中显示

结果显而易见,返回数据之后,还可以调用then方法,可then方法不是promise的方法吗? 答案是这样的:then方法返回数据时,会把数据包装成promise对象,以供下一个then调用。

 

  事实上,我们前面的例子都是只有“执行成功”的回调,还没有“失败”的情况,reject的作用就是把Promise的状态置为rejected,这样我们在then中就能捕捉到,然后执行“失败”情况的回调。

  

function runAsync() {            var p1 = new Promise(function (resolve, reject) {                setTimeout(function () {                    var num = Math.ceil(Math.random() * 10);                    if (num <= 5) {                        resolve(num);                    } else {                        reject('warming')                    }                }, 1000)            });            return p1;        }        runAsync().then(function (data) {            console.log('resolved');            console.log(data);        }, function (reason, data) {            console.log('rejected');            console.log(reason);            console.log(data);        })

在chrome中显示:

   或者

 可以看出then方法接收2个函数作为参数,第一个参数是状态成功时执行,第二个参数是状态失败后执行,该函数的第一个参数就是reject的数据。

 

  说完了then方法,还要说说其他方法

  catch,它是做什么用的呢?其实它和then的第二个参数一样,用来指定reject的回调,用法是这样:

function runAsync() {            var p1 = new Promise(function (resolve, reject) {                setTimeout(function () {                    var num = Math.ceil(Math.random() * 10);                    if (num <= 5) {                        resolve(num);                    } else {                        reject('warming')                    }                }, 1000)            });            return p1;        }        runAsync()        .then(function (data) {            console.log('resolved');            console.log(data);        })        .catch(function(err){            console.log('rejected');            console.log(err);        })

  不过它还有另外一个作用:在执行resolve的回调(也就是上面then中的第一个参数)时,如果抛出异常了(代码出错了),那么并不会报错卡死js,而是会进到这个catch方法中。来看代码:

function runAsync() {            var p1 = new Promise(function (resolve, reject) {                setTimeout(function () {                    var num = Math.ceil(Math.random() * 10);                    if (num <= 5) {                        resolve(num);                    } else {                        reject('warming')                    }                }, 1000)            });            return p1;        }        runAsync()        .then(function (data) {            console.log('resolved');            console.log(data);            console.log(num);        })        .catch(function(err){            console.log('rejected');            console.log(err);        })

   当进入resolve状态时,在chrome中显示:

  

  这个跟try/catch 类似。

 

转载于:https://www.cnblogs.com/first-time/p/6626912.html

你可能感兴趣的文章
Maven安装配置
查看>>
ORA-10635: Invalid segment or tablespace type
查看>>
计算机改名导致数据库链接的诡异问题
查看>>
Windows 8 操作系统 购买过程
查看>>
软件工程课程-个人编程作业
查看>>
Java8内存模型—永久代(PermGen)和元空间(Metaspace)(转)
查看>>
ObjectiveC基础教程(第2版)
查看>>
centos 引导盘
查看>>
Notes of Daily Scrum Meeting(12.8)
查看>>
Apriori算法
查看>>
onlevelwasloaded的调用时机
查看>>
求出斐波那契数组
查看>>
Vue.js 基础学习之组件通信
查看>>
lr_start_transaction/lr_end_transaction事物组合
查看>>
每天一个Linux命令 - 【chkconfig】
查看>>
△UVA10106 - Product(大数乘法)
查看>>
golang (7) 文件操作
查看>>
关于 Object.defineProperty()
查看>>
[转] Maven 从命令行获取项目的版本号
查看>>
CodeIgniter学习笔记(四)——CI超级对象中的load装载器
查看>>