/**
* 回调函数
*
* 当 函数A 作为 实参 传递到 函数B 中
* 在 函数B 中通过 形参 调用 函数A
*
* 此时我们就可以说 函数A 是一个 回调函数
*/
/**
* 回调地狱
*
* 回调地狱的问题在于 书写完代码后, 不利于阅读与后续的维护
* 并不是说 回调地狱会导致我们的功能无法实现
*
*
* 所以为了解决回调地狱导致的代码不利于维护与阅读的问题, 出现了 promise
*
* promise 最重要的是解决了回调地狱, 而不是解决了 异步代码
*
* 异步代码一直会用, 不管你用不用 promise
*
*
* 利用 promise 书写的代码, 相对于 回调地狱, 更方便阅读与后续的维护
*/
/**
认识 promise
* 其实 promise 就可以理解为一个盒子, 这个盒子内部 可以帮我们承载一些 需要一定时间才能加载完毕的代码 (其实就是异步代码)
*
*
* 刚书写一个 promise 内部的状态为 等待/持续
* 将来promise 会转变状态, 要么转为成功
* 要么转为失败
*
* 而且 promise 的状态一经转换, 永远不会在改变
* 等待 -> 成功
* 等待 -> 失败
*
*
* 利用 ES6 新增的一个内置构造函数 帮助我们创建
*/
const p = new Promise(function (reslove, rejected) {
/**
* 当前回调函数 会接收两个形参
*
* 拼写并不重要
*
* 第一个形参: 他的值是一个函数, 你可以调用, 调用完毕后, 可以修改 当前 promise 的状态为成功
* 第二个形参: 他的值也是一个函数, 你也可以调用, 调用完毕后, 可以修改 当前 promise 的状态为失败
*
* 注意: 两个形参都是一个函数, 函数由 Promise 处理, 我们不需要处理, 我们只需要在合适的时机 调用即可
*/
rejected() // 如果你这样写, 会让页面有一个报错, 以后我们会处理, 目前不用在意
reslove() // 将当前的 promise 状态修改为 成功
})
console.log(p)
const p = new Promise(function (reslove, rejected) {
const time = Math.floor(Math.random() * 3000) + 2000
setTimeout(() => {
if (time > 30) {
rejected(time)
} else {
reslove(time)
}
}, time)
})
p.then((res) => {
console.log('当前的 promise 实例化对象 如果状态成功, 那么我会执行', res)
}).catch((err) => {
console.log('当前的 promise 实例化对象 如果状态失败, 那么我会执行', err)
})
链式调用
function fn() {
return new Promise(function (reslove, rejected) {
const time = Math.floor(Math.random() * 3000) + 2000
setTimeout(() => {
if (time > 3000000) {
rejected(time)
} else {
reslove(time)
}
}, time)
})
}
const p = fn()
p.then((res) => {
console.log('成功', res)
return fn()
}).then((res) => {
console.log('如果第二次成功, 那么我也会执行')
return fn()
}).then((res) => {
console.log('如果第三次成功, 那么我也会执行')
}).catch((err) => {
console.log('失败', err)
})
Promise.all()
function loadImage(src) {
return new Promise(function (resolve, reject) {
var img = new Image();
img.src = src;
img.onload = function () {
resolve(img);
};
});
}
var arr=[];
for(var i=2;i<6;i++){
arr.push(loadImage(`./img/img_${i}.jpeg`))
}
Promise.all(arr).then(function(list){
list.forEach(function(item){
console.log(item.src)
})
})
Promise.allSettled()
如果Promise中有一个没有执行resolve,执行的是reject,那么就不能使用Promise.all
需要使用allSettled
当多个Promise需要同时调用时,如果不确定是否都能成功,使用allSettled
Promise.allSettled();
function loadImage(src) {
return new Promise(function (resolve, reject) {
var img = new Image();
img.src = src;
img.onload = function () {
resolve(img);
};
img.onerror=function(){
reject();
}
});
}
var arr=[loadImage("./img/img_2.jpeg"),loadImage("./img/img_3.jpeg"),loadImage("./img/img_4.jpeg"),loadImage("./img/img_5.jpeg"),loadImage("./img/img_6.jpeg")];
Promise.all(arr).then(function(list){
console.log(list)
}).catch(function(){
console.log("aa")
})
Promise.allSettled(arr).then(function(list){
console.log(list);
})
Promise.race();
Promise.race();
var arr=[loadImage("./img/img_1.jpeg"),loadImage("./img/img_11.jpeg"),loadImage("./img/img_12.jpeg"),loadImage("./img/img_13.jpeg"),loadImage("./img/img_6.jpeg")];
Promise.race(arr).then(function(img){
console.log(img);
}).catch(function(list){
console.log(list)
})
Promise.any();
如果有一个成功的,就会把这个成功返回,如果都失败,打印全部失败
var arr=[loadImage("./img/img_2.jpeg"),loadImage("./img/img_3.jpeg"),loadImage("./img/img_4.jpeg"),loadImage("./img/img_5.jpeg"),loadImage("./img/img_6.jpeg")];
Promise.any(arr).then(function(img){
console.log(img);
})
var arr=[loadImage("./img/img_1.jpeg"),loadImage("./img/img_2.jpeg"),loadImage("./img/img_12.jpeg"),loadImage("./img/img_13.jpeg"),loadImage("./img/img_6.jpeg")];
Promise.any(arr).then(function(img){
console.log(img);
}).catch(function(list){
console.log(list) (全部失败才会执行,必须有失败状态的代码)
})
* async 和 await
*
* 必须要结合 promise 一起使用
*
* async 书写在一个函数的前边, 表明当前是一个异步函数
*
* await 书写在 promise 实例化对象前, 有一个作用是 只有当前这个对象的状态确定, 才会往下一行运行
*
*
*
* 注意:
* async await 只能处理 promise 的成功状态, 不能处理失败状态
*/
function post() {
return new Promise(function (reslove, rejected) {
const time = Math.floor(Math.random() * 3000) + 2000
setTimeout(() => {
if (time > 30) {
rejected(time)
} else {
reslove(time)
}
}, time)
})
}
async function fn () {
const res = await post()
console.log('第一次请求完毕的结果: ', res)
const res_2 = await post()
console.log('第二次请求完毕的结果: ', res_2)
console.log('一定是上边的异步代码运行完毕后, 才会执行我这个代码')
}
fn()
利用 async await 缺点更改
* async await 只能处理 promise 的成功状态, 不能处理失败状态
*/
function post() {
return new Promise(function (reslove, rejected) {
const time = Math.floor(Math.random() * 3000) + 2000
setTimeout(() => {
if (time > 3000) {
rejected('当前请求超时, 目前的时间是' + time)
} else {
reslove(time)
}
}, time)
})
}
async function fn() {
try {
const res = await post()
console.log('第一次请求完毕的结果: ', res)
} catch (err) {
console.log(err, '如果我执行, 说明 第一次请求出现报错')
}
try {
const res = await post()
console.log('第二次请求完毕的结果: ', res)
} catch (err) {
console.log(err, '如果我执行, 说明 第二次请求出现报错')
}
}
fn()
async await 缺点优化2
function post() {
return new Promise(function (reslove, rejected) {
const time = Math.floor(Math.random() * 3000) + 2000
setTimeout(() => {
if (time > 3000) {
reslove({
code: 0,
data: '当前请求超时, 目前的时间是' + time
})
} else {
reslove({
code: 1,
data: time
})
}
}, time)
})
}
async function fn() {
const res = await post()
console.log('请求完毕的结果: ', res)
if (res.code === 0) {
console.log('当前的请求失败了, 做一点措施, 并且不要再往下进行了')
return alert(res.data)
}
console.log('当前请求成功, 拿到数据后我们开始渲染页面')
}
fn()