Promise使用与理解

83 阅读4分钟

1.Promise简介

参考:blog.csdn.net/weixin_4497…

1.1 Promise是什么

  • 抽象表达:Promise是JS中进行异步编程的新的解决方案(旧方案是单纯使用回调函数)
  • 具体表达: ①从语法上看:Promise是一个构造函数 (自己身上有all、reject、resolve这几个方法,原型上有then、catch等方法) ②从功能上看:promise对象用来封装一个异步操作并可以获取其成功/失败的结果值
  • 阮一峰的解释: 所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果 从语法上说,Promise 是一个对象,从它可以获取异步操作的消息 Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理

Promise 的状态: 实例对象promise中的一个属性 PromiseState pending 变为 resolved/fullfilled pending 变为 rejected 注意: 对象的状态不受外界影响 只有这两种,且一个 promise 对象只能改变一次 一旦状态改变,就不会再变,任何时候都可以得到这个结果 无论成功还是失败,都会有一个结果数据。成功的结果数据一般称为 value,而失败的一般称为 reason。

1.2 Promise基本使用

流程: 在这里插入图片描述

基本使用:

const promise = new Promise(function(resolve, reject) {
  // ... some code
  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(reason);
  }
});

1.3 为什么使用Promise

  • 指定回调函数的方式更加灵活 旧的:必须在启动异步任务前指定

  • 支持链式调用,可以解决回调地狱问题 回到地狱:回调函数嵌套调用,外部回调函数异步执行的结果是其内部嵌套的回调函数执行的条件 回调函数缺点:不便于阅读、不便于异常处理 解决回调地狱的方案:

  • Promise链式调用

  • async/await

1.4 中断Promise链

我们都知道promise状态一旦变为resolve或reject就不会再改变,中间无法中断,那如何中断链式调用呢? 当使用 promise 的 then 链式调用时,在中间中断,不再调用后面的回调函数 办法:在回调函数中返回一个 pending 状态的 promise 对象

new Promise((resolve, reject) => {
   //resolve(1)
   reject(1)
}).then(
  value => {
    console.log('onResolved1()', value)
    return 2
  }
).then(
  value => {
    console.log('onResolved2()', value)
    return 3
  }
).then(
  value => {
    console.log('onResolved3()', value)
  }
).catch(
  reason => {
    console.log('onRejected1()', reason)
  }
).then(
  value => {
    console.log('onResolved4()', value)
  },
  reason => {
    console.log('onRejected2()', reason)
  }
)
// onRejected1() 1
// onResolved4() undefined

为了在 catch 中就中断执行,可以这样写:

new Promise((resolve, reject) => {
   //resolve(1)
   reject(1)
}).then(
  value => {
    console.log('onResolved1()', value)
    return 2
  }
).then(
  value => {
    console.log('onResolved2()', value)
    return 3
  }
).then(
  value => {
    console.log('onResolved3()', value)
  }
).catch(
  reason => {
    console.log('onRejected1()', reason)
    return new Promise(() => {}) // 返回一个pending的promise
  }
).then(
  value => {
    console.log('onResolved4()', value)
  },
  reason => {
    console.log('onRejected2()', reason)
  }
)
// onRejected1() 1

在 catch 中返回一个新的 promise,且这个 promise 没有结果。 由于,返回的新的 promise 结果决定了后面 then 中的结果,所以后面的 then 中也没有结果。 这就实现了中断 promise链的效果。

2.Promise顺序请求

方法1——连续使用then链式调用 方法2——使用promise构建队列 方法3——使用async、await实现类似同步编程,async函数内部实现同步 参考:www.jianshu.com/p/dbda3053d…

方法1:链式调用

function getA(){
    return  new Promise(function(resolve, reject){ 
    setTimeout(function(){     
          resolve(2);
      }, 1000);
  });
}
 
function getB(){
    return  new Promise(function(resolve, reject){       
        setTimeout(function(){
            resolve(3);
        }, 1000);
    });
}
 
function addAB(a,b){
    return a+b
}

function getResult(){
    var  obj={};
    Promise.resolve().then(function(){
        return  getA() 
    })
    .then(function(a){
         obj.a=a;
    })
    .then(function(){
        return getB() 
    })
    .then(function(b){
         obj.b=b;
         return obj;
    })
    .then(function(obj){
       return  addAB(obj['a'],obj['b'])
    })
    .then(data=>{
        console.log(data)
    })
    .catch(e => console.log(e));
}
getResult();

3.Promise并行请求

getA和getB并行执行,然后输出结果。如果有一个错误,就抛出错误 每一个promise都必须返回resolve结果才正确 每一个promise都不处理错误 参考:www.jianshu.com/p/dbda3053d…

/**
 * 每一个promise都必须返回resolve结果才正确
 * 每一个promise都不处理错误
 */

const getA = new Promise((resolve, reject) => {
   //模拟异步任务
   setTimeout(function(){
     resolve(2);
   }, 1000) 
})
.then(result => result)


const getB = new Promise((resolve, reject) => {
   setTimeout(function(){
     // resolve(3);
     reject('Error in getB');
   }, 1000) 
})
.then(result => result)


Promise.all([getA, getB]).then(data=>{
    console.log(data)
})
.catch(e => console.log(e));

getA和getB并行执行,然后输出结果。总是返回resolve结果 每一个promise自己处理错误

/**
 * 每一个promise自己处理错误
 */

const getA = new Promise((resolve, reject) => {
   //模拟异步任务
   setTimeout(function(){
     resolve(2);
   }, 1000) 
})
.then(result => result)
.catch(e=>{

})


const getB = new Promise((resolve, reject) => {
   setTimeout(function(){
     // resolve(3);
     reject('Error in getB');
   }, 1000) 
})
.then(result => result)
.catch(e=>e)


Promise.all([getA, getB]).then(data=>{
    console.log(data)
})
.catch(e => console.log(e));

Promise.all传入同一个方法不同参数的封装 应用场景 比如你需要同时发起多页请求,需要传入页码但是方法都是一样的此时我们就可以进行封装一下,很实用的一个技巧 参考:blog.csdn.net/qq_25842063…

/*
* @params : func:你封装的方法 params: 参数的数组
*/
let getDataBind = (func, params) => {
        return params.map( item => {
            return func.call(null, item) //传参
        })
    }
 /*
 @params : page_no 页码  
 getData 可以换成你自己需要重复操作的方法,同理
 */
let getData = (page_no) => {
        let saveListData = JSON.parse(localStorage.getItem(this.props.saveListData));
        let params = {
            page_no:page_no,
            ...saveListData.loadParams
        }
        return new Promise(resolve => {
            get(this.props.sortUrl, params, this, false).then(function (data) {
                resolve(data.result;);
            });
        })
    }  
 Promise.all(this.getDataBind(this.getData, arrPage))
	.then( resultArr  => {
		    resultArr = resultArr.flat();//拉平数组
		    console.log(resultArr)    //这里就获取到所有页的数据了
	});
//