Promise

 

ES6 原生提供了 Promise 对象。

Promise,就是一个对象,代表一个异步操作,用来传递异步操作的消息。它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个事件提供统一的 API,可供进一步处理。

Promise构造函数,接收的参数是函数,两个(resolve、reject)分别代表:

▪ resolve:异步操作成功后的回调函数

▪ reject:异步操作失败后的回调函数

▪ 标准来讲,resolve是将Promise状态置为fullfiled,reject将Promise状态置为rejected

▪ Promise一般是包在一个函数中,在需要的时候去运行这个函数就可以,我们的Promise并不需要调用,外面一层的函数运行,Promise就会执行

Promise 对象有以下两个特点。

(1)状态不受外界影响。有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和 Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

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

Promise 也有一些缺点。首先,无法取消 Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。第三,当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。也就是说then、catch、finally的回调都无法进入。

常用的:

Promise.prototype.then方法:链式操作

function runAsync(){
    var p = new Promise(function(resolve, reject){
        //做一些异步操作
        setTimeout(function(){
            console.log('执行完成');
            resolve('随便什么数据');
        }, 2000);
    });
    return p;            
}
runAsync().then(function(data){
    console.log(data);
    //后面可以用传过来的数据做些其他操作
    //......
});

// 我们包装好的这个runAsync函数,会return出我们的Promise对象,也就是说,执行这个函数我们得到一个Promise对象,还记得Promise对象上有then,catch方法,这也是强大之处:
// 在runAsync()的返回上直接调用then方法,then接收到一个参数是函数,并且会拿到resolve中传的参数,运行这段代码,两秒后输出‘随便什么数据’。

// 也就是说then和我们的回调函数callback一个意思,在runAsync异步任务完成之后执行,这也就是Promise的作用了,简单来说,就是能把原来的回调写法分离开来,在异步操作执行完之后,用链式调用的方式执行回调函数。

对于上述的用法可能你会不屑一顾,觉得callbak传进去也可以实现

function runAsync(callback){
    setTimeout(function(){
        console.log('执行完成');
        callback('随便什么数据');
    }, 2000);
}

runAsync(function(data){
    console.log(data);
});

效果与then一样,费劲写Promise干嘛,那么问题来了,如果是多层回调怎么办,如果callback也是一个异步操作,而且结束后也需要相应的回调函数,该怎么办,总不能定义callback2、callback3、···吧,而我们的Promise的优势在于,可以再then中继续回调Promise对象的返回,然后继续then进行回调操作。

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

function runAsync1(){
    var p = new Promise(function(resolve, reject){
        //做一些异步操作
        setTimeout(function(){
            console.log('异步任务1执行完成');
            resolve('随便什么数据1');
        }, 1000);
    });
    return p;            
}
function runAsync2(){
    var p = new Promise(function(resolve, reject){
        //做一些异步操作
        setTimeout(function(){
            console.log('异步任务2执行完成');
            resolve('随便什么数据2');
        }, 2000);
    });
    return p;            
}
function runAsync3(){
    var p = new Promise(function(resolve, reject){
        //做一些异步操作
        setTimeout(function(){
            console.log('异步任务3执行完成');
            resolve('随便什么数据3');
        }, 2000);
    });
    return p;            
}

// 调用1
runAsync1().then(function(data){
    console.log(data);
    return runAsync2();
}).then(function(data){
    console.log(data);
    return runAsync3();
}).then(function(data){
    console.log(data);
});

// 输出结果1
1.	异步任务1执行完成
2.	随便什么数据1
3.	异步任务2执行完成
4.	随便什么数据2
5.	异步任务3执行完成
6.	随便什么数据3

// 调用2
runAsync1().then(function(data){
    console.log(data);
    return runAsync2();
}).then(function(data){
    console.log(data);
    return '直接返回数据';  //这里直接返回数据
}).then(function(data){
    console.log(data);
});
// 输出结果2
1.	异步任务1执行完成
2.	随便什么数据1
3.	异步任务2执行完成
4.	随便什么数据2
5.	直接返回数据

Promise.prototype.catch方法:捕捉错误

前面的例子只有成功的的回调,没有失败的情况,reject就是讲Promise置为rejected状态,这样我们在then中就可以铺捉到,然后执行失败的回调。

除了和then第二个参数里面一样外,还有另外一个作用,在执行resolve的回调时,如果抛出异常,不会报错卡死js(js报错的话,后面代码不再执行,停止运行),而是执行catch方法

function getNumber(){
    var p = new Promise(function(resolve, reject){
        //做一些异步操作
        setTimeout(function(){
            var num = Math.ceil(Math.random()*10);            
            if(num<=5){
                resolve(num);
            }else{
                reject('数字太大了');
            }
        }, 2000);
    });
    return p;            
}

// 链式catch 第一种用法
getNumber()
.then(function(data){
    console.log('resolved');
    console.log(data);
})
.catch(function(reason){
    console.log('rejected');
    console.log(reason);
});
// 第二种用法,在then中第二个参数中回调
getNumber().then(
    function(data){
        console.log('resolved');
        console.log(data);
    }, 
    function(reason){
        console.log('rejected');
        console.log(reason);
    }
);

