• Promise初步详解(resolve,reject,catch


    Promise其实是一个构造函数,它有resolve,reject,race等静态方法;它的原型(prototype)上有then,catch方法,因此只要作为Promise的实例,都可以共享并调用Promise.prototype上面的方法(then,catch),接下来我们试着使用一下Promise。

    二,Promise的使用

    首先我们来看一下Promise的使用语法:

    new Promise(function(resolve,reject){}/*excutor*/);
    
    • 1

    在实例化Promise时需要传入一个函数excutor作为参数,并且在Promise构造函数执行时同步执行。废话不多说,先看一个简单的实例:

    var p = new Promise(function(resolve,reject){
                 var timer = setTimeout(function(){
                     console.log('执行操作1');
                 },1000);
             });
    
    • 1
    • 2
    • 3
    • 4
    • 5

    我们可以看到1s后在控制台输出相应的结果,这就说明在实例化过程中,作为参数的excutor函数也会执行。

    从上面的实例中我们看到,excutor函数还有两个参数resolve和reject,其实这两个参数也是函数,在excutor执行时被调用,下面我们具体来谈谈resolve和reject的用法

    三,resolve和reject的具体用法

    先来说说resolve的用法

    首先我们来看看Promise的几种状态:

    pending: 初始状态,成功或失败状态。
    fulfilled: 意味着操作成功完成。
    rejected: 意味着操作失败。
    当我们在excutor函数中调用resolve方法时,Promise的状态就变成fulfilled,即操作成功状态,还记得上面Promise.prototype上面的then和catch方法吗?当Promise状态为fullfilled状态时执行then方法里的操作,注意了,then方法里面有两个参数onfulfilled(Promise为fulfilled状态时执行) 和onrejected(Promise为rejected状态时执行),步骤如下:

    1,实例化Promise(new Promise(function(resolve,reject)))

    2,用Promise的实例调用then方法

    具体来看下面的例子:

    var p = new Promise(function (resolve, reject) {
                var timer = setTimeout(function () {
                    console.log('执行操作1');
                    resolve('这是数据1');
                }, 1000);
            });
            p.then(function (data) {
                console.log(data);
                console.log('这是成功操作');
            });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    reject的用法

        看了上面的实例,我相信应该也很容易理解reject方法了,就是调用reject方法后,Promise状态变为rejected,即操作失败状态,此时执行then方法里面onrejected操作,上面我们提到了then方法有两个参数,一种是Promise状态为fulfilled时执行(onfullfilled),一种是Promise状态为rejected时执行(onrejected),其实就是类似于jquery里的hover方法里面的两个参数一样,来看看下面的例子:
    
    • 1
    var p = new Promise(function (resolve, reject) {
              var flag = false;
              if(flag){
                resolve('这是数据2');
              }else{
                reject('这是数据2');
              }
            });
            p.then(function(data){//状态为fulfilled时执行
                console.log(data);
                console.log('这是成功操作');
            },function(reason){ //状态为rejected时执行
                console.log(reason);
                console.log('这是失败的操作');
            });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    catch方法

       我们注意到除了then方法外,Promise原型上还有另外一个叫catch的方法,那么这个方法的作用是什么呢?其实跟then方法中的第二个参数一样,就是在Promise状态为rejected时执行,then方法捕捉到Promise的状态为rejected,就执行catch方法里面的操作,下面用catch方法改写上面reject用法里面的例子,如下所示:
    
    • 1
    var p = new Promise(function (resolve, reject) {
                var flag = false;
                if(flag){
                  resolve('这是数据2');
                }else{
                  reject('这是数据2');
                }
              });
              p.then(function(data){
                  console.log(data);
                  console.log('这是成功操作');
              }).catch(function(reason){
                  console.log(reason);
                  console.log('这是失败的操作');
              });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    四,为何用Promise

    首先我们来看这样一个例子,取4个定时器,设置延迟时间都为1s,然后每隔1s依次在控制台输出‘我’‘爱’‘米’‘饭’的字样。代码如:

    setTimeout(function () {
              console.log('我');
              setTimeout(function () {
                  console.log('爱');
                  setTimeout(function () {
                      console.log('米');
                      setTimeout(function () {
                          console.log('饭');
                      }, 1000);
                  }, 1000);
              }, 1000);
          }, 1000);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    发现什么问题没有?是不是有点感觉回调函数的嵌套有点多,如果有更多的回调函数呢?是不是使代码的可读性和可维护性都大大降低了呢(回调地狱?),这时如果我们使用Promise去实现这个效果,虽然可能代码不会减少,甚至更多,但是却大大增强了其可读性和可维护性。具体看下面例子:

    function getStr1() {
        return new Promise(function (resolve, reject) {
            setTimeout(function () {
                resolve('我');
            }, 1000);
        });
    }
    function getStr2() {
        return new Promise(function (resolve, reject) {
            setTimeout(function () {
                resolve('爱');
            }, 1000);
        });
    }
    function getStr3() {
        return new Promise(function (resolve, reject) {
            setTimeout(function () {
                resolve('米');
            }, 1000);
        });
    }
    function getStr4() {
        return new Promise(function (resolve, reject) {
            setTimeout(function () {
                resolve('饭');
            }, 1000);
        });
    }
    getStr1().then(function (data) {
        console.log(data);
        return getStr2();
    }).then(function (data) {
        console.log(data);
        return getStr3();
    }).then(function (data) {
        console.log(data);
        return getStr4();
    }).then(function (data) {
        console.log(data);
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    执行效果跟上面一样,在这个例子中,将得到Promise实例的过程封装成一个函数(getStr1,getStr2,getStr3,getStr4)并返回一个Promise实例,再用实例去调用相应的then方法,在每个then方法中通过return得到下一级的Promise实例,比如在第一个Promise实例(getStr1())then方法中,通过return返回下一个Promise对象(getStr2()),然后再去调用then方法执行里面的操作,再返回下一个Promise对象(这里是getStr3())

    小例子:

    **function checkFunc() {
    let p = new Promise(function (resolve, reject) {
        // 一些比较耗时异步操作
        if(操作完成标识) {
            resolve();
        }
    });
    p.then(function (data) {
        layer.confirm('执行下一步操作?', {
            btn: ['确定', '取消']
        }, function () {
           // 确保上面的操作都完成后,才执行下面的操作
           // 其他操作...
        });
    });
    }**
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    以上promise的基础介绍参考:promise的使用

    接下来介绍下:手写promise

    // 测试案例
    new Promise((resolve, reject) => {
       setTimeout(() => resolve(new Promise(res => res(333))), 2000)
    }).then(res => {
        console.log(res)
        return 222
    }).then().then(res => {
        console.log(res);
        return new Promise(res => {
            setTimeout(() => { res(666) }, 1000)
        }).then(res => {
            console.log(res);
            return 999
        })
    }).then(res => {
        console.log(res);
    })
    /*
     * 打印:
     * 333
     * 222
     * 666
     * 999
    */
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    // 上源码
    ;(function (global) {
    	global.Promise = Promise
    	// 定义promise三种状态
    	const PENDING = 'pending'
    	const FULFILLED = 'fulfilled'
    	const REJECTED = 'rejected'
    
    	function Promise(fn) {
    		this.state = PENDING
    		this.fulfilledQueue = []
    		this.rejectedQueue = []
    		try {
    			fn(
    				// 此处需注意this指向
    				(res) => {
    					this._resolve(res)
    				},
    				(err) => {
    					this._reject(err)
    				}
    				// 或者this.resolve.bind(this), this.reject.bind(this))
    			)
    		} catch (e) {
    			reject(e)
    		}
    	}
    
    	Promise.prototype = {
    		constructor: Promise,
    		_resolve: function (value) {
    			if (value instanceof Promise) {
    				return value.then(
    					// 此处需注意this指向
    					(res) => {
    						this._resolve(res)
    					},
    					(err) => {
    						this._reject(err)
    					}
    				)
    			}
    			setTimeout(() => {
    				if (this.state === PENDING) {
    					this.state = FULFILLED
    					this.value = value
    					this.fulfilledQueue.forEach((fn) => fn(this.value))
    				}
    			})
    		},
    		_reject: function (value) {
    			setTimeout(() => {
    				if (this.state === PENDING) {
    					this.state = REJECTED
    					this.value = value
    					this.rejectedQueue.forEach((fn) => fn(this.value))
    				}
    			})
    		},
    		then: function (fulfilled, rejected) {
    			this.fulfilled =
    				typeof fulfilled === 'function' ? fulfilled : (v) => v
    			this.rejected =
    				typeof rejected === 'function'
    					? rejected
    					: (err) => {
    							throw err
    					  }
    			if (this.state === PENDING) {
    				return new Promise((resolve, reject) => {
    					this.fulfilledQueue.push(() => {
    						try {
    							this.value = this.fulfilled(this.value)
    							resolve(this.value)
    						} catch (error) {
    							reject(error)
    						}
    					})
    					this.rejectedQueue.push(() => {
    						try {
    							this.value = this.rejected(this.value)
    							resolve(this.value)
    						} catch (error) {
    							reject(error)
    						}
    					})
    				})
    			}
    			if (this.state === FULFILLED) {
    				return new Promise((resolve, reject) => {
    					setTimeout(() => {
    						try {
    							this.value = this.fulfilled(this.value)
    							resolve(this.value)
    						} catch (error) {
    							reject(error)
    						}
    					})
    				})
    			}
    			if (this.state === REJECTED) {
    				return new Promise((resolve, reject) => {
    					setTimeout(() => {
    						try {
    							this.value = this.rejected(this.value)
    							resolve(this.value)
    						} catch (error) {
    							reject(error)
    						}
    					})
    				})
    			}
    		},
    	}
    })(window)
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
  • 相关阅读:
    【JAVA】SpringMVC(下)—— SSM整合&异常处理器
    HSRP协议
    多线程&并发篇---第十六篇
    GB28181协议-SDP详解
    Baize_ServoDriver_esp32(ROS+Arduino驱动舵机机械臂,通过串口或WiFi话题通信)(数字孪生:虚拟和现实同步)
    【rust/egui】(八)使用panels给你的应用划分功能区块
    了解一下 Fossil,一个 Git 的替代品 | Linux 中国
    艾思AI-admin框架开发指导意见与规范1.0
    虚拟机安装CentOS7教程
    [Linux](16)网络编程:网络概述,网络基本原理,套接字,UDP,TCP,并发服务器编程,守护(精灵)进程
  • 原文地址:https://blog.csdn.net/weixin_44834981/article/details/125616339