promise概念

ES6 原生提供了 Promise 对象。

所谓 Promise,就是一个对象,用来传递异步操作的消息。它相当于一个容器,存放了了某个未来才会知道结果的事件(通常是一个异步操作),并且这个事件提供统一的 API(resolve 和 reject),用来返回成功或者失败的结果,可供then等方法对成功或失败进行对应的操作

Promise对象的两个特点:

对象的状态不受外界影响,处理异步操作有三个状态, Pending(进行) Resolved(已完成) Rejected(已失败)

只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是 Promise 这个名字的由来,它的英语意思就是「承诺」,表示其他手段无法改变

一旦状态改变,就不会再被修改,任何时候都只会得到这个结果

Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果

有了 Promise 对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise 对象提供统一的接口,使得控制异步操作更加容易

Promise对象的缺点:

  • 无法取消 Promise,一旦新建它就会立即执行,无法中途取消
  • 如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部
  • 当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
  • Promise 构造函数接收一个回调函数作为参数,该函数的两个参数分别是 resolve函数和 reject函数

    这个回调函数接收两个参数,分别为promise的 resolve(成功) rejecte(失败) 两个函数

    then() 方法来接收通过if判断返回的结果,第一个参数是resolve回调函数,第二个是可选的,是rejecte状态回调函数, then() 返回一个新的promise实例,可以采用链式编程

    var promise = new Promise(function (resolve, reject) {//声明promise对象,并立即执行
        if ('异步操作成功') {
            resolve(value);
    } else {
          	reject(error);
    console.log(promise); //Promise {<pending>} 无需then方法调用,就返回了一个正在进行状态的Promise对象
    promise.then(function (value) {
        // success
    }, function (value) {
        // failure
    

    如果异步操作成功,则用 resolve 方法将 Promise 对象的状态,从「未完成」变为「成功」(即从 pending 变为 resolved)

    如果异步操作失败,则用 reject 方法将 Promise 对象的状态,从「未完成」变为「失败」(即从 pending 变为 rejected)

    理解promise执行顺序

    let promise = new Promise(function (resolve, rejecte) { //1.声明promise对象,并立即执行
        let res = { //声明res对象,模拟从后端返回的数据
            code: 200,
            data: {
                name: 'Max',
                age: 23
            error: '失败了'
        setTimeout(() => { //用setTimeout模拟后端返回数据的时间
            if (res.code === 200) { //2.条件判断code值是否符合条件
                resolve(res.data); //3-①符合条件,执行resolve函数中的-获得data并返回给then方法的第一个函数
            } else {
                rejecte(res.error);//3-②不符合条件,执行rejecte函数中的-获得误信息并返回给then的第二个函数
        }, 1000);
    //4.调用promise的then方法接收回调
    promise.then((val) => { //5-①then方法通过Val接收resolve传入的值
        console.log(val);//6-①在函数内进行处理,本处打印(res.data)
    }, (err) => {  //5-②then方法通过err接收rejecte传入的值
        console.log(err);//6-②在函数内进行处理,本处打印(res.error)
    

    封装Promise

    为避免Promise一旦被声明立即执行的特性,以及解决不能传参的问题,就需要对Promise进行函数封装,通过这个函数对Promise进行链式调用并传参,只有调用这个函数的时候,才返回一个Promise实例化对象,并开始执行,调用函数的同时,使用then方法来接收Promise返回的结果

    function timeOut(ms) {//2.接收传入的参数
        return new Promise((resolve, rejecte) => {//3.开始执行Promise函数
            setTimeout(() => {
                resolve('Promise Success!!')//4.通过rosolve函数返回给then一个结果
            }, ms);
    //1.函数调用,传入参数,并返回一个Promise实例化对象
    timeOut(1000).then((val) => {//5.then方法通过val接收传入的结果,并执行内部函数
        console.log(val);//6.打印传入的val的值
    

    使用Promise封装ajax

    const getJSON = function (url) {
        return new Promise((resolve, reject) => {
            const xhr = new XMLHttpRequest();//创建一个 `XMLHttpRequest` 对象
            xhr.open('GET', url);//打开xhr,GET方法打开传入的url
            xhr.onreadystatechange = handler;//调用当前状态发生改变的回调函数
            xhr.responseType = 'json';//约定返回数据的类型
            xhr.setRequestHeader('Accept', 'application/json');//设置请求头
            xhr.send();//发送
            function handler() { //创建对当前状态判断的回调函数
                if (this.readyState === 4) {
                    if (this.status === 201) {
                        resolve(this.response.HeWeather6[0].now);
                    } else {
                        reject(new Error(this.statusText))
    getJSON('https://free-api.heweather.net/s6/weather/now?location=beijing&key=4693ff5ea653469f8bb0c29638035976')
        .then(data => {
        console.log(data);
    }).catch(err => {
        console.log(err);
    

    Promise对象的其他方法

    resolve() rejecte() all() race() done() finally()

    resolve() 能将现有对象直接转换为一个Promise对象

    转换完成之后这个对象就有resolve()独有的状态,就可以通过 then() catch() 去获取

    let p = new Promise(resolve => {//下方等价于这个
        return resolve('foo')
    //-------------------------------------------------
    let p = Promise.resolve('foo');
    console.log(p)//Promise {<resolved>: "foo"}
    p.then(data => {
        console.log(data);//foo
    

    rejecte()能将先有对象转换为一个Promise对象

    同resolve()

    all() 提供了异步并行的操作行为,多个Promise同时进行,只有全部Promise都返回resolve才算成功

    让then一次接收Promise返回结果的方法,让所有异步操作都执行完成,没有错误之后再调用对应的方法

    let promise1 = new Promise((resolve,rejecte)=>{});
    let promise2 = new Promise((resolve,rejecte)=>{});
    let promise3 = new Promise((resolve,rejecte)=>{});
    let proAll = Promise.all([promise1,promise2,promise3]);//注意所有Promise对象要放大数组内
    proAll.then(()=>{
        //三个都成功才算成功,再执行此处方法
    }).catch(err=>{
        //其中一个失败则失败,执行失败的方法
    

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

    race() 同样是将多个Promise对象,包装成一个新的Promise对象,其中一个完成就立即改变状态,并通过then等方法接收返回结果

    第一个结束的Promise的返回结果,可以是resolve或rejecte,来传递给then或catch进行下一步的操作 应用:请求一个图片资源,超过3秒停止加载,并返回timeout的rejecte结果,3秒之内返回图片就进入then方法,超过3秒请求失败,就会进入catch方法

    function requestImg(imgSrc) {
        return new Promise((resolve, rejecte) => {
            const img = new Image();
            img.onload = function () {
                resolve(img);
            img.src = imgSrc;
    function timeout() {
        return new Promise((resolve, rejecte) => {
            setTimeout(() => {
                rejecte(new Error('图片请求超时'));
            }, 3000);
    let requestTimeout = Promise.race([requestImg('http://pic.netbian.com/downpic.php?id=18363&classid=66'), timeout()]);
    requestTimeout.then(data => {
      document.body.appendChild(data);
    }).catch(err => {
        console.log(err);
    

    需要注意的是这里 请求图片超时 的两个方法都需要放到数组中

    done() 用于接收错误

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

    finally() 在任何情况下都会执行,用于完成Promise状态返回后无论成功失败都必须执行的操作

    finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。它与done方法的最大区别,它接受一个普通的回调函数作为参数,该函数不管怎样都必须执行

    Maxuan
    粉丝