在 JavaScript 的世界中,所有代码都是单线程执行的。
由于这个“ 缺陷 ” ,导致 JavaScript 的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现。一旦有一连串的 ajax 请求 a,b,c,d... 后面的请求依赖前面的请求结果,就需要层层嵌套。
这种缩进和层层嵌套的方式,非常容易造成上下文代码混乱,我们不得不非常小心翼翼处理内层函数与外层函数的数据,一旦内层函数使用了上层函数的变量,这种混乱程度就会加剧......
总之,这种`层叠上下文 ` 的层层嵌套方式,着实增加了神经的紧张程度。
案例:用户登录,并展示该用户的各科成绩。在页面发送两次请求:
1. 查询用户,查询成功说明可以登录
2. 查询用户成功,查询科目
3. 根据科目的查询结果,获取去成绩
分析:此时后台应该提供三个接口,一个提供用户查询接口,一个提供科目的接口,一个提供各科成绩的接口,为了渲染方便,最好响应 json 数据。在这里就不编写后台接口了,而是提供三个 json 文件,直接提供 json 数据,模拟后台接口:
// 回调函数嵌套的噩梦:层层嵌套。
$.ajax({
url: "mock/user.json",
success(data) {
console.log("查询用户:", data);
$.ajax({
url: `mock/user_corse_${data.id}.json`,
success(data) {
console.log("查询到课程:", data);
$.ajax({
url: `mock/corse_score_${data.id}.json`,
success(data) {
console.log("查询到分数:", data);
}, error(error) {
console.log("出现异常了:" + error);
}
});
}, error(error) {
console.log("出现异常了:" + error);
}
});
}, error(error) {
console.log("出现异常了:" + error);
}
});
一、 Promise 语法
const promise = new Promise(function (resolve, reject) {
// 执行异步操作
if (/* 异步操作成功 */) {
resolve(value); // 调用 resolve,代表 Promise 将返回成功的结果
} else {
reject(error); // 调用 reject,代表 Promise 会返回失败结果
}
});
二、 处理异步结果
如果想等待异步执行完成后,再做一些事情,可通过 Promise 的 then 方法实现,而 catch 可以处理 promise 执行失败的事件
promise.then(function (value) {
// 异步执行成功后的回调
}).catch(function (error) {
// 异步执行失败后的回调
})
三、 Promise 优化
先把 Promise 封装成一个通用的 get 方法
let get = function (url, data) { // 实际开发中会单独放到 common.js 中
return new Promise((resolve, reject) => {
$.ajax({
url: url,
type: "GET",
data: data,
success(result) {
resolve(result);
},
error(error) {
reject(error);
}
});
})
}
再使用 promise 封装成 get 方法
// 使用封装的 get 方法,实现查询分数
get("mock/user.json").then((result) => {
console.log("查询用户:", result);
return get(`mock/user_corse_${result.id}.json`);
}).then((result) => {
console.log("查询到课程:", result);
return get(`mock/corse_score_${result.id}.json`)
}).then((result) => {
console.log("查询到分数:", result);
}).catch(() => {
console.log("出现异常了:" + error);
});