回调地狱
- 在异步的程序中想要拿到 异步程序执行的结果,必须使用回调函数
- 当异步操作越来越多,那么回调函数嵌套就会越来越深
- 当回调函数嵌套过多的这个请就叫做回调地狱
- 代码的执行顺序会非常不直观,不利于维护。
- 案例:
- 有三个接口 data1.php data2.php data3.php
- data2.php 需要 data1.php 中返回的数据当参数
- data3.php 需要 data2.php 中返回的数据当参数
<script>
// data1请求出来的结果 当成data2的请求参数
// data2 请求出来结果 当成 data3的请求参数
ajax({
url: "./data1.php",
success: function (res) {
ajax({
url: "./data2.php",
data: { num: res },
success: function (res2) {
ajax({
url: "./data3.php",
data: { num: res2 },
success: function (res3) {
console.log(res3);
},
});
},
});
},
});
</script>
- data1.php
<?php
echo 10;
?>
- data2.php
<?php
$n1 = $_GET['num'];
echo $n1*2;
?>
- data3.php
<?php
$num = $_GET['num'];
echo $num+10;
?>
promise介绍
-
promise:承诺
-
promise是ES6新增的一个语法
-
当你需要执行一个异步程序的时候,你可以把这个事情交给promise
-
promise帮你执行并且会把结果返回给你
-
promise的状态
- pedding 执行中
- resolved 成功状态
- rejected 失败状态
-
promise语法
-
创建promise对象:
let p = new Promise(function(){})
-
这个p对象有一个参数为一个函数
- 这个函数主要的作用就是让你执行异步代码的
-
这个p对象有两个方法:
- p.then() 当成功的时候,会执行这个函数,这个函数中有一个参数为回调函数,主要用来接收异步执行成功返回的结果
- p.catch() 当失败的时候,会执行这个函数,这个函数中有一个参数为回调函数,主要用来接收异步执行失败返回的结果
-
promise对象 参数为一个函数,这行函数中有两个参数:
- resolve:是一个成功的回调函数,当执行resolve() 就相当于在执行then方法中的回调函数
- reject:是一个失败的回调函数,当执行reject() 就相当于在执行catch方法中的回调函数
- 注意点:只要在then中返回promise对象,那么就能继续then
-
promise.html
let p=new Promise(function(resolve,reject){
ajax({
url:"./data1.php",
success:function(res){
resolves(res)
},
error:function(err){
reject(err);
}
});
});
p.then(function(res){
let p2=new Promies((resolve,reject)=>{
ajax({
url:"./data2.php",
data:{num:res},
success:function(res2){
resovle(res2);
}
})
})
p2.then(function(res2){
ajax({
url:"./data3.php",
data:{num:res2},
success:function(res3){
console.log(res3);
}
})
})
}).catch(function(res){
console.log(res);
})
promise2.html
<script>
let p=new Promise((resolve,reject)=>{
ajax({
url:"./data1.php",
success:function(res1){
resolve(res1);
},
});
});
p.then(res1=>{
return new Promise((resolve,reject)=>{
ajax({
url:"./data2.php",
data:{num:res1},
success:function(res2){
resolve(res2);
},
});
});
}).then(res2=>{
return new Promies((resolve,reject)=>{
ajax({
url:"./data3.php",
data:{num:res2},
success:function(res3){
resovle(res3);
},
});
});
}).then(data=>{
console.log(data);
})
</script>
promis3.html
<script>
let p = pAjax({
url: "./data1.php",
type: "post",
});
p.then((res) => {
return pAjax({
url: "./data2.php",
data: { num: res },
});
}).then((res2) => {
return pAjax({
url: "./data3.php",
data: { num: res2 },
});
}).then(data=>{
console.log(data);
});
封装一个promise形式的ajax请求
// 封装ajax请求
/*
参数:
【1】请求的地址
【2】请求方式(get||post)
【3】回调函数(用于获取异步代码执行结果),成功,失败
【4】请求的携带的参数
【5】设置同步或者异步
当函数的参数 过多的时候 应该把参数 写成一个对象传递
{
url:'请求的地址', //请求地址是必须
type:'get', 选填,不填的时候 默认值为get请求
data:{username:'aaa',password:'123123'} || "username=aaa&password=123123", 选填,有参数就传递 没有可以不填,需要有默认值为 ''
async:false, 选填 ,值为布尔值,不填写的时候为 true
success:fucntion(){}, 必填 请求成功之后执行的函数 获取到请求的结果
error:function(){} 选填 请求失败之后执行的函数
}
*/
function ajax(obj) {
// 判断必填的属性 是否有传递
if (!obj.url) {
// d当url没有填写的时候 抛出错误
throw Error("url属性不能为空");
}
// 判断success 是否有传递
if (!obj.success) {
throw Error("success属性不能为空");
}
// 当有一些参数没有传递的时候 需要添加默认值
let option = {
url: obj.url,
type: obj.type || "get",
data: obj.data || "",
async: obj.async || true,
success: obj.success,
error: obj.error || function (err) {
console.log(err);
},
};
// 判断一下 请求方式是否正确 post || get
if (!(option.type == "get" || option.type == "post")) {
throw Error("type属性的取值 暂时只支持 get 和 post");
}
// 判断data参数 是否是 对象 或者字符串
let datatype = Object.prototype.toString.call(option.data);
if (!(datatype == "[object Object]" || datatype == "[object String]")) {
throw Error("data参数的格式 暂时只支持对象或者字符串");
}
// 判断 async 是否是布尔值
if (!(Object.prototype.toString.call(option.async) == "[object Boolean]")) {
throw Error("async的取值只能为布尔值(true|| false)");
}
// 判断success 是否是函数
if (
!(Object.prototype.toString.call(option.success) == "[object Function]")
) {
throw Error("success 必须是一个函数");
}
// 判断error参数是否为函数
if (
!(Object.prototype.toString.call(option.error) == "[object Function]")
) {
throw Error("error 必须是一个函数");
}
// 如果参数为对象的时候 需要把对象转化为
// {name:'老谢',age:48}==>name=老谢&age=18
// "key=value&key=value"
if (Object.prototype.toString.call(option.data) == "[object Object]") {
let str = "";
for (let key in option.data) {
str += key + "=" + option.data[key] + "&";
}
option.data = str.substr(0, str.length - 1);
}
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
// ajax状态
if (xhr.readyState == 4 && /^[23]\d{2}$/.test(xhr.status)) {
// console.log(xhr.responseText);
option.success(xhr.responseText);
}
// http的状态码为 4 或者 5开头的时候
if (/^[45]\d{2}$/.test(xhr.status)) {
option.error(xhr.responseText)
}
};
// 判断请求方式
if (option.type == "get") {
xhr.open(option.type, `${option.url}?${option.data}`, option.async);
xhr.send();
return;
}
xhr.open(option.type, option.url, option.async);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send(option.data);
}
function pAjax(obj) {
return new Promise((resolve, reject) => {
ajax({
url: obj.url,
type: obj.type,
data: obj.data,
async: obj.async,
success: function (res) {
resolve(res)
},
error: function(err){
reject(err)
}
})
})
}
async和await
- async
- 写在函数前面的一个关键字
- 当写了async关键字之后 这个函数的返回值为promis对象
- await
- 等待 的必须是一个promise对象,当等到这个 promise 如果没有返回的结果的时候 后面的代码一直处于等待中 不会执行
- 当你等待的 promise 执行了resolve 或者reject的时候才表示等待到结果
async function fun(){
let res=await new Promise((resovle,reject)=>{
setInterval(()=>{
console.log(1);
resolve("aaa");
},1000);
});
console.log(res);
console.log(2);
}
fun();
//输出1 aaa 2 1 1 1 1 1 1 1....
async function getData() {
let res1 = await pAjax({
url: "./data1.php",
});
let res2 = await pAjax({
url: "./data2.php",
data: { num: res1 },
});
let res3 = await pAjax({
url: "./data3.php",
data: { num: res2 },
});
console.log(res3);
}
getData();
//输出30
</script>
瀑布流布局请求数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<meta name="referrer" content="no-referrer" />
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
ul,
li {
list-style: none;
}
a,
img {
width: 100%;
height: 100%;
display: block;
}
.box {
width: 1200px;
margin: 0 auto;
}
ul {
width: 260px;
float: left;
margin-right: 30px;
}
ul > li {
width: 100%;
display: flex;
flex-direction: column;
border: 1px solid #333;
margin-top: 10px;
}
ul > li > .imgBox {
width: 100%;
}
ul > li > .contentBox {
height: 160px;
box-sizing: border-box;
padding: 10px;
display: flex;
flex-direction: column;
justify-content: space-between;
}
ul > li > .contentBox > p {
display: flex;
justify-content: flex-start;
align-items: center;
}
ul > li > .contentBox > p:nth-child(1) {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
word-break: break-all;
height: 40px;
overflow: hidden;
}
ul > li > .contentBox > p:nth-child(2) > i {
width: 10px;
height: 10px;
background-color: #bbb;
}
ul > li > .contentBox > p:nth-child(2) > span {
color: #bbb;
padding: 0 10px;
}
ul > li > .contentBox > p:nth-child(3) > span:nth-child(1) {
width: 25px;
height: 25px;
border-radius: 50%;
overflow: hidden;
}
ul > li > .contentBox > p:nth-child(3) > span:nth-child(2) {
padding-left: 10px;
display: flex;
flex-direction: column;
}
ul > li > .contentBox > p:nth-child(3) .msg {
display: inline-block;
width: 100px;
overflow: hidden;
height: 18px;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: normal;
}
</style>
<script src="../ajax/ajax.js"></script>
</head>
<body>
<div class="box">
<ul>
<!-- <li>
<div class="imgBox">
<a href="javascript:;">
<img
src="https://c-ssl.duitang.com/uploads/item/201904/26/20190426233120_zxpmm.thumb.400_0.jpg"
alt=""
/>
</a>
</div>
<div class="contentBox">
<p>
黑白线稿/橡皮章素材/动漫/魔道祖师/蓝忘机黑白线稿/橡皮章素材/动漫/魔道祖师/蓝忘机
</p>
<p>
<i></i>
<span>12</span>
<i></i>
<span>22</span>
</p>
<p>
<span>
<a href="javascript:;">
<img
src="https://c-ssl.duitang.com/uploads/people/201803/15/20180315202505_VsjC4.thumb.24_24_c.jpeg"
alt=""
/>
</a>
</span>
<span>
<strong>name</strong>
<span>
发布到
<strong>位置</strong>
</span>
</span>
</p>
</div>
</li> -->
</ul>
<ul></ul>
<ul></ul>
<ul></ul>
</div>
<script>
/*
【1】获取页面中所需要的标签
【2】根据接口获取数据
【3】渲染数据
1】判断4列的ul高,往高度最小的ul中添加数据
【4】滚动滚动条的时候,当滚动条到达最小ul的高度的时候需要再次请求数据
*/
let uls = document.querySelectorAll(".box ul");
let start = 0;
// 设置一个变量表示 是否可以请求数据
// 如果为true的时候表示可以请求数据
let flag = true;
ajax({
url: "/dt",
data: {
include_fields:
"top_comments%2Cis_root%2Csource_link%2Citem%2Cbuyable%2Croot_id%2Cstatus%2Clike_count%2Csender%2Calbum%2Creply_count",
filter_id: "%E6%89%8B%E5%B7%A5DIY",
start: start,
},
success: function (res) {
let data = JSON.parse(res);
console.log(data);
start = data.data.next_start;
render(data.data.object_list);
},
});
// 滚动条滚动
window.onscroll = function () {
let minUl = getMinUl();
let h = minUl.offsetHeight;
if (scrollY >= h - innerHeight && flag == true) {
// 表示正在请求数据 不可以第二次请求
flag = false;
// console.log(1);
// 再次请求数据
ajax({
url: "/dt",
data: {
include_fields:
"top_comments%2Cis_root%2Csource_link%2Citem%2Cbuyable%2Croot_id%2Cstatus%2Clike_count%2Csender%2Calbum%2Creply_count",
filter_id: "%E6%89%8B%E5%B7%A5DIY",
start: start,
},
success: function (res) {
let data = JSON.parse(res);
start = data.data.next_start;
// 表示数据请求完成 可以进行一下次数据请求
flag = true;
render(data.data.object_list);
},
});
}
};
function render(data) {
data.forEach((item) => {
let str = `<li>
<div class="imgBox">
<a href="javascript:;">
<img
src="${item.photo.path}"
alt=""
/>
</a>
</div>
<div class="contentBox">
<p>
${item.msg}
</p>
<p>
<i></i>
<span>${item.favorite_count}</span>
<i></i>
<span>${item.like_count}</span>
</p>
<p>
<span>
<a href="javascript:;">
<img
src="${item.sender.avatar}"
alt=""
/>
</a>
</span>
<span>
<strong>${item.sender.username}</strong>
<span>
发布到
<strong>${item.album.name}</strong>
</span>
</span>
</p>
</div>
</li>`;
// 需要判断 ul的高度 得到一个最小高度的ul
// 假设第一个ul是最小
let minUl = getMinUl();
minUl.innerHTML += str;
});
}
// 计算最小高度的ul
function getMinUl() {
let ul = uls[0];
for (let i = 1; i < uls.length; i++) {
if (uls[i].offsetHeight < ul.offsetHeight) {
ul = uls[i];
}
}
return ul;
}
</script>
</body>
</html>