目录
Promise
所谓 Promise,简单来说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个 异步操作)的结果。从语法上来说, Promise 是一个对象,从它可以获取异步操作的消息。 Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
特点:
- 对象的状态不受外界影响。 Promise 对象代表一个异步操作,有 3 种状态:Pending (进 行中)、 Fulfilled (己成功)和 Rejected (己失败)。只有异步操作的结果可以决定当前是哪一种 状态,任何其他操作都无法改变这个状态。
- -旦状态改变就不会再变,任何时候都可以得到这个结果。 Promise 对象的状态改变只 有两种可能:从 Pending 变为 Fulfilled 和从 Pending 变为 Rejected。只要这两种情况发生,状态 就凝固了,不会再变,而是一直保持这个结果,这时就称为 Resolved (己定型)。 就算改变己经 发生,再对 Promise 对象添加回调函数,也会立即得到这个结果。这与事件 CEvent)完全不同。 事件的特点是,如果错过了它,再去监昕是得不到结果的。
常用用法
Promise 实例生成以后,可以用 then 方法分别指定 Resolved 状态和 Rejected 状态的回调 函数。
JavaScript 提供原生的Promise构造函数,用来生成 Promise 实例。
var promise= new Promise(function(resolve, reject) {
// ... some code
if (/*异步操作成功*/){
resolve(value) ;
}
else { reject(error); }
});
promise.then(
function(value} { //success } ,
function (error) { // failure }
});
延时执行
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms,'done');
});
timeout(1000).then ((value) => {
console .log (value);
});
异步加载图片
function loadimageAsync(url){
return new Promise(function(resolve, reject){
var image= new Image() ;
image.onload =function(){
resolve(image);
}
image.onerror =function(){
reject(new Error('Could not load image at'+ url));
}
image.src = url;
});
}
AJAX操作
var getJSON = function(url){
var promise= new Promise(function(resolve, reject){
var client= new XMLHttpRequest() ;
client.open('GET', url);
client.onreadystatechange = handler;
client.responseType = 'json';
client.setRequestHeader('Accept','application/json');
client.send();
function handler(){
if(this.readyState !== 4){
return;
}
if (this.status === 200){
resolve(this.response);
} else {
reject(new Error(this . statusText)) ;
}
}
});
return promise;
}
getJSON('/posts.]son').then(function(json){
console.log('Contents:'+ json);
}, function(error){
console.error('出错了',error);
});
方法
Promise.prototype.then
Promise 实例具有then方法,也就是说,then方法是定义在原型对象Promise.prototype上的。它的作用是为 Promise 实例添加状态改变时的回调函数。前面说过,then方法的第一个参数是resolved状态的回调函数,第二个参数是rejected状态的回调函数,它们都是可选的。
then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。
getJSON("/posts.json").then(function(json) {
return json.post;
}).then(function(post) {
// ...
});
上面的代码使用then方法,依次指定了两个回调函数。第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。
采用链式的then,可以指定一组按照次序调用的回调函数。这时,前一个回调函数,有可能返回的还是一个Promise对象(即有异步操作),这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用。
getJSON("/post/1.json").then(function(post) {
return getJSON(post.commentURL);
}).then(function (comments) {
console.log("resolved: ", comments);
}, function (err){
console.log("rejected: ", err);
});
上面代码中,第一个then方法指定的回调函数,返回的是另一个Promise对象。这时,第二个then方法指定的回调函数,就会等待这个新的Promise对象状态发生变化。如果变为resolved,就调用第一个回调函数,如果状态变为rejected,就调用第二个回调函数。
可以使用箭头函数变得更为简洁
getJSON("/post/1.json").then(
post => getJSON(post.commentURL)
).then(
comments => console.log("resolved: ", comments),
err => console.log("rejected: ", err)
);
Promise.prototype.catch
该方法是Promise.prototype.then(null, rejection)的别名,用于指定发 生错误时的回调函数。
getJSON( ’/ posts.json’).then(function(posts){
//some code
}).catch(function(error){
//处理 getJS ON 和前一个回调函数运行时发生的错误
console.log(’发生错误!’,error);
});
// 写法一
const promise = new Promise(function(resolve, reject) {
try {
throw new Error('test');
} catch(e) {
reject(e);
}
});
promise.catch(function(error) {
console.log(error);
});
// 写法二
const promise = new Promise(function(resolve, reject) {
reject(new Error('test'));
});
promise.catch(function(error) {
console.log(error);
});
Promise.prototype.finally
finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。
finally方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是fulfilled还是rejected。这表明,finally方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
Promise.all
Promise.all 方法用于将多个 Promise 实例包装成一个新的 Promise 实例。
var p = Promise.all([pl, p2 , p3]);
Promise.all 方法接受一个数组作为参数, p1 p2, p3 都是 Promise 对象的实例:如果不是, 就会先调用下面讲到的 Promise.resolve 方法, 将参数转为 Promise 实例,再进一步处理( Promise.all 方法的参数不一定是数组, 但是必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例)
p的状态由p1、p2、p3 决定, 分成两种情况
- 只有 p1、p2、p3的状态都变成Fulfilled, p的状态才会变成Fulfilled,此时 p1、p2、p3的返回值组成一个数组,传递给p的回调函数
- 只要 p1、p2、p3中有一个被 Rejected, p的状态就变成Rejected,此时第一个被Rejected的实例的返回值会传递给p的回调函数。
Promise.race
Promise.race 方法同样是将多个 Promise 实例包装成一个新的 Promise 实例。
var p = Promise.race ([pl, p2, p3]);
上面的代码中,只要 p1,p2, p3 中有一个实例率先改变状态, p 的状态就跟着改变。那 个率先改变的 Promise 实例的返回值就传递给 p 的回调函数。
Promise.resolve
有时需要将现有对象转为 Promise 对象, Prom工se.resolve 方法就起到这个作用。
var jsPromise = Promise.resolve($.ajax(’/whatever.json’));
上面的代码将 jQuery 生成的 deferred 对象转为新的 Promise 对象。
Promise.resolve 等价于下面的写法。
Promise.resolve (‘foo’) //等价于
new Promise(resolve =>resolve (‘foo’));
resolve 参数 4 种情况
- 参数是一个 Promise实例
如果参数是 Promise 实例 ,那么 Promise.resolve 将不做任何修改,原封不动地返回这个实例。
- 参数是一个 thenable 对象
thenable对象指的是具有 then 方法的对象,比如下面这个对象
let thenable = {
then: function(resolve, reject){
resolve(42);
}
};
Promise.resolve方法会将这个对象转为 Promise 对象,然后立即执行 thenable对象的 then 方法。
let pl= Promise.resolve(thenable);
pl.then(function(value){
console.log (value); //42
});
上面的代码中,thenable对象的then方法执行后,对象pl的状态就变为resolved,
从而立即执行最后的 then 方法指定的回调函数,输出 42.
- 参数不是具有 then 方法的对象或根本不是对象
如果参数是一个原始值,或者是一个不具有 then 方法的对象,那么 Promise.resolve 方法返回一个新的 Promise 对象,状态为 Resolved。
var p = Promise.resolve ('Hello');
p.then(function (s){
console.log(s) //Hello
});
- 不带有任何参数
Promise.resolve 方法允许在调用时不带有参数, 而直接返回一个 Resolved 状态的 Promise 对象。
Promise.reject
Promise.reject(reason )方法也会返回一个新的 Promise 实例,状态为 Rejected。
var p = Promise.reject(‘出错了’);
//等同于
var p =new Promise((resolve, reject) =>reject(‘出错了’));p.then(null, function (s) {
console.log(s)
});
// 出错了