// 第三种,在执行resolve的回调时,如果抛出异常,不会报错卡死js(js报错的话,后面代码不再执行,停止运行),而是执行catch方法
getNumber()
.then(function(data){
    console.log('resolved');
    console.log(data);
    console.log(somedata); 
//此处的somedata未定义,报错、,走catch
})
.catch(function(reason){
    console.log('rejected');
    console.log(reason);
})

getNumber 函数用来异步获取数字,2s执行完成,如果数字小于5,认为成功,否则失败,getNumber默认向then传了两个参数,一个是resolve回调,另一个对应reject回调。

 

Promise.all方法

Promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。我们仍旧使用上面定义好的runAsync1、runAsync2、runAsync3这三个函数,代码如下:

这样子是三个异步操作并行执行,等到他们都执行结束才回到then中,all会把异步操作结果,也就是resolve的参数放到一个数组内传给then。

// 执行
Promise.all([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
    console.log(results);
});
//输出
1.	异步任务1执行完成
2.	异步任务2执行完成
3.	异步任务3执行完成
4.	[‘随便什么数据1’,’随便什么数据2’,略不想写] all里面回调then中的输出

有了all,你就可以并行执行多个异步操作,并且在一个回调中处理所有的返回数据

Promise.race方法

rece用法,all方法效果实际上是[谁跑得慢,以谁为准执行回调],也就是说all是在所有的异步函数全部执行结束才走then函数,那么相对于另一个方法[谁跑得快,以谁为准执行回调],这就是rect,这个词就是赛跑的意思。

Promise.race([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
    console.log(results);
});
// 这三个异步操作同样是并行执行的。结果你应该可以猜到,1秒后runAsync1已经执行完了,此时then里面的就执行了。结果是这样的: 
1.	异步任务1执行完成
2.	随便什么数据1 // race 中输入
3.	异步任务2执行完成 //rece虽然输出了,但是异步回调还在继续
4.	异步任务3执行完成



// 这个race有什么用呢?使用场景还是很多的,比如我们可以用race给某个异步请求设置超时时间,并且在超时后执行相应的操作,代码如下:

//请求某个图片资源
function requestImg(){
    var p = new Promise(function(resolve, reject){
        var img = new Image();
        img.onload = function(){
            resolve(img);
        }
        img.src = 'xxxxxx';
    });
    return p;
}

//延时函数,用于给请求计时
function timeout(){
    var p = new Promise(function(resolve, reject){
        setTimeout(function(){
            reject('图片请求超时');
        }, 5000);
    });
    return p;
}

Promise.race([requestImg(),timeout()])
.then(function(results){
    console.log(results);
}).catch(function(reason){
    console.log(reason);
});

// 结果
requestImg函数会异步请求一张图片,我把地址写为”xxxxxx”,所以肯定是无法成功请求到的。timeout函数是一个延时5秒的异步操作。我们把这两个返回Promise对象的函数放进race,于是他俩就会赛跑,如果5秒之内图片请求成功了,那么遍进入then方法,执行正常的流程。如果5秒钟图片还未成功返回,那么timeout就跑赢了,则进入catch,报出“图片请求超时”的信息。运行结果如下: 
1.	GET file://••••••••••••• 图片加载失败的报错
2.	图片请求超时
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Promise嵌套是指在使用Promise时,一个Promise的回调函数中又返回了一个新的Promise,形成了嵌套的结构。这种嵌套的结构可以用来处理多个异步操作的依赖关系,使得代码更加清晰和可读。 在Promise嵌套中,可以通过链式调用的方式来处理多个异步操作。具体来说,可以在一个Promise的回调函数中返回一个新的Promise对象,然后继续在新的Promise对象上添加回调函数。这样就可以形成一个Promise链,每个Promise的回调函数都可以处理前一个Promise的结果,并返回一个新的Promise对象。 下面是一个简单的示例,展示了Promise嵌套的用法: ```javascript function asyncOperation1() { return new Promise((resolve, reject) => { setTimeout(() => { resolve('Operation 1 completed'); }, 1000); }); } function asyncOperation2() { return new Promise((resolve, reject) => { setTimeout(() => { resolve('Operation 2 completed'); }, 2000); }); } function asyncOperation3() { return new Promise((resolve, reject) => { setTimeout(() => { resolve('Operation 3 completed'); }, 1500); }); } asyncOperation1() .then(result1 => { console.log(result1); return asyncOperation2(); }) .then(result2 => { console.log(result2); return asyncOperation3(); }) .then(result3 => { console.log(result3); }) .catch(error => { console.error(error); }); ``` 在上面的示例中,asyncOperation1、asyncOperation2和asyncOperation3分别表示三个异步操作。通过Promise的then方法,可以依次处理这三个异步操作的结果,并在控制台输出。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值