回调地狱和promise

14 篇文章 0 订阅
本文深入探讨了JavaScript中处理异步操作的常见问题,从传统的回调函数导致的回调地狱,过渡到Promise的使用,以及如何通过Promise链式调用来改善代码结构。进一步,文章介绍了async/await的使用,展示了如何通过async函数实现类似同步的代码逻辑,避免了回调的复杂性。最后,通过多个示例分析了Promise和async/await的执行顺序,强调了正确处理异步操作的重要性。
摘要由CSDN通过智能技术生成

根据setTimeout的延迟时间,会依次执行奶茶、火锅、唱歌、看电影。这不是我想要的顺序。

function getTea(fn){
    setTimeout(()=>{
        fn('奶茶')
    },500)
}
function getHotpot(fn){
    setTimeout(()=>{
        fn('火锅')
    },600)
}
function getSing(fn){
    setTimeout(()=>{
        fn('唱歌')
    },700)
}
function getfilm(fn){
    setTimeout(()=>{
        fn('看电影')
    },1000)
}
//统一处理数据的方法
function fn(data){
    console.log(data);
}
getfilm(fn)
getSing(fn);
getHotpot(fn);
getTea(fn);

我想先看电影,唱歌、火锅、奶茶,就需要一层一层嵌套实现。就会造成可怕的回调地狱,层数越多维护起来越麻烦。

function getTea(fn){
    setTimeout(()=>{
        fn('奶茶')
    },500)
}
function getHotpot(fn){
    setTimeout(()=>{
        fn('火锅')
    },600)
}
function getSing(fn){
    setTimeout(()=>{
        fn('唱歌')
    },700)
}
function getfilm(fn){
    setTimeout(()=>{
        fn('看电影')
    },1000)
}
getfilm(function(data){
    console.log(data);
    getSing(function(data){
        console.log(data);
        getHotpot(function(data){
            console.log(data);
            getTea(function(data){
                console.log(data);
            })
        })
    })
})

办法:使用promise解决异步问题,比回调地狱更好维护。

//每个函数调用后返回的都是promise对象
function getTea(){
    return new Promise(function(resolve){
        setTimeout(()=>{
            //调用resolve把数据传出去
            resolve('奶茶')
        },500)
    })
}
//每个函数调用后返回的都是promise对象
function getHotpot(){
    return new Promise(function(resolve){
        setTimeout(()=>{
            resolve('火锅')
        },600)
    })
}
//每个函数调用后返回的都是promise对象
function getSing(){
    return new Promise(function(resolve){
        setTimeout(()=>{
            resolve('唱歌')
        },700)
    })
}
//每个函数调用后返回的都是promise对象
function getfilm(){
    return new Promise(function(resolve){
        setTimeout(()=>{
            resolve('看电影')
        },1000)
    })
}
// getfilm();  返回值是一个promise对象  直接用then
getfilm().then(function(data){
    console.log(data);
    //then 里面写一个return 一个还想调的promise对象
    return getSing();
}).then(function(data){
    console.log(data);
    return getHotpot();
}).then(function(data){
    console.log(data);
    return getTea();
}).then(function(data){
    console.log(data);
})

可是看起来也没有化繁为简,一堆的then。
使用async函数

function getTea(){
    return new Promise(function(resolve){
        setTimeout(()=>{
            //调用resolve把数据传出去
            resolve('奶茶')
        },500)
    })
}
function getHotpot(){
    return new Promise(function(resolve){
        setTimeout(()=>{
            resolve('火锅')
        },600)
    })
}
function getSing(){
    return new Promise(function(resolve){
        setTimeout(()=>{
            resolve('唱歌')
        },700)
    })
}
function getfilm(){
    return new Promise(function(resolve){
        setTimeout(()=>{
            resolve('看电影')
        },1000)
    })
}
//将异步实现效果为同步
async function fn(){
    //getfilm() 返回值是promise对象,
    //用await直接获取  resolve传递出来的异步数据。
    //而之前我们用then 才能拿到数据data。then(function(data){})
    let film  = await getfilm();
     //必须等待await结束后才继续执行下面代码
    console.log(film);
    //相当于实现同步了
    let sing = await getSing();
    console.log(sing);
    let hot = await getHotpot();
    console.log(hot);
    let tea = await getTea();
    console.log(tea);
}
fn();

