![在这里插入图片描述](https://img-blog.csdnimg.cn/1422ea4fac42431a973813d5c38afe20.png)
JavaScript是单线程的,在代码的执行过程中,碰见异步代码,先单独放置另一队列,原有队列继续执行(不被阻塞)。
引入
如果我们需要依次的执行多个异步操作,我们的代码可能就要写成这样,这个我们就叫作 回调地狱(Callback Hell)。
Promise就是为了解决这个问题。
// 异步操作进行层层嵌套,使得依次执行
setTimeout(() => {
console.log("异步1要做的事情");
setTimeout(() => {
console.log("异步2要做的事情");
setTimeout(() => {
console.log("异步3要做的事情");
},2000)
},1000)
},3000)
console.log("虽然我在后面,但是我不会等前面的异步操作");
console.log("666");
console.log("你说呢");
// 程序会依次执行 异步1 -> 异步2 -> 异步3
// 3s -> 1s -> 2s
执行结果:
Promise
为什么出现 Promise
遇到一个请求要依赖前一个请求的结果,如果多个层层回调函数的嵌套叫做“回调地域”,代码不美观而且不易于维护。
Promise的优点在于可以用链式结构将多个异步操作串联起来
Promise 对象有三个状态:pending、fulfilled 和 rejected。
resolve
:在异步操作成功时调用,将异步操作的结果,作为参数传递出去,并使Promise状态变为fulfilled。
reject
:在异步操作失败时调用,将异步操作报的错误,作为参数传递出去,并使Promise状态变为 rejected。
// 链式调用, 顺序执行异步
axios.get(url)
.then()
.then()
.catch()
.finally();
const promise = new Promise((resolve,reject) => {
// 这里做异步任务 axios 等 暂且用 setTimeout 模拟
//-------------
setTimeout(function(){
let data = {retCode:0,msg:'jkl'};
if(data.retCode == 0){
// 异步操作成功
resolve(data); // pending -> fullfilled
console.log("成功执行");
}else{
// 异步操作失败
reject({retCode:-1,msg:'netWork error'}); // pending -> rejected
console.log("执行失败");
}
},1000);
//-------------
console.log("fewfewgwegweg");
});
这个Promise对象是会立即执行的。
then方法和catch方法都是异步代码
当Promise对象中是resolve时,外面可以没有then去处理。
当Promise对象中是reject时,外面要么then要写第二个函数参数去处理,要么使用链式catch的方式去处理,反正必须要处理。
async&await
async关键字,是声明异步函数,返回值是promise对象,如果返回的不是promise,会自动用Promise.resolve()包装。
await 后 是一个 Promise对象。
const fun1 = function(){
return new Promise((resolve,reject) => {
// 异步操作 1
resolve("data1....")
});
};
const fun2 = function(){
return new Promise((resolve,reject) => {
// 异步操作 2
resolve("data2....")
});
};
const asyncFun = async function(){
let res1 = await fun1();
let res2 = await fun2();
console.log("hello");
console.log(res1); // data1....
console.log(res2); // data2....
}
asyncFun();
console.log("sffsdgd");
await等后面的promise对象执行完毕,然后拿到resolve()
的值并进行返回,之后继续向下执行。
如果 Promise中没有 resolve,就会引起 asyncFun
函数内部执行的阻塞,await一直在等待,只打印 sffsdgd
。
但是对于 asyncFun
函数 外部的代码来说没有影响。
Attention:
await 命令后面的 Promise 对象,运行结果可能是 rejected,所以最好把 await 命令放在 try…catch 代码块中。
async function myFunction() {
try {
await somethingThatReturnsAPromise();
} catch (err) {
console.log(err);
}
}
JS异步顺序调用
await用法
Promise
Promise详解
Promise处理多次 Ajax 请求
function queryData(url) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState != 4) return;
if (xhr.readyState == 4 && xhr.status == 200) {
// 处理正常情况
// xhr.responseText 是从接口拿到的数据
resolve(xhr.responseText);
} else {
// 处理异常情况
reject('接口请求失败');
}
};
xhr.responseType = 'json'; // 设置返回的数据类型
xhr.open('get', url);
xhr.send(null); // 请求接口
});
}
// 发送多个ajax请求并且保证顺序
queryData('http://localhost:3000/api1')
.then(
data1 => {
console.log(JSON.stringify(data1));
// 请求完接口1后,继续请求接口2
return queryData('http://localhost:3000/api2');
}
)
.then(
data2 => {
console.log(JSON.stringify(data2));
// 请求完接口2后,继续请求接口3
return queryData('http://localhost:3000/api3');
}
)
.then(
data3 => {
// 获取接口3返回的数据
console.log(JSON.stringify(data3));
}
);
then方法
return 后面的返回值,有两种情况:
情况1:返回 Promise 实例对象。返回的该实例对象会调用下一个 then。
情况2:返回普通值。返回的普通值会直接传递给下一个then,通过 then 参数中函数的参数接收该值。
.then(data2 => {
console.log(JSON.stringify(data2));
// 返回普通值
return 'qianguyihao';
})
/*
这里会产生一个新的 默认的 promise实例,来调用这里的then,确保可以继续进行链式操作。
*/
.then(data3 => {
// 这里的 data3 接收的是 普通值 'qianguyihao'
console.log(data3);
});