Promise用法小结

78 阅读4分钟

一、什么是Promise

Promise是解决异步编程的一种解决方案,是一个构造函数,有all、race、reject、resolve这几个方法,原型上有then、catch等方法。

原型:每一个javascript对象(除null外)创建的时候,都会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型中“继承”属性。)

image.png

Promise对象有以下特点:

  1. 对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)
  2. 一旦状态改变,就不会再变
    var p = new Promise(function(resolve, reject){
    //做一些异步操作
    setTimeout(function(){
        console.log('执行完成');
        resolve('随便什么数据');
    }, 2000);
});
  • Promise的构造函数接收一个参数,是函数,并且传入两个参数:resolve,reject,分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数。

成功和失败不准确,实际resolve是将Promise的状态置为fullfiled,reject是将Promise的状态置为rejected。

  • 运行后,2秒后会输出“执行完成”,注意只new了一个对象,没有调用就已经执行了,所以用Promise的时候一般包在一个函数中,并在最后return出Promise对象,需要时再去调用。

先是方法被调用执行了promise,最后执行了promise的then方法,then方法是一个函数接受一个参数是接受调用resolve传的参数。

  • 从表面上看,Promise只是能够简化层层回调的写法,而实质上,Promise的精髓是“状态”,用维护状态、传递状态的方式来使得回调函数能够及时调用,它比传递callback函数要简单、灵活的多。

Promise的优势在于,可以在then方法中继续写Promise对象并返回,然后继续调用then来进行回调操作

二、reject的用法

reject就是失败的时候的回调,他把promise的状态修改为rejected,这样我们在then中就能捕捉到,然后执行“失败”情况的回调

function getNumber(){
    var p = new Promise(function(resolve, reject){
        //做一些异步操作
        setTimeout(function(){
            var num = Math.ceil(Math.random()*10); //生成1-10的随机数
            if(num<=5){
                resolve(num);
            }
            else{
                reject('数字太大了');
            }
        }, 2000);
    });
    return p;            
}

getNumber()
.then(
    function(data){
        console.log('resolved');
        console.log(data);
    }, 
    function(reason, data){
        console.log('rejected');
        console.log(reason);
    }
);

运行getNumber并且在then中传了两个参数,then方法可以接受两个参数,第一个对应resolve的回调,第二个对应reject的回调。所以我们能够分别拿到他们传过来的数据。

三、catch的用法

和then的第二个参数一样,用来指定reject的回调,但还有另外的作用:在执行resolve的回调时,如果抛出异常了(代码出错了),那么并不会报错卡死js,而是会进到这个catch方法中。

getNumber()
.then(function(data){
    console.log('resolved');
    console.log(data);
    console.log(somedata); //此处的somedata未定义
})
.catch(function(reason){
    console.log('rejected');
    console.log(reason);
});

运行结果

image.png

四、all的用法

all接收一个数组参数,里面的值最终都算返回Promise对象。这样,三个异步操作并行执行,等到它们都执行完后才会进到then里面。有了all,你就可以并行执行多个异步操作,并且在一个回调中处理所有的返回数据,适合打开网页较多静态文件,所有的加载完后,再进行页面初始化。

Promise
.all([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
    console.log(results);
});

输出结果:

image.png

五、race的用法

谁跑得快,以谁为准执行回调。

Promise
.race([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
    console.log(results);
});

输出结果:

image.png

这三个异步操作同样是并行执行的。1秒后runAsync1已经执行完了,此时then里面的就执行了,在then里面的回调开始执行时,runAsync2()和runAsync3()并没有停止,仍旧再执行。于是再过1秒后,输出了他们结束的标志。

  • race使用场景 给某个异步请求设置超时时间,并且在超时后执行相应的操作。
//请求某个图片资源
function requestImg(){
    var p = new Promise(function(resolve, reject){
        var img = new Image();
        img.onload = function(){
            resolve(img);
        }
        img.src = 'xxxxxx';
    });
    return p;
}

//延时函数,用于给请求计时
function timeout(){
    var p = new Promise(function(resolve, reject){
        setTimeout(function(){
            reject('图片请求超时');
        }, 5000);
    });
    return p;
}

Promise
.race([requestImg(), timeout()])
.then(function(results){
    console.log(results);
})
.catch(function(reason){
    console.log(reason);
});