可以任意先做什么就做什么,先log谁就log谁

async function fn(){
    let film  = await getfilm();
    let sing = await getSing();
    let hot = await getHotpot();
    let tea = await getTea();
    console.log(sing);
    console.log(tea);
    console.log(hot);
    console.log(film);
}
fn();

关于promise:
1、没有resolve、没有reject
不会调用then或者catch。

let p = new Promise(()=>{
    //函数里面是同步代码
    console.log('同步执行代码');
})
//只有resolve才会执行then
p.then(()=>{
    console.log('then');
})
console.log('同步2');

输出 同步执行代码、同步2

2、resolve没有参数
没有参数也就是没有传数据

let p = new Promise((resolve)=>{
    //函数里面是同步执行代码
    console.log('同步执行代码');
    resolve();//有then就会执行
})
//只有resolve才会执行then
p.then(()=>{
    console.log('then微任务');
})
console.log('同步2');

注意then是异步的微任务,等待同步任务完成后,才执行微任务。
依次输出同步执行代码、同步2、then微任务。

3、resolve有参数

let p = new Promise((resolve)=>{
    //函数里面是同步代码
    console.log('同步执行代码');
    resolve('参数data');
})
//只有resolve才会执行then
p.then((data)=>{
    console.log('then微任务');
    console.log(data);
})
console.log('同步2');

注意then是异步的微任务,等待同步任务完成后,才执行微任务。
依次输出同步执行代码、同步2、then微任务、参数data。

3、有resolve、reject。
resolve则执行then、reject则执行catch。且改变不可逆。
当isPass = true,调用resolve。
当为false,调用reject。

        const isPass = true;
        const p = new Promise((resolve,reject)=>{
            if(isPass){
                resolve("通过了")
            }else{
                reject("没有通过哦")
            }
        });
        p.then(grade =>{
                  console.log(`你的四六级结果是,${grade}`);
              })
         .catch(grade =>{
                  console.log(`你的四六级结果是,${grade}`);
              })

在promise对象p 加上finally,不管什么情况,都会调用

              .finally(() =>{
                  console.log("不管怎么样那还是要吃大餐的");
              });

关于async
1、async函数返回的是promise对象

async function fun1(){
    return  20
}
//acync返回的是promise对象
console.log(fun1());
//fun1、fun2 函数是等价的
function fun2(){
    return new Promise((resolve)=>{
        resolve(20)
    })
}
console.log(fun2());

2、和await配合在例子也提过了。
练习:

console.log('start1');
async function f1(){
    await f2();//立即去执行f2函数
    //awaitf2(); 的后面相当于 then
    //将console.log('2');放入微任务队列
    console.log('2');
}
async function f2(){
    console.log('3');
}
f1();
setTimeout(function(){
    console.log(4);
},500)
console.log(5);
setTimeout(function(){
    console.log(6);
},0)
new Promise(resolve=>{
    console.log(7);
    resolve();
}).then(function(){
    console.log(8);
})
console.log(9);
process.nextTick(()=>{
    console.log('process.nextTick');
})
new Promise(resolve=>{
    console.log(10);
    resolve();
}).then(function(){
    console.log(11);
})
console.log('end');

依次输出start1、3、5、7、9、10、end、process.nextTick、2、8、11、6、4。

总结:
1、同步
2、process.nextTick
3、异步(4、微任务:promise.then…。 5、宏任务:计时器、ajax,读取文件…)

补充:
promise链式调用

      <script>
        new Promise((resolve,reject)=>{
            console.log(1);
            resolve(100)
        })
        .then(v=>{
            new Promise((resolve,reject)=>{
                console.log(2+',v:'+v);
                resolve(200)
            }).then(v=>{
                console.log(3+',v:'+v);
            }).then(v=>{
                console.log(4+',v:'+v);
                return 300
            }).then(v=>{
                console.log(5+',v:'+v);
                return 400
            })
        })
        .then(v=>{
            console.log(6+',v:'+v);
        })
    </script>

