剖析promise,async/await,settimeout
promise
Promise一句话就是用同步的写法和同步的执行顺序实现异步的业务功能。
同步异步的通俗的理解就是,比如同步的话:你去餐厅吃饭要点菜叫服务员过来,服务员说要等前一桌客人吃完才能点菜,异步的话:去吃饭大家都可以吃饭点菜,你吃饭的时候我也可以点菜。
在代码上的理解就是promise使用.then()链式写法解决回调地狱的问题。
回调地狱案例(无限嵌套):通过登录获取用户订单列表再通过订单列表默认获取列表第一条数据
function fn3(){
$.ajax({
type:'POST',
url:'/login',
data:{user:user},
success(res){
//登陆成功获取用户id,拿到id去找order表对应所有订单列表
$.ajax({
type:'GET',
url:'/getOrder',
data:{userid:res.userid},
success:function(res){
//获取所有订单列表,以及成功的状态,成功再默认获取第一个订单的详情。
$.ajax({
type:'GET',
url:'/getDetail',
data:{id:res[0].id},
success(res){
//渲染订单详情
console.log(res)
}
})
}
})
}
})
}
使用Promise解决,resolve成功返回值继续向下一个.then传递数据,reject为失败的传值,跳过后面的.then执行catch内容。
function a1(){
return new Promise((resolve,reject)=>{
$.ajax({
type:'POST',
url:'/login',
data:{user:user},
success(res){
//登陆成功返回用户id
console.log(res)
resovle(res.userid)
},
error(err){
reject({
msg:'登录失败',
status:-1
})
}
})
})
}
function a2(res){
return new Promise((resolve,reject)=>{
$.ajax({
type:'GET',
url:'/getOrder',
data:{userid:res},
success(res){
//返回所有列表
console.log(res)
resolve(res)
},
error(err){
reject('获取订单列表失败')
}
})
})
}
function a3(res){
return new Promise((resolve,reject)=>{
$.ajax({
type:'GET',
url:'/getDetail',
data:{id:res[0].id},
success(res){
//渲染订单详情
console.log(res)
},
error(err){
reject('获取订单详情失败')
}
})
})
}
function main(){
a1()
.then((data)=>{
return a2(data)
})
.then((data)=>{
return a3(data)
})
.catch((err)=>{
console.log(err)
})
.finally(()=>{
console.log('执行了Promise')
})
}
Promise使用数据打印结果:
function test2() {
fn1() //函数内部,都相当于是异步的请求操作;
.then((data) => {
console.log(data)
return fn2(); //函数内部,都相当于是异步的请求操作;
})
.then((data)=>{
console.log(data)
return 1111
})
.then((data) => {
console.log(data)
return new Promise((resove, reject) => {
console.log("d3")
reject("------");
})
})
.catch((data) => {
console.log(data)
console.log("d4")
})
.finally(()=>{
console.log("无能前面是成功,还是失败的结果,都要执行finally")
})
// d1, d2, d3
// promise异步的业务功能 的实现,代码是同步的写法和同步的执行顺序 ;
// fn1();
// fn2();
// console.log("d3")
// d3, d2,d1
}
function fn1() {
return new Promise((resolve, reject) => {
setTimeout(function () {
console.log("d1")
resolve({
name:'username'
})
}, 2000);
});
}
function fn2() {
return new Promise((resolve, reject) => {
setTimeout(function () {
console.log("d2")
resolve("d20")
}, 1000);
});
}
async
先说一下async的用法,它作为一个关键字放到函数前面,用于表示函数是一个异步函数,因为async就是异步的意思, 异步函数也就意味着该函数的执行不会阻塞后面代码的执行。
async的使用:--------------->打印结果3,await类似于.then()的执行
如果有reject,则跳到catch打印reject内的内容。
function a1(){
return new Promise((resolve,reject)=>{
resolve(3)
})
}
function a2(res){
return new Promise((resolve,reject)=>{
resolve(res)
})
}
function a3(res){
return new Promise((resolve,reject)=>{
resolve(res)
})
}
async function test(){
try{
let data1 = await a1()
let data2 = await a2(data1)
let data3 = await a3(data2)
console.log(data3)
}
catch(err){
console.log(err);
}
}
--------------------------------------------------------------------------
//ajax传值同理:
function a1(){
return new Promise((resolve,reject)=>{
$.ajax({
type:'POST',
url:'/login',
data:{user:user},
success(res){
//登陆成功返回用户id
console.log(res)
resovle(res.userid)
},
error(err){
reject({
msg:'登录失败',
status:-1
})
}
})
// resolve(3)
})
}
function a2(res){
return new Promise((resolve,reject)=>{
$.ajax({
type:'GET',
url:'/getOrder',
data:{userid:res},
success(res){
//返回所有列表
console.log(res)
resolve(res)
},
error(err){
reject('获取订单列表失败')
}
})
// resolve(res)
})
}
function a3(res){
return new Promise((resolve,reject)=>{
$.ajax({
type:'GET',
url:'/getDetail',
data:{id:res[0].id},
success(res){
//渲染订单详情
console.log(res)
resolve(res)
},
error(err){
reject('获取订单详情失败')
}
})
// resolve(res)
})
}
关于async/await、promise和setTimeout执行顺序
-
js EventLoop 事件循环机制:
JavaScript的事件分两种,宏任务(macro-task)和微任务(micro-task)
宏任务:包括整体代码script,setTimeout,setInterval
微任务:Promise.then(非new Promise),process.nextTick(node中) -
执行顺序:
应该整体先分成同步任务和异步任务
异步任务又分成宏任务和微任务
先执行同步 再执行异步
异步中先执行微任务,再执行宏任务
头条一个经典面试题为案例,打印结果:
async function async1() {
console.log('async1 start');
await async2();
console.log('asnyc1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(() => {
console.log('setTimeOut');
}, 0);
async1();
new Promise(function (reslove) {
console.log('promise1');
reslove();
}).then(function () {
console.log('promise2');
})
console.log('script end');
对于async await的理解
- async 做一件什么事情?
- await 在等什么?
- await 等到之后,做了一件什么事情?
async 做一件什么事情?
- 一句话概括: 带 async 关键字的函数,它使得你的函数的返回值必定是 promise 对象。
也就是如果async关键字函数返回的不是promise,会自动用Promise.resolve()包装。
如果async关键字函数显式地返回promise,那就以你返回的promise为准。
这是一个简单的例子,可以看到 async 关键字函数和普通函数的返回值的区别。
async function fn1(){
return 123
}
function fn2(){
return 123
}
console.log(fn1())
console.log(fn2())
--------打印结果---------------------------------------------------
Promise {<resolved>: 123}
123
所以,async 函数也没啥了不起的,以后看到带有 async 关键字的函数也不用慌张,你就想它无非就是把return值包装了一下,其他就跟普通函数一样。
关于async关键字还有那些要注意的?
- 在语义上要理解,async表示函数内部有异步操作
- 另外注意,一般 await 关键字要在 async 关键字函数的内部,await 写在外面会报错。
await 在等什么?
- 一句话概括: await等的是右侧「表达式」的结果
也就是说:
右侧如果是函数,那么函数的return值就是「表达式的结果」
右侧如果是一个 ‘hello’ 或者什么值,那表达式的结果就是 ‘hello’
async function async1() {
console.log( 'async1 start' )
await async2()
console.log( 'async1 end' )
}
async function async2() {
console.log( 'async2' )
}
async1()
console.log( 'script start' )
这里注意一点,可能大家都知道await会让出线程,阻塞后面的代码,那么上面例子则为从右向左的。先打印async2,后打印的script start
await 等到之后,做了一件什么事情?
那么右侧表达式的结果,就是await要等的东西。等到之后,对于await来说,分2个情况:
- 不是promise对象
- 是promise对象
-
如果不是 promise , await会阻塞后面的代码,先执行async外面的同步代码,同步代码执行完,再回到async内部,把这个非promise的东西,作为 await表达式的结果。
-
如果它等到的是一个 promise 对象,await 也会暂停async后面的代码,先执行async外面的同步代码,等着 Promise 对象fulfilled,然后把 resolve 的参数作为 await 表达式的运算结果。
本文地址:https://blog.csdn.net/Z269571627/article/details/111030900
推荐阅读
-
详解koa2学习中使用 async 、await、promise解决异步的问题
-
JS异步编程 (2) - Promise、Generator、async/await
-
Promise, Generator, async/await的渐进理解
-
node传统读取文件和promise,async await,
-
async & await & Promise
-
js-异步机制,同步机制,promise,async,await
-
ES6---Promise应用: async, await
-
ES6---async, await, promise 综合例子
-
promise与async-await
-
setTimeout、Promise、Async/Await 的执行顺序