Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Promise的理解及react中的运用 #1

Open
liqunbin opened this issue May 6, 2018 · 0 comments
Open

Promise的理解及react中的运用 #1

liqunbin opened this issue May 6, 2018 · 0 comments

Comments

@liqunbin
Copy link
Owner

liqunbin commented May 6, 2018

前言

前几天同事无意间问我对promise的理解,作为一年前端开发的我,虽然项目里一直有在用,但细细回想promise是什么、怎么用的和我对这个的理解,还真不说不出来,所以我周末就好好花了时间对promise进行了浅层的了解,如果有说错的欢迎指点。

一、promise是什么?为什么会有promise?

首先,promise是js的抽象异步处理对象实现异步编程的方案,简单的说就是解决传统js运行单线程的诟病以及异步操作的多层级嵌套带来的麻烦。

Q:资料说promise是个容器,我对这个理解不是很清晰。

我的理解是说,这个容器指promise的异步操作内容,然后我们这个操作放在这个容器里面让他自己执行,不会受外界影响。

然后,promise有三种状态,分别是:pending、fulfilled、rejected;
当 promise执行resolve是状态由pending->fulfilled;
当 promise执行reject是状态由pending->rejected;
状态一旦改变就不会再变。

avatar

二、基本用法

1、实例

  const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

Promise对象是一个构造函数,实例后的Promise是一个对象,该构造函数接受一个函数参数,这个函数参数传入两个参数(resolve,reject), 这两个参数是各是一个函数方法;
我们可以根据函数的结果来判断执行resolve或reject;

2、.then()

  promise.then(()=>{
   /* resolve 的执行内容 */
    },()=>{
    /*reject执行的内容*/
    }
  )

.then()方法接受两个函数参数,第一个参数是获取resolve的内容来执行异步操作,第二个参数是执行reject,然后执行一个捕获错误的内容,貌似可以获取代码执行错误的位置;
(我的理解:有then方法的promise才是完整的。)

2.1、第一个函数接受一个来自promise的构造函数resolve传递的对象;
3.2、第二个函数会不会promise构造函数的错误;

注意:建议是不推荐 .then(()=>{},()=>{/捕获错误/}) 这样去捕获错误,而是推荐用.catch的方法去捕获错误 .then(()=>{/resolve 内容/}).catch(error){/error捕获错误/}。因为直接在后面点catch()就能够捕获第一次发生错误的地方。

运用promise做多层次的回调
终取到这个节点,但是如果用promise就能够同步异步操作去获取到;

  console.log('start');
  var promise1 = new Promise((resolve,reject)=>{
              setTimeout(resolve('葡萄'),1);
          });
  promise1.then(value=>new Promise((resolve,reject)=>setTimeout(resolve(value+',苹果'),1)))
          .then(value=>new Promise((resolve,reject)=>setTimeout(resolve(value+',橘子'),1)))
          .then(value=>new Promise((resolve,reject)=>setTimeout(resolve(value+',香蕉'),1)))
          .then(value=>new Promise((resolve,reject)=>setTimeout(resolve(value+',西瓜'),1)))
          .then(value=>{console.log(value)});

  console.log('上面是个异步过程,所以我先出来,后面才是水果');
  
  /*
    控制台打印:
    start
    上面是个异步过程,所以我先出来,后面才是水果
    葡萄,苹果,橘子,香蕉,西瓜
  */

这里的then都只执行了成功(resolve)方法,来把前面的只拼接起来传给下个then()方法去接受,下个then的value接受到上面的值继续new Promise 来执行下一个异步操作;

3、.all()

Promise.all() 接收一个 promise对象的数组作为参数,当这个数组里的所有promise对象全部变为resolve或reject状态的时候,它才会去调用 .then() 方法。

// `delay`毫秒后执行resolve
  function timerPromisefy(delay) {
      return new Promise(function (resolve) {
         setTimeout(function () {
             resolve(delay);
         }, delay);
     });
  }
  var startDate = Date.now();
  // 所有promise变为resolve后程序退出
  Promise.all([
      timerPromisefy(1),
      timerPromisefy(32),
      timerPromisefy(64),
      timerPromisefy(128)
  ]).then(function (values) {
     console.log(Date.now() - startDate + 'ms');
      // 約128ms
     console.log(values);    // [1,32,64,128]
  });

所以,promise.all,会在所有的参数里的Promise方法执行完再返回所有数据,以数组的格式。

4、.race()

