Promise | 学习笔记核心分享

有很多操作都需要从服务器验证是否具有操作权限,为了避免重复代码,为了避免重复代码,我们可以将验证权限的功能当作是一个异步任务,并把它提取成一个方法。

首先来模拟验证权限的过程,更好的理解为什么会有promise的存在。

 1  //是否拥有权限
 2         function hasPermission(username, callback) {
 3             console.log("开始询问服务器," + username + "是否有权限");
 4             //向服务器询问username是否有权限
 5             setTimeout(() => {
 6                 var rad = Math.random();
 7                 if (rad < 0.1) {
 8                     //网络连接失败
 9                     //后续处理
10                 } else if (rad < 0.5) {
11                     //后续处理
12                 } else {
13                     //后续处理
14                       }
15             }, 1000)
16         }

 按照上述1.0代码编写,所需功能会存在不灵活的情况,可以理解为写死了,而实际中会存在很多种情况。那我们再用伟大的回调来解决这个问题

 1  //是否拥有权限
 2         function hasPermission(options) {
 3             //向服务器询问username是否有权限
 4             setTimeout(() => {
 5                 var rad = Math.random();
 6                 if (rad < 0.1) {
 7                     //网络连接失败
 8                     options.onEnd(0)
 9                 } else if (rad < 0.5) {
10                     //没有权限
11                     options.onEnd(2)
12                 } else {
13                     //有权限
14                     options.onEnd(1)
15                 }
16             }, 1000)
17         }
18 
19         //评论
20         hasPermission({
21             username: "张三",
22             onEnd: function(result) {
23                 if (result === 0) {
24                     //网络有问题:弹出提示
25                 } else if (result === 1) {
26                     //有权限
27                     //评论
28                 } else {
29                     //没有权限:弹出提示
30                 }
31             }
32         })

js 经常会遇到一些异步任务,所谓的异步任务,就是需要经过一段时间或当某一个时机到达后才能得到结果。

例如:

  • l  使用Ajax请求服务器,当服务器完成响应后拿到响应结果
  • l  监听按钮是否被点击,当按钮被点击后拿到某个文本框的值
  • l  使用setTimeout等待一段时间后做某些事情

面对这样的场景,js没有一种标准的模式来进行处理。我们处理这些问题的方式是杂乱的,这就导致了不同的人书写的异步任务代码使用方式不一致。

ES6总结了各种异步场景,并提出一种通用的异步模型。

以前使用node回调模式解决

1.所有的回调函数不能作为属性出现

2所有对调函数必须作为函数的最后参数

3.所有回调函数必须有两个参数,第一个参数表示错误,第二个参数表示结果(erro优先)

if (rad < 0.1) {

                    //网络连接失败

                    callback("网络连接失败", null)

                } else if (rad < 0.5) {

                    //没有权限

                    callback(null, false)

                } else {

                    //有权限

                    callback(null, true)

                }

 

ES6的异步处理模型

es6将异步场景分为两个阶段三种状态

两个阶段:unseteled(未决)和seteled(已决)

三种状态:pending(挂起)、resolved(完成)、rejected(失败)

 

当任务处于未决阶段时,它一定是pending挂起状态,表示任务从开始拿到结果之间的过程。比如:网络完成了各种配置,也发送了请求,但是请求结果还没有拿到。

 

当任务处于已决阶段时,它只能是resolved和rejected两种状态的一种,表示任务有了一个结果。比如:从服务器拿到了数据(resolved)、网络不好没有拿到数据(rejected)

eg:询问服务器,赵点点是否有权限,服务器告诉你,没有权限。(已决阶段resolved)

 

任务开始时,始终是未决阶段那任务如何才能走向未决阶段呢?

 

ES6认为,任务在未决阶段的时候,有能力将其推向已决。比如,当服务器拿到数据后,我们就从未决阶段推向已决的resolved状态,如果网络不好,导致出错了,我们就从未决阶段推向已决的rejected状态

 

我们把未决推向已决的resolved状态的过程,叫做resolve,从未决推向已决的rejected状态的过程叫做reject

 if (rad < 0.1) {
                        // 网络连接失败、服务器报错了
                        // 推向rejected,附带错误数据
                        reject("网络连接失败")
                    } else if (rad < 0.5) {
                        // 没有权限
                        // 推向resolved,附带false(数据)
                        resolve(false)
                    } else {
                        // 有权限
                        // 推向resolved,附带true(数据)
                        resolve(true)
                    }

 

这种状态和阶段的变化是不可逆的,也就是说,一旦推向已决,就无法重新改变状态

 

