Promise自我总结

一、Promise介绍

  Promise是异步编程的一种解决方案,比传统的解决方案(回调函数和事件)更合理和强大。Promise有以下两个特点:

  • 对象的状态不受外界影响。
  • 一旦状态改变,就不会再变,任何时候都可以得到这个结果。事件的特点是,如果错过了它,再去监听,是得不到结果的。

  Promise缺点:

  • 无法取消Promise,一旦新建就会立即执行,无法中途取消;
  • 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部;
  • 当处于pending状态时,无法得知目前进展到哪一个阶段。
  1. Promise.prototype.finally()
    finally方法用于指定不管Promise对象最后状态如何,都会执行的操作。
Promise
.then(result => {...})
.catch(error => {...})
.finally(() => {...});

finally方法的回调函数不接受任何参数,不依赖与Promise的执行结果。例如,可以公仔服务器使用Promise处理请求,然后使用finally方法关掉服务器。

  1. Promise.all()
    该方法用于多个Promise实例,包装成一个新的Promise实例。
const p = Primise([p1, p2, p3]);

Promise.all接收一个数组作为参数,p1 p2 p3都是Promise实例,如果不是,就会先调用Promise.resolve方法,将参数转为Promise实例,再进一步处理。
p的状态由p1 p2 p3决定:
(1)只有p1 p2 p3的状态都是fulfilled,p的状态才会变成fulfilled,此时p1 p2 p3的返回值组成一个数组,传递给p的回调函数;
(2)只要p1 p2 p3中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

  1. Promise.race()
    该方法也是将多个Promise实例包装成一个新的Promise实例。
const p = Promise.race([p1, p2, p3]);

Promise.race与Promise.all一样,接收一个数组作为参数,p1 p2 p3都是Promise实例,如果不是,就会先调用Promise.resolve方法,将参数转为Promise实例再做进一步处理。
p的状态有pa p2 p3中第一个改变的状态决定,只要其中一个实例率先改变状态,p的状态就跟着改变。那个率先改变的Promise实例的返回值,就传递给p的回调函数。
下面是一个经典例子:

// 如果指定时间内没有获得结果,就将Promise的状态reject掉
const p = Promise.race([
  fetch('/resource-that-may-take-a-while'),
  new Promise(function (resolve, reject) {
    setTimeout(() => reject(new Error('request timeout')), 5000)
  })
]);

p
.then(console.log)
.catch(console.error);

  1. Promise.resolve()与Promise.reject()
    将对象转为Promise对象

  2. 注意一些只能同步执行的函数,比如foreach等

二、ES5实现Promise

  1. 构造函数
function Promise(executor){
    var self = this;
    self.status = 'pending';
    self.data = undefined;
    // resolve或者reject之后的回调函数集,因为在Promise结束之前可能有多个回调函数;
    self.onResolvedCallback = [];
    self.onRejectedCallback = [];
    // 执行器
    executor(resolve, reject);
}
  1. executor函数有两个参数:resolve与reject,这两个函数需要定义
function Promise(executor){
    var self = this;
    self.status = 'pending';
    self.data = undefined;
    // resolve或者reject之后的回调函数集,因为在Promise结束之前可能有多个回调函数;
    self.onResolvedCallback = [];
    self.onRejectedCallback = [];
    function resolve(value){
        // TODO
    }
    function reject(reason){
        // TODO
    }
    // 执行executor可能会出错,用try...catch将错误信息reject出去
    try{
        executor(resolve, reject);
    } catch(e){
        reject(e);
    }
}

由于resolve与reject两个函数在调用的时候,有其自己的this,但是resolve和reject执行的时候,this应该指向Promise内部。如果把resolve与reject定义在Promise 的外部,在使用的时候,需要调用bind函数将this指向Promise内部,但是bind函数会返回一个新的函数,还是相当于每个Promise对象都有属于自己的resolve与reject函数,与定义在函数内部没有区别。
3. resolve函数与reject函数

function Promise(executor){
    var self = this;
    ...
    function resolve(value){
        if(self.status === 'pending'){
            self.status = 'resolved';
            self.data = value;
            for(var i = 0; i < self.onResolvedCallback.length; i++){
                self.onResolvedCallback[i](value);
            }
        }
    }
    function reject(reason){
        if(self.status === 'pengding'){
            self.status = 'rejected';
            self.data = reason;
            for(var i = 0; i > self.onResolvedCallback.length; i++){
                self.onRejectedCallback[i](reason);
            }
        }
    }
}
  1. then方法
    then方法用来注册在这个Promise状态确定后的回调,then方法会返回一个Promise,才可以进行链式调用。
// then函数接收两个参数:onResolved, onRejected,分别代表成功或者失败后的回调
Promise.prototype.then = function(onResolved, onRejected){
    // 根据标准,then的参数如果不是function,需要忽略它
    var onResolved = typeof onResolved === 'function' ? onResolved : function(value){};
    var onRejected = typeof onRejected === 'function' ? onRejected : function(reason){};
    var self = this;
    var promise2;
    
    if(self.status === 'resovled'){
        // 若promise1的状态已经确定并且是resolved,直接调用onResolved,但是有可能throw,所以包裹在try...catch中
        return promise2 = new Promise(function(resolve, reject){
            try{
                var x = onResolved(self.data);
                // 若onResolved返回的是一个Promise,则直接将它的结果返回
                if(x instanceof Promise){
                    x.then(self.data);
                }
                // 否则直接将它的返回值作为promise2的结果
                resolve(x);
            } catch(e){
                reject(e);
            }
        })
    }
    if(self.status === 'reject'){
        return promise2 = new Promise(function(resolve, reject){
            try{
                var x = onRejected(self.data);
                if(x instanceof Promise){
                    x.then(resolve, reject);
                }
            } catch(e){
                reject(e);
            }
        })
    }
    if(slef.status === 'pending'){
    // 如果当前的Promise还处于pending状态,我们并不能确定调用onResolved还是onRejected,
    // 只能等到Promise的状态确定后,才能确实如何处理。
    // 所以我们需要把我们的**两种情况**的处理逻辑做为callback放入promise1(此处即this/self)的回调数组里
    // 逻辑本身跟第一个if块内的几乎一致,此处不做过多解释
        return promise2 = new Promise(function(resolve, reject) {
            self.onResolvedCallback.push(function(value) {
                try {
                     var x = onResolved(self.data)
                    if (x instanceof Promise) {
                        x.then(resolve, reject)
                    }
                } catch (e) {
                  reject(e)
                }
             })
    
            self.onRejectedCallback.push(function(reason) {
                try {
                    var x = onRejected(self.data)
                    if (x instanceof Promise) {
                        x.then(resolve, reject)
                    }
                } catch (e) {
                    reject(e)
                }
            });
        })
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值