Promise.race()的参数跟all一样是接受一个promise对象数组,不同的是race(),的结果是只要有一个promise变个fulfilled或rejected就能够then()中获取值,然后其他的Promise对象则会继续执行。

  // `delay`毫秒后执行resolve
  function timerPromisefy(delay) {
     return new Promise(function (resolve) {
          setTimeout(function () {
            console.log(delay)
              resolve(delay);
          }, delay);
     });
  }
  // 任何一个promise变为resolve或reject 的话程序就停止运行
  Promise.race([
     timerPromisefy(1),
     timerPromisefy(32),
      timerPromisefy(64),
      timerPromisefy(128)
  ]).then(function (value) {
     console.log('then',value);    // => 1
  });
  
  控制台
  /*
  1 
  32
  64
  128
  then,1 
  */

三、在react中的运用

1、生命周期的运用

前几天有个需求是要在初次渲染完后获取页面的某个节点,但是我用了reactd的生命周期函数始终取到这个节点,但是如果用promise就能够同步异步操作去获取到;

componentWillMount() {
  let P = new Promise((resolve, reject)=>{
      console.log('new success')
      console.log('promiseNew',document.getElementById('text'))
      resolve('8888');
    })

    P.then((value)=>{
      console.log('then','obj',document.getElementById('text'));
    })
    .catch((error)=>{
      console.log('it is error',error)
    })
  }
  componentDidMount(){
    this.setState({isFind:true})
    console.log('DidMount',document.getElementById("text"))
  }
  render() {
    return (
      <div>
        {this.state.isFind ? (<Divider id="text">this is PromiseClick</Divider>) : null}
      </div>
    );
  }
  
/*
控制台打印内容:
  new success
  promiseNew null
  DidMount null
  then obj <div class=​"ant-divider ant-divider-horizontal ant-divider-with-text" id=​"text">​…​</div>​
*/

所以,我的认为是在react的生命周期函数里去执行promise的异步操作,相当于页面加载完再去执行的操作;

2、结合ajax请求的运用

前段时间,刚好有对登录调整的需求,这边登录会请求多个接口(用户信息、token、权限列表),所以之前就是用的多层的函数嵌套,在代码的排查上确实显得不那么直观,所以借此机会用了promise去做了一次代码重构。

一开是我以为NEW一个Promise实例出来,然后用return去传递返回的来的数据就可以了,如下:

错误示范

  let P = new Promise((resolve, reject)=>{
      request.post(url, { form: reqBody, timeout: configObject.agTimeout }, function (error, response, body){
            if(!error) {
                resolve(body);
            } else {
                reject(error);
            }
        });
      
    })
P.then(result=>{
  request.post(list.url1, { form: list.formData, timeout: configObject.agTimeout }, function (error, response, body) {
            if(!error){
            return body;//用return去传递返回的数据
            }else 
            
            })
})
p.then(newResult => {
  console.log('newResult',newResult)
})

/*
*
控制台打印内容:newResult ,undefined

*
*/

原因

Promise异步加载,所以中间的那个ajax请求还没结束时,就会跑到.then里面。

其实,我之前也发现别人代码里每次请求都会重新去new一个Promise然后在构造函数里面去请求ajax,之前觉得这好麻烦,但经过这次实验,算是知道原因了,只有每次请求都去new一个Promise来请求,才能让逻辑按我们所想要的顺序去执行,同时每次请求可以判断成功与否,不成功只要把error传进reject中,就能够在最后面的catch中一起捕获。代码如下:

let P = new Promise((resolve, reject)=>{
     $.ajax({
        type:"get",
        url:"index.aspx",
        success:function(data){
            if(data.code=="0"){
                resolve(data.ResultJson)//在异步操作成功时调用
            }else{
                reject(data.ErrMsg);//在异步操作失败时调用
            }
        }
    });
P.then(result=>{
  return new Promise((resolve,reject) => {
    $.ajax({
        type:"get",
        url:"index.aspx2",
        success:function(data){
            if(data.code=="0"){
                resolve(data.ResultJson)//在异步操作成功时调用
            }else{
                reject(data.ErrMsg);//在异步操作失败时调用
            }
        }
    });
  
  })

}).then((result) => {
  console.log('result',result)
}).catch((errot)=>{
  console.log('error',error)
})

/*
*
控制台打印内容:
  如果成功:就能获取返回的数据
  如果失败:就能捕获错误

*
*/

总结

Promise确实很强大,很好的解决了地狱回调的问题,打打加强了代码的可读性,让业务逻辑更加的氢气。
具体吹捧的内容我就不多说,剩下的就于大家自己去感受吧!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant