Promise

首先要了解什么是异步操作?所谓异步操作,指的是可以跟当前程序同时执行的操作

$("#page").scrolltop(0 ,1000);    //使用1秒钟时间将页面滚动至顶部
$("#nav-float").hide (1000);    //使用1秒钟时间将悬浮导航栏隐藏

这两个方法会同时完成,它们的编写顺序并不会影响它们的执行顺序

//异步操作的特点就是,不会打断当前程序的执行
//getUsers请求发出后,会立刻向下继续执行第二个请求
ajax("/getUsers",function(data) {
    //回掉函数会在请求成功后调用
})
//resumelist请求会立刻开始,无论getUsers是否结束
ajax("/resumelist", function(data) {

})
//至于哪一个ajax先返回结果并执行回调函数,从代码的编写顺序上是无法确定的。

异步操作:当一个操作开始执行后,主程序无需等待它的完成,可以继续向下执行。此时该操作可以跟主程序同时(并发)执行。通常当操作完成时,会执行一个我们事先设定好的回调函数来做后续的处理。
常见的异步操作:
1.添加定时器 setTimeout/setInterval
2.执行某个动画 animate
3.发起网络请求 request

异步操作常见语法:
1.事件监听

document.getElementById('#start').addEventListener('click', start, false);
function start() {
// 响应事件,进行相应的操作
}
// jquery on 监听
$('#start').on('click', start)

2.回调

// 比较常见的有ajax
$.ajax('http://www.wyunfei.com/', {
 success (res) {
   // 这里可以监听res返回的数据做回调逻辑的处理
 }
})

// 或者在页面加载完毕后回调
$(function() {
 // 页面结构加载完成,做回调逻辑处理
})

Eg:

//调用两个动画,会有先后顺序,传统解决方式为回调函数,如下:
animateA(function( ){
      animateB( );  
})   

但是当调用的动画过多时,就需要很多的异步操作,如果按照以上方法,就会不断回调,产生“回调地狱”

//但是当调用的动画过多时,就需要很多的异步操作,就会不断回调,产生“回调地狱”
animateA(function( ){
    animateB(function( ){
        animateC(function( ){
            animateD(function( ){
                ......   
            }); 
        }); 
    }); 
}) 

Promise改造以上代码:

new Promise(animateA)
        .then(animateB)
        .then(animateC)
        .then(animateD);  

接下来介绍Promise:

1、主要用于异步计算
2、可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果
3、可以在对象之间传递和操作promise,帮助我们处理队列

.promise是一个对象, 对象和函数的区别就是对象可以保存状态, 函数不可以( 闭包除外)
.并未剥夺函数return的能力, 因此无需层层传递callback, 进行回调获取数据
.代码风格, 容易理解, 便于维护
.多个异步等待合并便于解决

new Promise(
            function (resolve, reject) {
                // 一段耗时的异步操作
                resolve('成功') // 数据处理完成
                //reject('失败')/ // 数据处理出错
            }
        ).then(
            (res) => {
                console.log(res)
            }, // 成功
            (err) => {
                console.log(err)
            } // 失败
        )

resolve作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
promise有三个状态:
1、pending[待定]初始状态
2、fulfilled[实现]操作成功
3、rejected[被否决]操作失败

当promise状态发生改变,就会触发then()里的响应函数处理后续步骤;
promise状态一经改变,不会再变。
Promise对象的状态改变,只有两种可能:
从pending变为fulfilled
从pending变为rejected。
这两种情况只要发生,状态就凝固了,不会再变了。

举例:

new Promise(resolve => {
            setTimeout(() => {
                resolve('hello')
            }, 2000)
        }).then(res => {
            console.log(res)
        })
//2s后打印hello

结论: promise作为队列最为重要的特性, 我们在任何一个地方生成了一个promise队列之后, 我们可以把他作为一个变量传递到其他地方。

   假如在.then() 的函数里面不返回新的promise, 会怎样?
        .then()
        1、 接收两个函数作为参数, 分别代表fulfilled( 成功) 和rejected( 失败)
        2、.then() 返回一个新的Promise实例, 所以它可以链式调用
        3、 当前面的Promise状态改变时,.then() 根据其最终状态, 选择特定的状态响应函数执行
        4、 状态响应函数可以返回新的promise, 或其他值, 不返回值也可以我们可以认为它返回了一个null;
        5、 如果返回新的promise, 那么下一级.then() 会在新的promise状态改变之后执行
        6、 如果返回其他任何值, 则会立即执行下一级.then()

Promise 的使用以及原理:

promise的实例代码:

newPromise(resolve=>{
    ajax("/pay/post", data=>resolve() );
}).then(resolve=>{
    ajax("/order/fix", data=>{
        //处理数据   
    })
})