链式调用,then一定依赖同一个promise的上一个then中return的值。
在这里插入图片描述
结果:
第一个then中没有return给第二个then,而且第一个then中有promise,它是异步操作
在这里插入图片描述
加上return 后,执行完第一个then才到第二个then。
在这里插入图片描述
结果:

在这里插入图片描述
关于reutrn的值:必须是当前then的return 的promise的最后一个then一定要有return。
在这里插入图片描述
有return:
再怎么嵌套都要保证最后一个then有return。
在这里插入图片描述
绕啊绕

    <script>
        new Promise((resolve,reject)=>{
            resolve(100)
        })
        .then(v=>{
            return new Promise((resolve,reject)=>{
                console.log(1+',v:'+v);
                resolve(200)
            }).then(v=>{
                console.log(2+',v:'+v);
                return 300
            }).then(v=>{
                console.log(3+',v:'+v);
                return 3
            }).then(v=>{
                console.log(33+',v:'+v);
                return 33
            }).then(v=>{
                console.log(333+',v:'+v);
                return 333
            }).then(v=>{
                console.log(3333+',v:'+v);
                return 400
            })
        })
        .then(v=>{
            return new Promise((resolve,reject)=>{
                console.log(4+',v:'+v);
                resolve(500)
            }).then(v=>{
                console.log(5+',v:'+v);
                return 600
            }).then(v=>{
                console.log(6+',v:'+v);
                return 6
            }).then(v=>{
                console.log(66+',v:'+v);
                return 66
            }).then(v=>{
                console.log(666+',v:'+v);
                return 666
            }).then(v=>{
                console.log(6666+',v:'+v);
                return 700
            })
        })
        .then(v=>{
            return new Promise((resolve,reject)=>{
                console.log(7+',v:'+v);
                resolve(400)
            }).then(v=>{
                console.log(8+',v:'+v);
                return 800
            }).then(v=>{
                console.log(9+',v:'+v);
                return 9
            }).then(v=>{
                console.log(99+',v:'+v);
                return 99
            }).then(v=>{
                console.log(999+',v:'+v);
                return 999
            }).then(v=>{
                console.log(9999+',v:'+v);
                return 1000
            })
        })
        .then(v=>{
            return new Promise((resolve,reject)=>{
                console.log(10+',v:'+v);
                resolve(1000)
            }).then(v=>{
                console.log(11+',v:'+v);
                return 1200
            })
        })
        .then(v=>{
            console.log(12+',v:'+v);
        })
    </script>

在这里插入图片描述
结果很顺序
在这里插入图片描述
但是当其中有的没有return,而且还有promise对象时。
把第1个、第2个、第四个的return删掉后

    <script>
        new Promise((resolve,reject)=>{
            resolve(100)
        })
        .then(v=>{
             new Promise((resolve,reject)=>{
                console.log(1+',v:'+v);
                resolve(200)
            }).then(v=>{
                console.log(2+',v:'+v);
                return 300
            }).then(v=>{
                console.log(3+',v:'+v);
                return 3
            }).then(v=>{
                console.log(33+',v:'+v);
                return 33
            }).then(v=>{
                console.log(333+',v:'+v);
                return 333
            }).then(v=>{
                console.log(3333+',v:'+v);
                return 400
            })
        })
        .then(v=>{
             new Promise((resolve,reject)=>{
                console.log(4+',v:'+v);
                resolve(500)
            }).then(v=>{
                console.log(5+',v:'+v);
                return 600
            }).then(v=>{
                console.log(6+',v:'+v);
                return 6
            }).then(v=>{
                console.log(66+',v:'+v);
                return 66
            }).then(v=>{
                console.log(666+',v:'+v);
                return 666
            }).then(v=>{
                console.log(6666+',v:'+v);
                return 700
            })
        })
        .then(v=>{
            return new Promise((resolve,reject)=>{
                console.log(7+',v:'+v);
                resolve(400)
            }).then(v=>{
                console.log(8+',v:'+v);
                return 800
            }).then(v=>{
                console.log(9+',v:'+v);
                return 9
            }).then(v=>{
                console.log(99+',v:'+v);
                return 99
            }).then(v=>{
                console.log(999+',v:'+v);
                return 999
            }).then(v=>{
                console.log(9999+',v:'+v);
                return 1000
            })
        })
        .then(v=>{
             new Promise((resolve,reject)=>{
                console.log(10+',v:'+v);
                resolve(1000)
            }).then(v=>{
                console.log(11+',v:'+v);
                return 1200
            })
        })
        .then(v=>{
            console.log(12+',v:'+v);
        })
    </script>

