ES规定,Promise
对象是一个构造函数,用来生成Promise
实例
const promise = new Promise(function(resove,reject){
// some code
if(/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是resolve
和reject
。它们是两个函数,由JavaScript引擎提供,不用自己部署。
resolve
函数的作用是,将Promise
对象的状态从"未完成"变成"成功"(即从pending变为resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject
函数的作用是,将Promise
对象的状态从"未完成"变为"失败"(即从pending变为rejected),在异步操作失败时调用,并将异步 操作报出的错误,作为参数传递出去。
Promise
实例生成以后,可以用then
方法分别指定resolved
状态和rejected
状态的回调函数。
promise.then(function(value){
//success
},function(error){
//failure
})
then
方法可以接受两个回调函数作为参数。第一个回调函数时Promise
对象的状态变为resolved
时调用,第二个回调函数是Promise
对象的状态变为rejected
时调用。其中,第二个函数是可选的,不一定是提供。这两个函数都接受Promise
对象传出的值作为参数。
下面是一个Promise
对象的简单例子。
function timeout(ms){
return new Promise((resolve,reject) => {
setTimeout(resolve,ms,"done");
});
}
timeout(100).then((value) =>{
console.log( value )
})
上面代码中,timeout
方法返回一个Promise
实例,表示一段时间以后才会发生的结果,过了指定的时间(ms)参数以后,Promise
实例的状态变为resolved
,就会=触发then
方法绑定的回调函数。
** Promise 新建后就会立即执行。**
let promise = new Promise((resolve,reject)=>{
console.log("Promise");
resolve();
});
promise.then(function(){
console.log( "resolved.");
})
console.log( "hi")
//Promise
//hi
//resolved
上面的代码中,Promise新建后立即执行,所以首先输出的是Promise
。然后,then
方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved
最后输出。
下面是异步加载图片的例子。
function loadImageAsync(url){
return new Promise((resolve,reject) =>{
const image = new Image();
image.onload = ()=>{
resolve(image);
};
image.onerror = ()=>{
reject( new Error("Could not load image at" + url));
};
image.src = url;
})
}
上面代码中,使用Promise
包装了一个图片加载的异步操作,如果加载成功,就调用resolve
方法,否则就调用reject
方法。
下面是一个用Promise
对象实现的Ajax操作的例子。
const getJSON = function(url){
const promise = new Promise(function(resolve,reject){
const handler = function(){
if(this.readyState !== 4){
return ;
}
if(this.status === 200){
resolve(this.response);
}else{
reject(new Error(this.statusText));
}
};
const client = new XMLHttpRequest();
client.open("GET",url);
client.onreadystatechange = handler;
client.responseType = "json";
client.setRequestHeader("Acceot","application/json");
client.send();
});
return promise;
}
getJSON("/post.json").then(function(json){
console.log( "Contents: "+json);
},function(error){
console.error("出错了",error)
});
上面代码中,getJSON
是对 XMLHttpRequest对象的封装,用于发出一个队JSON数据的HTTP请求,并且返回一个Promise
对象。需要注意的是,在getJSON
内部,resolve
函数和reject
函数调用时,都带有参数。
如果调用resolve
函数和reject
函数时带有参数,那么它们的参数会被传递给回调函数。reject
函数的参数通常是Error
对象的实例,表示抛出错误;resolve
函数的参数除了正常的值以外,还可能是另一个 Promise 实例,比如像下面这样。
const p1 = new Promise(function(resolve,reject){
//...
})
const p2 = new Promise(function(resolve,reject){
//...
resolve(p1)
})
上面代码中,p1
和p2
都是Promise
的实例,但是p2
的resolve
方法将p1
作为参数,即一个异步操作的结果是返回另一个异步操作。
注意,这是p1
的状态就会传递给p2
也就是说,p1
的状态决定了p2
的状态。如果p1
的状态是pending
,那么p2
的函数就会等待p1
的状态 改变;如果p1
的状态已经是resolved
或者rejected
,那么p2
的回调函数 将会立即执行。
const p1 = new Promise(function(resolve,reject){
setTimeout(()=> reject(new Error("fail")),3000)
})
const p2 = new Promise(function(resolve,reject){
setTimeout(()=>resolve(p1),1000)
})
p2.then(result => console.log(result))
.catch(error => console.log(error))
上面的代码中,p1
是一个 Promise ,3秒之后变为rejected
。p2
的状态在 1 秒之后改变,resolve
方法返回的是p1
。由于p2
返回的是另一个 Promise,导致p2
自己的状态无效了,由p1
的状态决定p2
的状态。所以,后面的then
语句都变成针对后者(p1
)。又过了 2 秒,p1
变为rejected
,导致触发catch
方法指定的回调函数。
注意,调用resolve
或reject
并不会终结Promise 的参数函数的执行。
new Promise(function(resolve,reject){
resolve(1);
console.log( 2);
}).then(r => {
console.log(r )
})
//2
//1
上面的代码中,调用resolve(1)
以后,后面的console.log(2)
还是会执行的,并且会首先打印出来,这是因为立即 resolved 的 Promise 是在本轮事件循环的末尾执行,后续操作应该放到then
方法里面,而不应该直接写在resolve
或reject
的后面。所以,最好在它们的前面加上return
语句。这样就不会有意外了。
new Promise(function(resolve,reject){
return resolve(1);
//后面的语句不会执行
console.log( 2 )
})
网友评论