10.Promise的基本使用

207 阅读3分钟

Promise:相当于一个容器,保存着未来才会结束的事件(异步操作)的一个结果。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的Promise对象。

特点:

  1. 用来处理异步操作,它有三个状态:Pending(进行)、Resolved(成功)、Rejected(失败),且它的对象状态不受外界的影响。
  2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果。它的状态改变只有两种:一种是Pending到Resolved,另一种是Pending到Rejected。
let pro = new Promise(function (resolved, rejected) {
    //执行异步操作
    let res = {
        code: 201,
        data: {
            name: 'tom',
            age: 18
        },
        error: '请求失败'
    };
    setTimeout(() => {
        if (res.code === 200) {
            resolved(res.data);
        } else {
            rejected(res.error);
        }
    }, 1000);
});
console.log(pro);
//then()用来接收当前异步操作完成之后返回的结果
pro.then((val) => {
    console.log(val);
}, (err) => {
    console.log(err);
})

then()用来接收当前异步操作完成之后返回的结果,第一个参数是Resolved状态的回调函数,第二个参数是可选的,是Rejected状态的回调函数。同时then()返回的还是一个Promise对象的实例,所以可以采用链式编程。
catch(err=>{}).then(null,err=>{})的别名,用于指定发生错误时的回调函数。通常使用.then(捕获成功).catch(捕获失败)

如果我们希望setTimeout()的时间由外界传入,我们需要进行简单封装:

function timeOut(ms) {
    return new Promise((resolved, rejected) => {
        setTimeout(() => {
            resolved('请求成功');
        }, ms);
    });
}

timeOut(2000).then((val) => {
    console.log(val);
});

封装ajax

const getJSON = function (url) {
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open('GET', url);
        xhr.onreadystatechange = handler;
        xhr.responseType = 'json';
        xhr.setRequestHeader('Accept', 'application/json');
        //发送
        xhr.send();

        function handler() {
            //console.log(this);
            if (this.readyState === 4) {//0表示初始化,1表示还没发送,2、3表示当前进行中,4表示完成
                if (this.status === 200) {//200表示成功
                    resolve(this.response.HeWeather6);
                } else {
                    reject(new Error(this.statusText));
                }
            }
        }
    })
};

getJSON('https://free-api.heweather.net/s6/weather/now?location=beijing&key=4693ff5ea653469f8bb0c29638035976').then((data) => {
    console.log(data);
}, (error) => {
    console.log(error);
})

Promise的方法

resolve()

resolve:能将现有的任何对象转换成Promise对象

//let p = Promise.resolve('tom');
/*let p = new Promise(function (resolve) {
    return resolve('tom');
});*/
let p = new Promise(resolve => resolve('tom'));
console.log(p);//Promise {<resolved>: "tom"}
p.then(data => console.log(data))//tom

reject()

resolve()

all()

all:多个异步操作并发运行

let pro1 = new Promise((resolve, reject) => {
});
let pro2 = new Promise((resolve, reject) => {
});
let pro3 = new Promise((resolve, reject) => {
});
let pros = Promise.all([pro1, pro2, pro3]);
pros.then(() => {
    //3个都成功,才成功
}).catch(err => {
    //如果有一个失败,则失败
})

应用: 一些游戏类的素材比较多,等待图片、flash、静态资源文件等都加载完成,才进行页面的初始化。

race()

race:为某个异步请求设置超时时间,并且在超时后执行相应的操作

//1.请求图片资源
function requestImg(imgSrc) {
    return new Promise((resolve, reject) => {
        const image = new Image();
        image.onload = function () {
            resolve(image);
        };
        image.src = imgSrc;
    })
}

//2.超时处理
function timeOut() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject(new Error('图片请求超时'));
        }, 10);
    })
}

Promise.race([requestImg('https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3569105906,107357083&fm=26&gp=0.jpg'), timeOut()]).then((data) => {
    console.log(data);
    document.body.appendChild(data);
}).catch(err => {
    console.log(err);
})

注意: race()里面一定是个数组,如果请求成功就不会走timeOut(),直接就走then()

done()和finally()(了解)

Promise对象的回调链,不管以then方法或catch方法结尾,要是最后一个方法抛出错误,都有可能无法捕捉到(因为Promise内部的错误不会冒泡到全局)。因此,我们可以提供一个done或finally方法,总是处于回调链的尾端,保证抛出任何可能出现的错误。

作用: 这为在Promise是否成功完成后都需要执行的代码提供了一种方式,避免了同样的语句需要在then()catch()中各写一次的情况。