Promise 是什么
- 认识 Promise
Promise 是异步操作的一种解决方案 - 什么时候使用 Promise
Promise 一般用来解决层层嵌套的回调函数(回调地狱 callback hell)的问题
Promise 的基本用法
- 实例化构造函数生成实例对象
const p = new Promise(() => {});
- Promise 的三种状态
Promise有3种状态,一开始是 pending(未完成),执行 resolve, 变成 fulfilled(resolve),已成功,执行 reject,变成 rejected,已失败
Promise 的状态一旦变化,就不会再改变了
// pending -> fulfilled
resolve();
// pending -> rejected
reject();
- then 方法
p.then(() => {
console.log('success');
}, () => {
console.log('error');
});
- resolve 和 reject 函数的参数
const p = new Promise((resolve, reject) => {
resolve({username: 'Tom'});
})
p.then((data) => {
console.log(data);
}, (err) => {
console.log(err);
})
then()
- 什么时候执行
pending -> fulfilled 时,执行 then 的第一个回调函数
pending -> rejected 时,执行 then 的第二个回调函数 - 执行后的返回值
then 方法执行后返回一个新的 Promise 对象
catch()
- 有什么用
catch 专门用来处理 rejected 状态
catch 本质上是 then 的特例
then(null, err => {})
- 基本用法
new Promise((resolve, reject) => {
reject('reason');
}).then(data => {
console.log(data);
}).catch(err => {
console.log(err);
});
catch() 可以捕获它前面的错误
一般总是建议, Promise 对象后面要跟 catch 方法,这样可以处理 Promise 内部发生的错误
finally()
- 什么时候执行
当 Promise 状态发生变化时,不论如何变化都会执行,不变化不执行 - 本质
finally() 本质上是 then() 的特例
Promise.resolve() 和 Promise.reject()
- Promise.resolve()
是成功状态 Promise 的一种简写形式
new Promise(resolve => resolve('foo'));
// 简写
Promise.resolve('foo');
参数
(1) 一般参数
Promise.resolve('foo').then(data => {
console.log(data);
})
(2) Promise
当 Promise.resolve() 接收的是 Promise 对象时,直接返回这个 Promise 对象,什么都不做
const p1 = new Promise(resolve => {
setTimeout(resolve, 1000, '我执行了');
// 上面等同于
// setTimeout(() => {
// resolve('我执行了');
// }, 1000);
});
Promise.resolve(p1).then(data => {
console.log(data);
})
// 等价于
p1.then(data => {
console.log(data);
})
console.log(Promise.resolve(p1) === p1);
当 resolve 函数接收的是 Promise 对象时,后面的 then 会根据传递的 Promise 对象的状态变化决定执行哪一个回调
new Promise(resolve => resolve(p1)).then(data => {
console.log(data);
});
(3) 具有 then 方法的对象
- Promise.reject()
失败状态 Promise 的一种简写形式
new Promise((resolve, reject) => {
reject('reason');
});
// 等价于
Promise.reject('reason');
参数
不管什么参数,都会原封不动地向后传递,作为后续方法的参数
const p1 = new Promise(resolve => {
setTimeout(resolve, 1000, '我执行了');
})
Promise.reject(p1).catch(err => console.log(err));
Promise.all()
- 有什么用
Promise.all() 关注多个 Promise 对象的状态变化
传入多个 Promise 实例, 包装成一个新的 Promise 实例返回 - 基本用法
const delay = ms => {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms, '我执行了');
});
}
const p1 = delay(1000).then(() => {
console.log('p1 完成了');
return 'p1';
})
const p2 = delay(2000).then(() => {
console.log('p2 完成了');
return 'p2';
// return Promise.reject('err');
});
const p = Promise.all([p1,p2]);
p.then(
data => {
console.log(data);
},
err => {
console.log(err);
}
)
Promise.race()
Promise.race() 的状态取决于第一个完成的 Promise 实例对象,如果第一个完成的成功了,那最终的就成功;如果第一个完成的失败了,那最终的就失败
const racePromise = Promise.race([p1, p2]);
racePromise.then(
data => {
console.log(data);
},
err => {
console.log(err);
}
);
Promise.allSettled()
Promise.allSettled() 的状态与传入的 Promise 状态无关,永远都是成功的,它只会忠实的记录下各个Promise 的表现
const allSettledPromise = Promise.allSettled([p1, p2]);
allSettledPromise.then(
data => {
console.log(data);
}
);
Promise 的注意事项
- resolve 或 reject 函数执行后的代码
推荐在调用 resolve 或 reject 函数的时候加上 return,不再执行它们后面的代码
new Promise((resolve, reject) => {
return resolve(123);
// return reject('reason');
});
- Promise.all/race/allSettled 的参数问题
参数如果不是 Promise 数组,会将不是 Promise 的数组元素转变成 Promise 对象
Promise.all([1,2,3]).then(datas => {
console.log(datas);
});
// 等价于
Promise.all([
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3)
]).then(datas => {
console.log(datas);
});
不只是数组,任何可遍历的都可以作为参数
数组、字符串、Set、Map、arguments、NodeList
Promise.all(new Set([1, 2, 3])).then(data => console.log(data))
- Promise.all/race/allSettled 的错误处理
错误既可以单独处理,也可以统一处理
一旦被处理,就不会在其他地方再处理一遍
const delay = ms => {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms, 'error');
});
}
const p1 = delay(1000).then(() => {
console.log('p1 完成了');
return 'p1';
})
// 第一种情况
.catch(err => console.log(err));
const p2 = delay(2000).then(() => {
console.log('p2 完成了');
return 'p2';
// return Promise.reject('err');
})
// 第一种情况
.catch(err => console.log(err));
const p = Promise.all([p1,p2]);
p.then(
data => {
console.log(data);
}
)
// 第二种情况
.catch(err => console.log(err));
Promise 的应用
<body>
<img id="img" src="//img1.mukewang.com/604ec1a30001d21b17920764.jpg" alt="">
<script>
const loadImageAsync = url => {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = function () {
resolve(img);
}
img.onerror = function () {
reject(new Error(`Could not load image at ${url}`));
}
img.src = url;
})
}
const imgDom = document.getElementById('img');
loadImageAsync('//img3.mukewang.com/604587df000158fd17920764.jpg').then(img => {
imgDom.src = img.src
});
</script>
</body>