ES6 实用的promise的用法与杂谈

1.通俗点说,promise就是一种异步操作的解决方案,说起异步操作,那有必要先讲讲“同步”和“异步”的概念。

    1.1 同步:

        举个例子,比如中午做饭,先淘米,等饭熟了,然后炒菜,等菜熟了再把衣服丢经洗衣机里去洗衣服,就是说你在等一件事完成后,你才开始做下一步的事情,这就是同步,而在代码中的同步就是从上而下,逐行执行,如下所示:

function aa(){
   console.log('第一步,先淘米,现在饭熟了')
}

function bb(){
   console.log('第二步,我的菜熟了')
}

function cc(){
    console.log('第三步,洗衣机洗衣服')
}
aa() 
bb()
cc()

 

   1.2 异步

        在你淘好米的同时,你就马上把衣服丢经洗衣机里,接着就开始炒菜,几件事同时进行,有可能饭先熟,也有可能菜先熟,也有可能衣服先洗好

function aa(fn){
   console.log('第一步,先淘米,现在饭熟了')
   fn()
}

function bb(){
   console.log('第二步,我的菜熟了')
}

function cc(){
    console.log('第三步,洗衣机洗衣服')
}
aa(cc) 
bb()

解释:大家有没有发现,我是以回调函数的方式将函数cc,传入函数aa的?没错,回调函数也是最基础最常用的处理js异步操作的办法。

 

2.进入正题,谈谈promise

    Promise是一个构造函数,自己身上有all、reject、resolve这几个眼熟的方法,原型上有then、catch等同样很眼熟的方法。

    先new一个再说:

var data = new Promise(function(resolve, reject){
    setTimeout(function(){
        console.log('执行完成');
        resolve('数据1');
    }, 2000);
});

Promise的构造函数接收一个参数,是函数,并且传入两个参数:resolve,reject,分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数。

在上面的代码中,我们执行了一个异步操作,也就是setTimeout,2秒后,输出“执行完成”,并且调用resolve方法。

运行代码,会在2秒后输出“执行完成”。注意!我只是new了一个对象,并没有调用它,我们传进去的函数就已经执行了,这是需要注意的一个细节。所以我们用Promise的时候一般是包在一个函数中,在需要的时候去运行这个函数,如:

function fn1(){
    var data = new Promise(function(resolve, reject){
        setTimeout(function(){
            console.log('执行完成');
            resolve('数据1');
        }, 2000);
    });
    return data;            
}

看到这里,估计你肯定有点蒙B,写的到底是啥破玩意啊,你到底想干什么啊,别急,听我慢慢道来,还记得Promise对象上有then、catch方法吧?这就是强大之处了

  • then:

fn1().then(function(data){
    console.log(data);
});

意思就是说,当函数fn1执行完成后,调用promise上的then方法,在then方法里面接受一个data参数,这个data参数就是fn1里面传过来的,你可以在then里面对传过来的data参数进行操作,也可以继续执行其他函数,看到这里你可能已经明白了,但你一定会有一个疑问,就算说出花来,你这样不就是在玩回调嘛!我下面那样写结果还不一样:

function fn1(callback){
  callback('数据1')
}

function callback(data){
  console.log(data)
}

fn1(callback)

可是你想过没有,你现在还只是在函数里嵌套一个函数,如果让你嵌套10个呢?100个呢?你就会陷入常说的回调地狱,你确定你不会疯掉?

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


function fn1(){
    var data = new Promise(function(resolve, reject){
            resolve('数据1');
    });
    return data;            
}
function fn2(){
    var data = new Promise(function(resolve, reject){
            resolve('数据2');
    });
    return data;            
}
function fn3(){
    var data = new Promise(function(resolve, reject){
            resolve('数据3');
    });
    return data;            
}

fn1()
.then(function(data){
    console.log(data);
    return fn2();
})
.then(function(data){
    console.log(data);
    return fn3();
})
.then(function(data){
    console.log(data);
});
  • catch的用法:

  它是做什么用的呢?其实它和then的第二个参数一样,用来指定reject的回调,用法是这样:


function fn1(){
    var data = new Promise(function(resolve, reject){
             var num = 3;
              if(num>3){
                  resolve('num大于3');
               }else{
                  reject('num小于3')
                }
            
    });
    return data;            
}

fn1()
.then(function(data){
    console.log(data);
})
.catch(function(reason){
    console.log('rejected');
    console.log(reason);
});

 看看打印结果:

.finally

这个方法用的不多,很多人都会忽略这个方法,还是讲讲吧,意思是不管Promise 对象最后状态如何,都会执行的操作

function fn1(){
    var data = new Promise(function(resolve, reject){
             var num = 3;
              if(num>3){
                  resolve('num大于3');
               }else{
                  reject('num小于3')
                }
            
    });
    return data;            
}

fn1()
.then(function(data){
    console.log(data);
})
.catch(function(reason){
    console.log('rejected');
    console.log(reason);
})
.finally(()=>{
    console.log('执行了finally')
})

  • all的用法:

    这个all方法个人觉得真的比较实用,前段时间做项目的时候,产品经理有那么一个需求,当用户每次在input框里输入内容的时候,都要实时的将后台返回的查询结果实时渲染在列表中,以供用户查看,需求看起来很简单,不就是监听一下input框的value值吗?value每改变一次,就发送一次ajax的请求,将后台最后返回的数据渲染出来就好了呀!可是事实真的那么简单吗?我举个例子:比如用户想查【中国建设银行】’,

  1. 输入了‘中国’,敲下回车,发送请求,后台返回【中国建设银行,中国农业银行,中国工商银行】,
  2. 接着输“建设银行”’,敲下回车,发送请求,后台返回【中国建设银行】,

 按道理来说,我只要将最后一次返回的【中国建设银行】渲染在li中就大功告成了吧?但事实真的是这样吗?

大家知道,发送一次请求是有响应时间的,如果第一次响应时间花费了4s ,而第二次只响应时间花费了2s呢??那不是就出现了,用户精确搜索【中国建设银行】,你却给用户看【中国建设银行,中国农业银行,中国工商银行】,这样就尴尬了吧?所以这也是异步操作带来的坑,

那有没有办法让这里的异步变成类似同步请求呢?接下来promise的all方法就闪亮登场了,


function fn1(){
    var data = new Promise(function(resolve, reject){
       setTimeout(function(){
            resolve('数据1')
        },1000)    
            
    });
    return data;            
}
function fn2(){
    var data = new Promise(function(resolve, reject){
        setTimeout(function(){
            resolve('数据2')
        },3000)       
    });
    return data;            
}
function fn3(){
    var data = new Promise(function(resolve, reject){
       setTimeout(function(){
            resolve('数据3')
        },2000)    
            
    });
    return data;            
}

Promise.all([fn1(),fn2(),fn3()]).then((data)=>{
    console.log(data)
})

上面代码我fn1,fn2,fn3, 的数据分别延时1s, 3s , 2s 输出,来模拟异步请求,大家想想最后console.log(data),这个data会输出什么?

会是['数据1',‘数据3’,‘数据2’]吗?

下面就是见证奇迹的时刻了:

看到没?是不是很神奇??

转载于:https://my.oschina.net/u/3964830/blog/2052029

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值