修改为js代码结构:

new Promise(function(resolve){
    ajax("/pay/post",function(data){
        resolve();
    })
}).then(function(){
    ajax("/order/fix",function(data){

    })
})
  • [根据问题理解promise ] ----------------------------------------------------------------------------

问题1, 作为一个异步函数,尤其像ajax这种网络请求,连我自己都不能确定函数的执行时间,Promise是怎么知道第一个函数什么时候结束的? 然后再开始执行下一个?

答:Promise并没有那么神奇,它并不能知道我们的函数什么时候结束,
上面代码中的第3行
在ajax请求结束执行回调的时候,
我们调用了一个resolve()函数,这句代码非常的关键.
这其实就是在通知Promise,当前这个函数结束啦,
你可以开始执行下一个。 这时Promise就会去执行then里面的函数了。

问题2, 所以按照你的意思,如果我不调用这个方法,Promise就不知道这个函数有没有结束,那么then里面的函数就不会执行,也就是说我的第二个请求就永远不会发送了呗?

答:正确

问题3, 可是这个resolve函数是从哪来的? 需要我自己定义吗? 从代码上看它好像是个参数,那又是谁传入函数中的?

答:你得先弄明白Promise的基本结构
new Promise(函数1).then(函数2);

我们把函数1和函数2都以参数形式传给了一个Promise对象,
所以接下来函数1和2都会由这个Promise对象控制,
简单的说,函数1和函数2都会由Promise对象来执行。
所以在函数1执行时,参数也当然是由Promise对象传递进去的。

new Promise(function(resolve){
  //resolve是Promise对象在调用函数时传入的参数
}).then(函数2);

问题4, Promise对象为啥要在执行第1个任务的时候,把这个resolve函数 传进来,有什么目的?

答:Promise对象没办法知道我们的异步函数啥时候结束。它传进来的resolve函数, 就好像一个对讲机,当我们的异步任务要结束时,通过对讲机 来通知Promise对象。也就是调用resolve方法。

new Promise(function(resolve){
    ajax("/pay/post",function(data){
        //当请求结束时,通过调用resolve方法,通知Promise对象,该任务已完成
        resolve(); //收到通知后,Promise会立刻开始函数2的执行
    })	
}).then(函数2);

所以这个resolve函数,必须在异步任务的最后调用(例如ajax的回调方法),相当于告诉Promise对象,该任务结束。

问题6, 那如果我有ajaxA、ajaxB、ajaxC三个异步任务,想按照先A后B再C的顺序执行,像这样写行吗?

new Promise(function(resolve){
    ajax("/AAA", function(){
        resolve(); //通知Promise该任务结束
    })    
}).then(function(resolve){
    ajax("/BBB", function(){
        resolve();//通知Promise该任务结束
    })
}).then(function(){
    ajax("/CCC", function(){ //.... })
})  

答:上面的这种写法是不对的。
Promise的中文含义是“承诺”,
则意味着,每一个Pormise对象,代表一次承诺
而每一次承诺,只能保证一个任务的顺序,也就是说
new Promise(A).then(B); 这句话表示, 只能保证A和B的顺序

一旦A执行完,B开始后,这次承诺也就兑现了,Promise对象也就失效了
那如果还有C呢? 我们就必须在函数B中,
重新创建新的Promise对象,来完成下一个承诺,具体的写法就像这样:

new Promise(函数1(resolve){
    ajaxA("xxxx", function(){
        resolve();//通知Promise该任务结束
    })    
}).then(函数2(){
    //在函数2开始运行后,第一次创建的Promise对象完成使命,已经不能再继续工作。
    //此时,我们创建并返回了新的Promise对象
    return new Promise(function(resolve){
        ajaxB("xxxx", function(){
            resolve();//通知新的Promise对象该任务结束
        })    
    })
}).then(函数3(){ //尽管这里使用了链式调用,但负责执行函数3的,已经是新的Promise对象了
    // 如果,我们还有ajaxD需要顺序调用
    // 那就必须在这里重新new Promise()对象了
    ajaxC("xxx", function(){     })
})   

问题7:Promise还有什么其它强大的功能(promise.all—批量操作)

答:

如果我有 A,B,C 三个异步任务,ABC同时开始执行
当A,B,C三个任务全部都结束时,执任务D,
传统方法实现起来就比较复杂,Promise就非常简单,就像这样:

Promise.all([new Promise(A), new Promise(B), new Promise(C)])
.then(function(){
    D();
});

问题8, 希望A,B,C 其中任意一个任务完成,就马上开始任务D。

答:

Promise.race([new Promise(A), new Promise(B), new Promise(C)])
.then(function(){
   D();
});
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值