概念:Promise 对象用于表示一个异步操作的最终完成 (或失败), 及其结果值。
语法:
new Promise( function(resolve, reject) {...} /* executor */ );
参数:
executor
executor是带有 resolve 和 reject 两个参数的函数 。Promise构造函数执行时立即调用executor 函数, resolve 和 reject 两个函数作为参数传递给executor(executor 函数在Promise构造函数返回所建promise实例对象前被调用)。resolve 和 reject 函数被调用时,分别将promise的状态改为fulfilled(完成)或rejected(失败)。executor 内部通常会执行一些异步操作,一旦异步操作执行完毕(可能成功/失败),要么调用resolve函数来将promise状态改成fulfilled,要么调用reject 函数将promise的状态改为rejected。如果在executor函数中抛出一个错误,那么该promise 状态为rejected。executor函数的返回值被忽略。
描述:
Promise 对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的promise对象
一个 Promise有以下几种状态:
pending: 初始状态,既不是成功,也不是失败状态。
fulfilled: 意味着操作成功完成。
rejected: 意味着操作失败。
pending 状态的 Promise 对象可能会变为fulfilled 状态并传递一个值给相应的状态处理方法,也可能变为失败状态(rejected)并传递失败信息。当其中任一种情况出现时,Promise 对象的 then 方法绑定的处理方法(handlers )就会被调用(then方法包含两个参数:onfulfilled 和 onrejected,它们都是 Function 类型。当Promise状态为fulfilled时,调用 then 的 onfulfilled 方法,当Promise状态为rejected时,调用 then 的 onrejected 方法, 所以在异步操作的完成和绑定处理方法之间不存在竞争)。
因为 Promise.prototype.then 和 Promise.prototype.catch 方法返回promise 对象, 所以它们可以被链式调用。
属性:
Promise.length
length属性,其值总是为 1 (构造器参数的数目).
Promise.prototype
表示 Promise 构造器的原型.
方法:
Promise.all(iterable)
这个方法返回一个新的promise对象,该promise对象在iterable参数对象里所有的promise对象都成功的时候才会触发成功,一旦有任何一个iterable里面的promise对象失败则立即触发该promise对象的失败。
这个新的promise对象在触发成功状态以后,会把一个包含iterable里所有promise返回值的数组作为成功回调的返回值,顺序跟iterable的顺序保持一致;如果这个新的promise对象触发了失败状态,它会把iterable里第一个触发失败的promise对象的错误信息作为它的失败错误信息。Promise.all方法常被用于处理多个promise对象的状态集合。(可以参考jQuery.when方法—译者注)
Promise.race(iterable)
**当iterable参数里的任意一个子promise被成功或失败后,**父promise马上也会用子promise的成功返回值或失败详情作为参数调用父promise绑定的相应句柄,并返回该promise对象。
Promise.reject(reason)
返回一个状态为失败的Promise对象,并将给定的失败信息传递给对应的处理方法
Promise.resolve(value)
返回一个状态由给定value决定的Promise对象。如果该值是thenable(即,带有then方法的对象),返回的Promise对象的最终状态由then方法执行决定;否则的话(该value为空,基本类型或者不带then方法的对象),返回的Promise对象状态为fulfilled,并且将该value传递给对应的then方法。通常而言,如果你不知道一个值是否是Promise对象,使用Promise.resolve(value) 来返回一个Promise对象,这样就能将该value以Promise对象形式使用。
ES5中传统的回调
{
//Es5
//基本定义 模拟ajax请求
let ajax = function(callback) {
console.log('执行');
setTimeout(function(){
//执行回调函数
callback&&callback.call();
},1000)
};
ajax(function(){
console.log('ES5'+'timeout1');
});
}
ES6新增的Promise可解决地狱回调
{
//ES6
let ajax = function() {
console.log('执行2');
return new Promise(function(resolve,reject){
//setTimeout可以看成一个模拟网络等异步执行的函数
setTimeout(function(){
resolve();//表示执行下一步(then())
}, 1000);
})
};
ajax().then(function(){
console.log('promise','timeout2');
});
}
Promise实例
{
let ajax = function() {
console.log('执行3');
return new Promise(function(resolve,reject){
setTimeout(function(){
resolve();
}, 3000);
})
};
ajax()
.then(function(){
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log('2');
resolve()
}, 3000);
});
})
.then(function(){
console.log('timeout3');
// resolve(); //直接使用会报错 必须在返回Promise对象中才能执行
return new Promise(function(resolve,reject){
setTimeout(function(){
resolve();
},3000);
})
})
//error 因为如果上一个不是返回Promise对象故resolve()无法执行下面的then()
.then(function(){
console.log('4');
})
//打印结果:执行3 2 timeout3 4
}
catch捕获错误:在Promise对象中有两个参数
{
//catch捕获错误
let ajax = function(num){
console.log('执行4');
return new Promise(function(resolve,reject) {
if(num > 5){
resolve();
}else{
reject('结果小于5');
}
})
}
ajax(6)
.then(function(){
console.log('log',6); //log 6
})
.catch(function(err){
console.log('catch',err);
});
ajax(3)
.then(function(){
console.log('log',3);
})
.catch(function(err){
console.log('catch',err); //catch 结果小于5
ajax(7)
.then(function(){
console.log('log',7); // 7
})
});
}
Promise还可以做更多的事情,比如,有若干个异步任务,需要先做任务1,如果成功后再做任务2,任何任务失败则不再继续并执行错误处理函数。
要串行执行这样的异步任务,不用Promise需要写一层一层的嵌套代码。有了Promise,我们只需要简单地写:
job1.then(job2).then(job3).catch(handleError);
//其中,job1、job2和job3都是Promise对象。
除了串行执行若干异步任务外,Promise还可以并行执行异步任务。
试想一个页面聊天系统,我们需要从两个不同的URL分别获得用户的个人信息和好友列表,这两个任务是可以并行执行的,用Promise.all()实现如下:
var p1 = new Promise(function (resolve, reject) {
setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
setTimeout(resolve, 600, 'P2');
});
// 同时执行p1和p2,并在它们都完成后执行then:
Promise.all([p1, p2]).then(function (results) {
console.log(results); // 获得一个Array: ['P1', 'P2']
});
有些时候,多个异步任务是为了容错。比如,同时向两个URL读取用户的个人信息,只需要获得先返回的结果即可。这种情况下,用Promise.race()实现:
var p1 = new Promise(function (resolve, reject) {
setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
setTimeout(resolve, 600, 'P2');
});
Promise.race([p1, p2]).then(function (result) {
console.log(result); // 'P1'
});
由于p1执行较快,Promise的then()将获得结果’P1’。p2仍在继续执行,但执行结果将被丢弃。
如果我们组合使用Promise,就可以把很多异步任务以并行和串行的方式组合起来执行。
Promise.all()实例 - 所有图片加载完在添加到页面
{
// 所有图片加载完在添加到页面
function loadImg(src){
return new Promise((resolve,reject)=>{
let img = document.createElement('img');
img.src = src;
img.onload = function(){
resolve(img);
}
img.onerror = function(err){
reject(err);
}
})
}
function showImgs(imgs){
imgs.forEach(function(img){
document.body.appendChild(img);
})
}
//Promise.all() 需等待所有资源加载完成才执行下一步
Promise.all([
loadImg('http://localhost:8081/H5test/img/monster1.jpg'),
loadImg('http://localhost:8081/H5test/img/mario.jpg'),
loadImg('http://localhost:8081/H5test/img/monster1.jpg')
]).then(showImgs);
}
Promise.race()实例 - 有一个图片加载完就添加到页面 其他图片不显示了
{
// 有一个图片加载完就添加到页面 其他图片不显示了
function loadImg(src){
return new Promise((resolve,reject)=>{
let img = document.createElement('img');
img.src = src;
img.onload = function(){
resolve(img);
}
img.onerror = function(err){
reject(err);
}
})
}
//创建图片
function showImgs(img){
let p = document.createElement('p');
p.appendChild(img);
document.body.appendChild(p);
}
//Promise.race() 只要其中一个资源先加载完成就只执行该资源对应下一步的操作
Promise.race([
loadImg('http://localhost:8081/H5test/img/monster1.jpg'),
loadImg('http://localhost:8081/H5test/img/mario.jpg'),
loadImg('http://localhost:8081/H5test/img/monster1.jpg')
]).then(showImgs);
}