promise 面试必问问题,我项目里又不经常写promise,so 每次问都有些细节不清楚,觉得自己写写,因为阮一峰老师的es6写的很详细了,所以此文章只是笔记
Promise 特性
特点
- 三个状态 ,pending(进行中),fulfilled(pending—>resolved),rejected(pending—>rejected)
- 当状态改变后,就不会再改变
缺点
- 一旦创建就会立即执行,无法取消
- 不设置catch回调,Promise内部抛出错误,不会反应到外部。(即js代码继续执行,不会终止)
- 当处于pending状态时,无法得知目前进展到哪一阶段
用法
// 对象Promise 接收两个参数且都是函数
// resolve 异步成功时调用
// reject 异步失败时调用
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
通过then方法指定resolved状态和rejected状态的回调函数。接收的参数是resolve或者reject传来的参数
promise.then(function(value) {
// success
}, function(error) {
// failure
});
promise.then(value=>{},error=>{});
当resolve返回的是一个Promise
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)) // Error: fail
当p2返回的是一个promise对象,这时候,p2的状态由p1决定,then语句针对p1
Promise.prototype.then()
前面说了,then方法接收两个参数,第一个是resolved状态的回调函数,第二个是rejected状态的回调函数
then方法返回的是一个_新的Promise实例_,所以可以采用链式写法。
<script>
const p1 = new Promise(function(resolve,reject){
resolve('成功了')
})
const result = p1.then(value=>console.log(value)).then(value=> console.log(value))
console.log(result)
</script>
运行结果
可以看到,真的是返回的promise对象哎,而且链式调用,value最后是undefined
再看一个
const p1 = new Promise(function(resolve,reject){
resolve('p1成功了')
})
const p2 = new Promise(function(resolve,reject){
resolve('p2成功了')
})
const res = p1.then(value=>{
console.log(value);return p2
}).then(value=>{ console.log(value);
},
error=>console.log('error',error))
console.log(res)
可以想想返回什么
第一个then返回的是一个promise对象p2,之后的第二个then会等待p2的状态发生变化,成功走成功的回调,失败走失败回调
最后的res返回的是新的promise,不是p1也不是p2
Promise.prototype.catch()
catch 用于指定发生错误时的回调函数
p1.then(function(posts) {
// ...
}).catch(function(error) {
// 处理 getJSON 和 前一个回调函数运行时发生的错误
console.log('发生错误!', error);
});
这个 等我遇到具体事情的时候再补充吧
说明的一点是,catch可以捕获前面所有then的异常,中间有异常 ,后边的then不会再执行了
const p1 = new Promise(function(resolve,reject){
resolve('p1成功了')
})
const p2 = new Promise(function(resolve,reject){
throw new Error('test');
})
const res = p1.then(value=>p2).then(
value=> console.log('value',value)).catch(error=>console.log(error)
)
console.log(res)
// Promise
// Error: test
如果promise内部出现错误,js代码不会停止执行,不会影响到后面代码的执行
Promise.prototype.finally()
一句话,不管promise状态如何,都会执行finally
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
Promise.prototype.all()
用法
const p = Promise.all([p1, p2, p3]);
这个也不难理解,我的理解就是同时执行多个异步,而且返回一个新的Promise对象,只有p1,p2,p3状态全部变为fulfilled时,p才是fulilled,其中一个是rejected,状态就是rejected
需要注意的点
const p1 = new Promise((resolve, reject) => {
resolve('hello');
})
.then(result => result)
.catch(e => e);
const p2 = new Promise((resolve, reject) => {
throw new Error('报错了');
})
.then(result => result)
.catch(e => e);
Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// ["hello", Error: 报错了]
因为p2有自己的catch方法,catch返回新的promise对象,新的promise对象的状态是resolved,所以all方法不会走catch。
Promise.race()
const p = Promise.race([p1, p2, p3]);
这个方法也简单,p1,p2,p3有一个率先改变状态(不管fulfilled还是rejected),p的状态跟着改变,将率先改变的那个promise实例返回
应用
图片懒加载
function loadImageAsync(url) {
return new Promise(function(resolve, reject) {
const image = new Image();
image.onload = function() {
resolve(image);
};
image.onerror = function() {
reject(new Error('Could not load image at ' + url));
};
image.src = url;
});
}
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("Accept", "application/json");
client.send();
});
return promise;
};
getJSON("/posts.json").then(function(json) {
console.log('Contents: ' + json);
}, function(error) {
console.error('出错了', error);
});