1.什么是回调地域?
回调地狱的概念:回调函数里面嵌套回调函数。(问题解决慢慢看)
//需求: 向某位女生发送短信
/**
* @description: name:女神名字 onFulffiled成功后的回调 onRejected失败后的回调
* @return {*}
* @author: 前端33号笔记员
*/
function sendMessage(name, onFulffiled, onRejected) {
console.log('我:' + name + '我喜欢你');
setTimeout(() => {
if (Math.random() <= 0.1) {
// 成功
onFulffiled('女神:我也喜欢你!')
} else {
onRejected('女神:我老公不同意!')
}
}, 1000);
}
// 只追小美
sendMessage('小美', (message) => {
console.log('成功', message);
}, (message) => {
console.log('失败', message);
})
/**
* @description: 需求,有4位女生,小美,小蓝,小红,小花,一个一个追,不同意就追下一个!
* @return {*} 下面代码就是回调地域
* @author: 前端33号笔记员
*/
sendMessage('小美', (message) => {
console.log('成功', message);
}, (message) => {
console.log('失败', message);
// 追小蓝
sendMessage('小蓝', (message) => {
console.log('成功', message);
}, (message) => {
console.log('失败', message);
// 追小红
sendMessage('小红', (message) => {
console.log('成功', message);
}, (message) => {
console.log('失败', message);
// 追小花
sendMessage('小花', (message) => {
console.log('成功', message);
}, (message) => {
console.log('失败', message);
})
})
})
})
2.Promise 规范
1. 所有的异步场景,都可以看做是一个异步任务,每个异步任务,在JS中应该表现为一个对象,该对象被称为Promise对象,也叫任务对象
2.每个任务对象,都应该有两个阶段、三个状态
未决阶段就是没有结果的阶段(例如:发送账号密码到服务器,还没通知是否正确的阶段)
已决阶段就是有结果的阶段(例如:通知账号密码正确或失败)
根据常理,他们之间存在以下步骤:
1.任务总是从未决阶段变到已决阶段,无法逆行
2.任务总是从挂起状态变到完成或失败状态,无法逆行
3.任务一旦完成或失败,状态就固定下来了,永远无法改变
3.挂起到完成,称之为 resolve;挂起到失败,称之为 reject;任务完成时,可能有一个相关数据,任务失败时,可能有一个失败原因
4.可以针对任务进行后续处理,针对完成状态的后续处理称之为onFulfilled,针对失败的后续处理称之为onRejected
3.Promise API (es6提供) 基础使用
// 创建了一个异步任务(任务总是从未决阶段变到已决阶段,无法逆行),所以状态是pending
const pro = new Promise((resolve, reject) => {
console.log('百米赛跑');
const duration = Math.floor(Math.random() * 5000)
setTimeout(() => {
if (Math.random() < 0.5) {
resolve(duration)
} else {
reject('脚伤了')
}
}, duration)
})
pro.then((data) => {
console.log("跑了", data, '秒');
}, (reason) => {
console.log('不好意思', reason);
})
改造回掉地狱问题 第一步:
function sendMessage(name) {
return new Promise((resolve, reject) => {
console.log('我:' + name + '我喜欢你');
setTimeout(() => {
if (Math.random() <= 0.1) {
// 成功
resolve('女神:我也喜欢你!')
} else {
reject('女神:我老公不同意!')
}
}, 1000);
})
}
// 只追小美
sendMessage('小美').then((data) => {
console.log('成功', data);
}, (reason) => {
console.log('失败', reason);
})
4.Promise 链式调用
1.then方法必定会返回一个新的promise
2.新任务状态取决于后续处理
1.若没有相关的后续处理,新任务的状态和前任务保持一致,数据为前任务的数据
const pro = new Promise((resolve, reject) => { console.log(1); resolve(123) //成功了 数据123 }) // 对pro只进行了 失败处理 const pro2 = pro.catch(() => { console.log(2); }) setTimeout(() => { console.log(pro2);//那么新任务状态和前任务状态一样,数据也是123 }, 1000)
2.若有后续处理,但是还未执行,新任务挂起
const pro = new Promise((resolve, reject) => { setTimeout(() => { reject(123) //2秒之后失败 }, 2000) }) // 对pro只进行了 失败处理 const pro2 = pro.catch(() => { console.log(2); }) setTimeout(() => { console.log(pro2);//一秒输出 pro2未执行所以挂起状态 }, 1000)
3.若后续处理执行了,则根据后续处理的情况确定新任务状态
- 后续处理无错,新任务状态完成,数据为后续处理的返回值
- 若后续处理执行有错,新任务状态为失败,数据为异常对象
- 后续执行后返回的是一个任务对象,新任务的状态和数据与该任务对象一致
const pro = new Promise((resolve, reject) => { resolve()//成功了, }) // 对pro只进行了 成功 const pro2 = pro.then(() => { console.log(2); // return 100 //没错误 状态为完成 返回值100 // throw new Error('出错了')//有错误状态为失败,数据为异常对象 return new Promise(() => {}) //返回一个任务对象,在未决阶段,所以pro2 状态pending }) setTimeout(() => { console.log(pro2); }, 1000)
改造回掉地狱问题(后面继续优化):
function sendMessage(name) {
return new Promise((resolve, reject) => {
console.log('我:' + name + '我喜欢你');
setTimeout(() => {
if (Math.random() <= 0.1) {
// 成功
resolve('女神:我也喜欢你!')
} else {
reject('女神:我老公不同意!')
}
}, 1000);
})
}
// 小美,小蓝,小红,小花,
sendMessage('小美').catch((reason) => {
console.log(reason);
return sendMessage('小蓝')
})
.catch((reason) => {
console.log(reason);
return sendMessage('小红')
})
.catch((reason) => {
console.log(reason);
return sendMessage('小花')
})
.then((reply) => {
console.log(reply);
}, (reply) => {
console.log(reply);
})
5.async与await
async关键字用于修饰函数,被他修饰的函数,一定返回Promise
await 关键字表示等待某个Promise完成,它必须用于async函数中
await作用是等待一个异步的成功结果,并且会阻塞代码在这个作用域await之后的代码,会将他们加入微任务。async是声明一个异步函数。相当于promise的简写。一般搭配await使用。async await优点是可以优雅编写异步操作。缺点是会阻塞
解决回调地域的问题:
async function sendMessage(name) {
// 若返回的是Promise,则方法得到的Promise状态一致(也就是说 这个函数的async可以省略)
return new Promise((resolve, reject) => {
console.log('我:' + name + '我喜欢你');
setTimeout(() => {
if (Math.random() <= 0.3) {
// 成功
resolve('女神:我也喜欢你!')
} else {
reject('女神:我老公不同意!')
}
}, 1000);
})
}
let beautyGirls = ['小美', '小蓝', '小红', '小花'];
(async () => {
for (const name of beautyGirls) {
try {
const reply = await sendMessage(name)
// 表白成功 跳出循环
console.log(reply);
break;
} catch (error) {
// 表白失败
console.log(error);
}
}
})()