前言
本文以学习为目的分享回调地狱的几种简单的解决方式,处理较为粗糙
回调地狱
首先我们来看一个例子,这个例子不断地嵌套,不断地缩进,使代码难以阅读、难以维护。
const xhr1 = new XMLHttpRequest();
xhr1.open("GET", 'http://127.0.0.1:5500/index.html');
xhr1.send();
xhr1.onreadystatechange = function () {
if (xhr1.readyState === 4) {
if (xhr1.status >= 200 && xhr1.status < 300) {
console.log(`success1: ${xhr1.response}`)
const xhr2 = new XMLHttpRequest();
xhr2.open("GET", 'http://127.0.0.1:5500/index2.html');
xhr2.send();
xhr2.onreadystatechange = function () {
if (xhr2.readyState === 4) {
if (xhr2.status >= 200 && xhr2.status < 300) {
console.log(`success2: ${xhr2.response}`)
const xhr3 = new XMLHttpRequest();
xhr3.open("GET", 'http://127.0.0.1:5500/index3.html');
xhr3.send();
xhr3.onreadystatechange = function () {
if (xhr3.readyState === 4) {
if (xhr3.status >= 200 && xhr3.status < 300) {
console.log(`success3: ${xhr3.response}`)
} else {
console.log(`error3: ${xhr3.status}`);
}
}
};
} else {
console.log(`error2: ${xhr2.status}`);
}
}
};
} else {
console.log(`error1: ${xhr1.status}`);
}
}
};
通过抽取函数解决回调问题
我们可以抽取函数来解决回调问题,我们将上面的代码进行优化
function request1 () {
const xhr = new XMLHttpRequest();
xhr.open("GET", 'http://127.0.0.1:5500/index.html');
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
console.log(`success1: ${xhr.response}`)
request2(xhr.response);
} else {
console.log(`error1: ${xhr.status}`);
}
}
};
}
function request2 (response) {
const xhr = new XMLHttpRequest();
xhr.open("GET", 'http://127.0.0.1:5500/index2.html');
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
console.log(`success1: ${xhr.response}`)
request3(xhr.response);
} else {
console.log(`error1: ${xhr.status}`);
}
}
};
}
function request3 (response) {
const xhr = new XMLHttpRequest();
xhr.open("GET", 'http://127.0.0.1:5500/index3.html');
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
console.log(`success1: ${xhr.response}`)
} else {
console.log(`error1: ${xhr.status}`);
}
}
};
}
request1();
通过 Promise
解决回调地狱
基础用法
在 MDN 中定义:Promise
对象用于表示一个异步操作的最终完成 (或失败)及其结果值。
Promise a+规范及其翻译版
简单来讲就是我们通过 Promise
类实例化 promise
对象可进行异步操作,其共有三个状态,初始为 PENDING
, 成功则通过 resolve
将其更改为 RESOLVED
,并自动调用 then
,失败则通过 reject
更改为 REJECTED
,并自动调用 catch
,状态一经改变则不会再更改
注意,在实例化 promise
时的回调函数本身是同步的,只有 then
与 catch
中的逻辑是异步的
例子
const p = new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
// 我使用了 Live Server 插件,这里请求的本文档
xhr.open("GET", "http://127.0.0.1:5500/index.html");
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response);
} else {
reject(xhr.status);
}
}
};
});
p.then((res) => {
console.log('then: ' + res);
}).catch((err) => {
console.log('catch: ' + err);
});
链式调用
因为 then
和 catch
返回的是 promise
对象,所以我们可以进行链式调用,这样我们就轻松解决了回调地狱的问题。
// 重复代码过多,这里写了个函数来生成 Promise 对象
function createPromise(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
console.log(`resolve:${url}`)
resolve(xhr.response);
} else {
console.log(`reject:${url}`)
reject(xhr.status);
}
}
};
})
}
const p1 = createPromise("http://127.0.0.1:5500/index.html")
const p2 = createPromise("http://127.0.0.1:5500/index2.html")
const p3 = createPromise("http://127.0.0.1:5500/index3.html")
const await1 = p1.then((res) => {
console.log('then1: ' + res);
return p2;
}).then((res) => {
console.log('then2: ' + res);
return p3;
}).then((res) => {
console.log('then3: ' + res);
}).catch((err) => {
console.log('catch: ' + err);
})
通过 sync
和 await
解决回调地狱
async
和 await
时 promise
的语法糖
async
用于声明一个 function
是异步的,而 async
函数的返回值是一个 promise
对象
await
必须在 async
函数中使用,会阻塞后面的异步语句,直到返回表达式结果,而后面如果是 promise
则会等待其变为 resolved
状态,并以其返回值作为运算结果。
通过 async
和 await
我们将异步变成了同步,但是同时也有一个问题, async
的返回值是一个 promise
对象,所以我们获取 async
函数的返回值时也需要使用 await
运算符,这就造成了 async
的地狱。
async function asyncFun1 () {
return 1;
}
console.log(asyncFun1()) // Promise {<fulfilled>: 1}
async function asyncFun2 () {
console.log('asyncFun2: ' + 1)
try {
const awaitResult1 = await p1;
console.log('asyncFun2: ' + awaitResult1)
} catch (e) {
console.log('asyncFun2: ' + e);
}
// 字符串相当于状态为 RESOLVED 的 promise 对象
const awaitResult2 = await 'Hello World';
console.log('asyncFun2: ' + awaitResult2)
console.log('asyncFun2: ' + 2)
return awaitResult2;
}
async function callAsyncFun () {
const result = await asyncFun2();
console.log('callAsyncFun: ' + result);
}
callAsyncFun()
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!