任务从未决到已决时,可以附带一些数据,比如:跑步完成后的用时、网络请求后拿到的数据

任务已决后(有了结果),可能需要进一步做后续处理,如果任务成功了(resolved),有后续处理,如果任务失败了(rejected),任然可能有后续处理。

 

我们把针对resolved的后续处理,称之为thenable,针对rejected的后续处理,称之为catchable

promise的基本使用

ES官方制定了一个全新的API来适配上面提到的异步模型,这个API即promise

 

promise是一个构造函数,通过new Promise()可以创建一个任务对象,构造函数的参数是一个函数,用于处理未决阶段的事务,该函数的执行是立即同步执行的。在函数中,可以通过两个参数自主的在何使的时候将任务推向已决阶段。

 

拿到promise对象后,可以通过then方法指定后续处理

 var task = new Promise((resolve, reject) => {
            //任务在未决阶段的代码
            //立即执行
            console.log("开始一百米长跑");
            setTimeout(() => {
                if (Math.random() < 0.5) {
                    //失败:腿摔断了
                    //推向rejected
                    reject("腿摔断了");
                } else {
                    var rad = Math.floor(Math.random() * 100); //跑了多少秒
                    //推向resolve
                    resolve(rad);
                }
            }, 3000);
        });

        task.then(data => { //thenable
            console.log("跑步完成,用时:" + data)
        })

        task.catch(err => {
            console.log("出错了,错误原因是:" + err)
        })

//还可以写成
        task.then(data => { //thenable
            console.log("跑步完成,用时:" + data)
        },err => {
            console.log("出错了,错误原因是:" + err)
        })

so:

         promise处理权限验证3.0

//是否拥有权限: 异步任务
        function hasPermission(username) {
            return new Promise((resolve, reject) => {
                console.log("开始询问服务器," + username + "是否有权限");
                //向服务器询问username是否有权限
                setTimeout(() => {
                    var rad = Math.random();
                    if (rad < 0.1) {
                        // 网络连接失败、服务器报错了
                        // 推向rejected,附带错误数据
                        reject("网络连接失败")
                    } else if (rad < 0.5) {
                        // 没有权限
                        // 推向resolved,附带false
                        resolve(false)
                    } else {
                        // 有权限
                        // 推向resolved,附带true
                        resolve(true)
                    }
                }, 1000)
            })
        }

        hasPermission("张三").then(result => {
            if (result) {
                console.log("有权限,发布评论")
            } else {
                console.log("弹出消息:没有权限")
            }
        }, err => {
            console.log("错误:" + err)
        })

 

注意:

1.一旦任务进入已决后,所有企图改变任务状态的代码都将失效

 var pro = new Promise((resolve, reject) => {
            console.log(0)
            resolve(1);
            reject(2);//无效
            resolve(3) //无效
        })

        pro.then(result => {
            console.log(result)
        }, err => {
            console.log(err)
        })

2.以下代码可以让任务达到rejected状态

  • 调用reject
  • 代码执行报错
  • 抛出错误
 1 var pro = new Promise((resolve, reject) => {
 2             console.log(0)
 3             // var obj = null;
 4             // obj.method(); //报错   reject(错误对象)
 5 //手动抛出错误 throw new Error("abc"); //报错  reject(new Error("abc"))
 6             resolve(1);
 7         })
 8 
 9         pro.then(result => {
10             console.log(result)
11         }, err => {
12             console.log(err)
13         })

 

注意:后续处理函数一定是异步函数,并且放在微队列中

 1 例如1:
 2 setTimeout(() => {
 3             console.log(1)
 4         }, 0);
 5         var pro = new Promise((resolve, reject) => {
 6             console.log(2)
 7             resolve(3); //只是简单的把任务推向了resolved,数据为3
 8             reject(4); //无效
 9             console.log(8)
10         })
11         //现在,任务已经是resolved
12         pro.then(result => {
13             console.log(result)
14         }, err => {
15             console.log(err)
16         })
17         console.log(5)
18 
19 
20 //2   5   3   1
21 
22 //再例如2:
23 setTimeout(() => {
24             console.log(1)
25         }, 0);
26         var pro = new Promise((resolve, reject) => {
27             console.log(2)
28             setTimeout(() => {
29                 resolve(3)
30             }, 0);
31             console.log(4)
32         })
33         //现在,任务已经是pending
34         pro.then(result => {
35             console.log(result)
36         }, err => {
37             console.log(err)
38         })
39         console.log(5)
40 
41 //2   4   5   1   3

 

posted @ 2020-02-20 17:28  Jessica赵点点  阅读(170)  评论(0编辑  收藏  举报