结果有undefined,而且then中有promise异步,执行顺序不一致,不过then所依赖的同级上一个then的return的值不变。
在这里插入图片描述
再补充:

1、fulfilled状态的promise,自动向下找then,在then中返回非promise的值,它会生成状态fulfilled的新promise对象,传入下一个回调函数。

    <script>
        new Promise((resolve,reject)=>{
            resolve(100)
        }).then(v=>{
            console.log(1+',v:'+v);
            return 200
        }).then(v=>{
            console.log(2+',v:'+v);
        }).catch(v=>{
            console.log(3+',v:'+v);
        })
    </script>

在这里插入图片描述
2、
rejected状态的promise,自动向下找catch,在catch中返回非promise的值,它会生成状态fulfilled的新promise对象,传入下一个回调函数。

    <script>
        new Promise((resolve,reject)=>{
            reject(100)
        }).then(v=>{
            console.log(1+',v:'+v);
            return 200
        }).catch(v=>{
            console.log(3+',v:'+v);
            return 300
        }).then(v=>{
            console.log(4+',v:'+v);
        }).catch(v=>{
            console.log(5+',v:'+v);
        })
    </script>

在这里插入图片描述
在这里插入图片描述

3、rejected状态的promise,自动向下找catch,在catch中返回promise对象的值,根据该promise对象的状态决定传入下一个回调函数。

    <script>
        new Promise((resolve,reject)=>{
            reject(100)
        }).then(v=>{
            console.log(1+',v:'+v);
            return new Promise.reject(200)
        }).then(v=>{
           console.log(2+',v:'+v);
        }).catch(v=>{
            console.log(3+',v:'+v);
            return new Promise.reject(300)
        }).then(v=>{
            console.log(4+',v:'+v);
        }).catch(v=>{
            console.log(5+',v:'+v);
        }).catch(v=>{
            console.log(6+',v:'+v);
        }).catch(v=>{
            console.log(7+',v:'+v);
        })
    </script>

在这里插入图片描述

4、
fulfilled状态的promise,自动向下找then,在then中返回promise对象的值,根据该promise对象的状态决定传入下一个回调函数。

        new Promise((resolve,reject)=>{
            resolve(100)
        }).then(v=>{
            console.log(1+',v:'+v);
            return new Promise.reject(200)
        }).then(v=>{
           console.log(2+',v:'+v);
        }).catch(v=>{
            console.log(3+',v:'+v);
        }).then(v=>{
            console.log(4+',v:'+v);
        }).catch(v=>{
            console.log(5+',v:'+v);
        })
    </script>

在这里插入图片描述
5、抛出错误异常
都会生成rejected状态的promise。

    <script>
        new Promise((resolve,reject)=>{
            resolve(100)
        }).then(v=>{
            console.log(2+',v:'+v);
            throw new Error('xxx')
        }).catch(v=>{
            console.log(3+',v:'+v);
            throw new Error('xxx')
        }).then(v=>{
            console.log(4+',v:'+v.message);
        }).catch(v=>{
            console.log(5+',v:'+v.message);
        }).catch(v=>{
            console.log(6+',v:'+v.message);
        })
    </script>

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值