说起他们的区别我们首先要知道,js中什么是同步执行和异步执行?
在js中,通常情况下代码都是自上而下同步执行的,在同步执行代码时,如果有一段代码执行的速度特别慢,会造成程序卡顿的后果。再者常见的就是向服务器发送请求,需要花费时间接受服务器返回的响应结果,对数据进行处理,因为网速和加载速度慢的原因,会带来不好的用户体验。从而引入异步处理,使代码无需等待,继续处理其他代码,直到其他程序处理完毕,js再继续之前的工作
js中的一部主要是通过事件和回调函数实现的,但是这种方式会存在一些问题
//为了方便演示,页面创建button元素,使用原生的dom来发送请求,后面会用到
<button>点我发送请求</button>
document.querySelector("button").addEventListener("click", function () {});
1.不能通过return设置返回值,
function fn1() {
setTimeout(() => {
console.log(1);
// 以异步的方式,来给函数设置返回值
return 'hello'
}, 0);
console.log(2);
}
let result = fn1();
console.log(result);
拿不到返回值,这时可以通过回调函数解决问题
function fn1(cb) {
setTimeout(() => {
console.log(1);
// 以异步的方式,来给函数设置返回值
cb("hello");
}, 0);
console.log(2);
}
fn1((result) => {
console.log(result);
});
2.当异步过于复杂时,多个函数相互依赖时,就会造成回调地狱问题,增加代码复杂度,难以维护
function fn1(n, cb) {
setTimeout(() => {
return cb(n + 1);
}, 0);
}
function fn2(n, cb) {
setTimeout(() => {
return cb(n + 2);
}, 0);
}
function fn3(n, cb) {
setTimeout(() => {
return cb(n + 3);
}, 0);
}
function fn4(n, cb) {
setTimeout(() => {
return cb(n + 4);
}, 0);
}
fn1(10, (n) => {
fn2(n, (n) => {
fn3(n, (n) => {
fn4(n, (n) => {
console.log(n);//20
});
});
});
});
Ajax作为js中早期的发送异步请求的方式,翻译过来就是异步的JS和XML的意思,目前用的较少
document.querySelector("button").addEventListener("click", function () {
//1. 创建核⼼对象
var xhr = new XMLHttpRequest();
//2.通过核⼼对象⽅法给当前的对象提供访问⽅式和URL路径
xhr.open("get", "https://api.q6q.cc/blog");
//3.发送当前的请求⾄指定的URL
xhr.send();
//4.异步回调接收返回值并处理
xhr.onreadystatechange = function () {
//xhr.readyState==4代表XMLHttpRequest对象读取服务器的响应结束
//xhr.status==200响应成功
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.response);
console.log(JSON.parse(xhr.response));
}
};
console.log("我是一个波浪线~~~~~~~");
});
拿到返回结果,并且不影响其他代码的正常运行
补充:readyState有五种可能的值:
为了解决一部带来的问题,js推出新对象promise,专门用来存储异步代码对象,他可以确保异步代码的执行和返回结果
Promise的回调函数可以指定两个参数
resolve :在代码正常执行时,来设置返回值的
reject(可选) :在代码执行出错时,用来设置错误信息,反正我不用,用catch更优雅
当Promise中的代码正常执行时,会通过then方法回调来返回结果,直接抛出异常非正常执行则不会执行then
const myPromise = new Promise((resolve, reject) => {
// throw new Error("报错了");
setTimeout(() => {
console.log("异步函数");
//设置返回值
resolve("hello");
}, 1000);
});
// 获取myPromise中的返回值
myPromise
.then((result) => console.log(result))
.catch((e) => console.log(e));
这时解决上述回调地狱问题就可以直接链式调用
function fn1(n) {
return new Promise((resolve) => {
resolve(n + 1);
});
}
function fn2(n) {
return new Promise((resolve) => {
resolve(n + 2);
});
}
function fn3(n) {
return new Promise((resolve) => {
resolve(n + 3);
});
}
function fn4(n) {
return new Promise((resolve) => {
resolve(n + 4);
});
}
fn1(10)
.then((n) => fn2(n))
.then((n) => fn3(n))
.then((n) => fn4(n))
.then((n) => console.log(n))//20
.catch((e) => console.log(e));
fetch是官方的发送异步请求的工具,基于promise,相较于ajax更加方便
document.querySelector("button").addEventListener("click", function () {
fetch("https://api.q6q.cc/blog")
.then((resp) => resp.json())
.then((data) => console.log(data));
});
非官方的发送异步请求的库,基于promise,需要自己引入,可以更好地封装,使用范围广,更方便
document.querySelector("button").addEventListener("click", function () {
axios
.get("https://api.q6q.cc/blog")
.then((res) => {
console.log(res.data);
})
.catch((e) => console.log(e));
});
技术 | 原生 | 作用 |
---|---|---|
Ajax | √ | 发送请求,太老 |
Promise | √ | 专门为异步提供支持 |
Fetch | √ | 官方库,基于Promise,可以直接用来发送请求 |
Axios | × | 第三方,基于Promise,需要引入,能更好的封装 |