Promise 异步
js核心代码在执行过程中,有的代码 代码 会在跳过执行,等待一段时间以后 又会继续执行,打破了从上至下,从左至右
的执行顺序, 这种代码我们统称为异步代码
- 定时器 延时器
- ajax
- 事件的监听和执行函数
- Promise 异步 类
1.基础语法
promise状态:
pending 等待
resolve=== fulfilled 成功
reject rejected 失败
promise 状态只会有一个结果, 状态不可逆, 等待--->成功
等待-->失败
1 2 3 4 5 6 7 8 9 10 11 12
| let p1 = new Promise(function(resolve,reject){ resolve() reject() })
|
2.promise 解决的问题
回调地狱问题
回调函数 有 回调 里面 还有回调
回调函数嵌套 层级 超过三层,一般就说形成了回调地狱
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| const http = { get(url,callback){ let xhr = new XMLHttpRequest(); xhr.open('get',url); xhr.send() xhr.onreadystatechange = function(){ if(xhr.readyState ==4 && xhr.status==200){ callback(JSON.parse(xhr.responseText)) } } }, post(url,data,callback){ let xhr = new XMLHttpRequest(); xhr.open('post',url); xhr.setReqeustHeader('content-type','application/json') xhr.send(JSON.stringify(data)) xhr.onreadystatechange = function(){ if(xhr.readyState ==4 && xhr.status==200){ callback(JSON.parse(xhr.responseText)) } } }, }
|
3.通过ajax 体验回调地狱 11:15
http.js 实现

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| <div class="list"> </div>
<script src="./http.js"></script> <script> let listDom = document.querySelector('.list') let data = []; // 请求用户的列表 http.get('/list',(res)=>{ data= res.data //循环数组 拿到id 请求对应的username 更新到data里面 for(let i=0;i<data.length;i++){ http.post('/info',{id:data[i].id},(res1)=>{ data[i].username = res1.data.username //请求头像 let formData = {id:data[i].id,username: data[i].username} http.post('/avatar',formData,(res2)=>{ data[i].avatar = res2.data.avatar; //将最新数据 拼接dom输出到页面 listDom.innerHTML+=` <div class="item"> <div class="img"> <img src="${data[i].avatar}" alt=""> </div> <div class="info"> <div class="id"> 用户编号:${data[i].id} </div> <div class="name"> 用户名字:${data[i].username} </div> </div> </div> `; }) }) } }) </script>
|
3.回调地狱
多个回调函数的嵌套,超过3级 形成回调地狱 【代码的可读性极低】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| http.get('/list',(res)=>{ data= res.data for(let i=0;i<data.length;i++){ http.post('/info',{id:data[i].id},(res1)=>{ data[i].username = res1.data.username let formData = {id:data[i].id,username: res1.data.username} http.post('/avatar',formData,(res2)=>{ data[i].avatar = res2.data.avatar; listDom.innerHTML+=` <div class="item"> <div class="img"> <img src="${data[i].avatar}" alt=""> </div> <div class="info"> <div class="id"> 用户编号:${data[i].id} </div> <div class="name"> 用户名字:${data[i].username} </div> </div> </div> `; }) }) } })
|
3.promise 解决回调地狱问题
三个:
pending 等待
fufailled resolve 成功
rejected reject 失败
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
let num =100 new Promise(function(resolve,reject){ setTimeout(()=>{ if(num%2 ==0){ resolve('是偶数') }else{ reject('是奇数') } },1000) }).then(function(res){ console.log(res); }).catch(function(err){ console.log(err); })
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
let num =101 let p = new Promise(function(resolve,reject){ setTimeout(()=>{ if(num%2 ==0){ resolve('是偶数') }else{ reject('是奇数') } },1000) })
p.then(function(res){ console.log(res); })
p.catch(function(err){ console.log(err); })
|
4.promise 的then 的链式调用
promise 的 then链式调用 可以解决ajax 的回调地狱
1 2
| p.then(res=>{}).then(res1=>{}).then(res2=>{})
|
1 2 3 4 5 6 7 8 9 10 11
| let data = {}; http.get('/list',res=>{ data = res.data; http.post('/info',{id:res.data.id},res1=>{ http.post('/avatar',{id:res1.data.id,username:res1.data.username},res2=>{ data.username = res2.data.username; data.avatar = res2.data.avatar; console.log(data); }) }) })
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| new Promise((resolve,reject)=>{ http.get('/list',res=>{ data = res.data; resolve(res) }) }).then(res=>{ return new Promise((resolve,reject)=>{ http.post('/info',{id:res.data.id},res1=>{ resolve(res1) }) }) }).then(res1=>{ return new Promise((resolve,reject)=>{ http.post('/avatar',{id:res1.data.id,username:res1.data.username},res2=>{ resolve(res2) }) }) }).then(res2=>{ console.log(res2); data.avatar = res2.data.avatar; data.username = res2.data.username })
|
5.简化代码 ,提炼公共部分代码 形成代码的封装
复写axios.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| const base_url = 'http://8.137.157.16:9004' const http = { get(url){ let p = new Promise((resolve,reject)=>{ let xhr = new XMLHttpRequest(); xhr.open('get',base_url+url); xhr.send() xhr.onreadystatechange = function(){ if(xhr.readyState ==4 && xhr.status==200){ resolve(JSON.parse(xhr.responseText)) } } }) return p; }, post(url,data){ return new Promise((resolve,reject)=>{ let xhr = new XMLHttpRequest(); xhr.open('post',base_url+url); xhr.setRequestHeader('content-type','application/json') xhr.send(JSON.stringify(data)) xhr.onreadystatechange = function(){ if(xhr.readyState ==4 && xhr.status==200){ resolve(JSON.parse(xhr.responseText)) } } }) }, } window.http = http;
|
1 2 3 4 5 6 7 8
| http.get('/list') .then(res => { return http.post('/info', { id: res.data.id }) }).then(res1 => { return http.post('/avatar', { id: res1.data.id, username: res1.data.username }) }).then(res2 => { console.log(res2); })
|
6.axios 的使用与原理
promise+ajax(XMLHttpReqeust)
- 找axios的中文网
- 下载axios.js
bootcdn
下载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <script src="./axios.js"></script> <script> let data = {};
axios.defaults.baseURL = 'http://8.137.157.16:9004';
axios.get('/list') .then(res => { console.log(res); return axios.post('/info', { id: res.data.data.id }) }).then(res1 => { return axios.post('/avatar', { id: res1.data.data.id, username: res1.data.data.username }) }).then(res2 => { console.log(res2.data); })
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| let base_url = 'http://8.137.157.16:9004' const http = (obj)=>{ let {method,url,data,responseType} = obj; if(method=='get'){ return http.get(url) } if(method=='post'){ let type = responseType==0?'application/json':'application/x-www-form-urlencoded' return http.post(url,data,type) } } http.get = (url)=>{ let p = new Promise((resolve,reject)=>{ let xhr = new XMLHttpRequest(); xhr.open('get',base_url+url); xhr.send() xhr.onreadystatechange = function(){
if(xhr.readyState ==4 && xhr.status==200){ resolve(JSON.parse(xhr.responseText)) } } }) return p; } http.post = (url,data,responseType='application/json')=>{ return new Promise((resolve,reject)=>{ let xhr = new XMLHttpRequest(); xhr.open('post',base_url+url); xhr.setRequestHeader('content-type',responseType) xhr.send(JSON.stringify(data)) xhr.onreadystatechange = function(){ if(xhr.readyState ==4 && xhr.status==200){ resolve(JSON.parse(xhr.responseText)) } } }) } window.http = http;
|
7. 浏览器事件循环机制 event loop
同步 异步的深入研究
代码执行顺序
定时器 延时器
ajax 事件
promise
1.promise 是异步吗?
promise 本身不是异步, promise.then 方法是异步
2.同步和 异步问题
先执行所有的同步 再 执行异步
3.浏览器事件循环机制
代码执行顺序:
遵循 从上至下 从左至右
依次执行。
异步代码: 宏任务(定时器 延时器 ajax 事件) 微任务 promise.then
如果微任务和 宏任务在同一个异步层级,先执行 所有的微任务 再执行宏任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| console.log(1);
new Promise((resolve,reject)=>{ console.log(3); console.log(5); resolve() }).then(_=>{ setTimeout(()=>{ console.log(4); },0) console.log(6);
}) console.log(7);
setTimeout(()=>{ console.log(2); },0)
|
面试题:
1.你对回调地狱的理解?
2.如何解决回调地狱?
3.event loop 浏览器事件循环机制 (关于同步异步代码的执行顺序)?
4.promise 是异步还是同步?
5.宏任务和微任务的区别 分别有哪些?
async await promise 内置方法 all race