1.异步行为
就比如向远程服务器发送请求并等待响应,那就出现长时间等待,然而后面的代码该执行就执行,等数据请求过来了,再回调回去,至于啥时候请求到数据谁也不知道,后面要用数据的代码在请求到代码之前执行,运气不错,正好用上,后面要用数据的代码在请求到代码之后,运气不行,代码就会报错
2.解决方法:
方法一:在ES6出现之前,采用回调嵌套回调的方法,这就形成回调地狱,看到就头皮发麻,不好维护
//获取奶茶的方法
function getTea(fn) {
setTimeout(() => {
fn("奶茶")
}, 1000)
}
//获取火锅的方法
function getHotpot(fn) {
setTimeout(() => {
fn("火锅")
}, 2000)
}
//有些方法没有写
getHotpot(function (data) {
console.log(data);
//调用获取奶茶的方法(回调)
getTea(function (data) {
console.log(data)
//调用获取出去玩的方法(回调)
getPlay(function (data) {
console.log(data)
//调用获取喝可乐的方法(回调)
getTea(function (data) {
console.log(data)
//调用获取睡觉的方法(回调)
getTea(function (data) {
console.log(data)
})
})
})
})
})
方法二:后来ES6推出了Promise解决了回调地狱,看起来更符合逻辑,Promise是一个构造函数,自己身上有all、reject、resolve这几个方法,原型上有then、catch的方法。
Promise的构造函数接收一个参数,是函数,并且传入两个参数:resolve,reject,分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数。
//获取奶茶的方法
function getTea() {
return new Promise(function (resolve) {
setTimeout(() => {
resolve("奶茶") //执行成功,传出数据
}, 1000)
})
}
//获取火锅的方法
function getHotpot(){
return new Promise(function(resolve){
setTimeout(()=>{
resolve("火锅")
},800)
})
}
//先吃火锅再喝奶茶
getHotpot().then(function(data){
console.log(data);
return getTea() //返回Promise对象
}).then(function(data){ //接收Promise对象,里面传出来数据,然后回调
console.log(data)
})
上面是执行成功的回调
reject是执行失败传出数据,再去回调失败数据
function getNumber() {
return new Promise(function (resolve, reject) {
//做一些异步操作
setTimeout(function () {
var num = Math.ceil(Math.random() * 10); //生成1-10的随机数
if (num <= 5) {
resolve(num); //传出执行成功的数据
}
else {
reject('数字太大了'); //传出执行失败的数据
}
}, 2000);
});
}
getNumber()
.then( //then方法可以接受两个参数,第一个对应resolve的回调,第二个对应reject的回调
function (data) {
console.log('resolved');
console.log(data);
},
function (data) {
console.log('rejected');
console.log(data);
}
);
then是用来进行回调的,成功的失败的都可以进行回调,而catch只接受失败的回调,相当于then的第二个参数
//then的写法
getNumber()
.then( //then方法可以接受两个参数,第一个对应resolve的回调,第二个对应reject的回调
function (data) {
console.log('resolved');
console.log(data);
},
function (data) {
console.log('rejected');
console.log(data);
}
);
//then和catch的写法
getNumber()
.then(function(data){
console.log('resolved');
console.log(data);
})
.catch(function(data){
console.log('rejected');
console.log(data);
});
Promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调
Promise
.all([异步任务1,异步任务2,异步任务3])
.then(function(data){
console.log(data)
}
)
Promise的race方法是所有异步操作中最快的执行回调,其他的照常运行,但不参与回调
Promise
.race([runAsync1(), runAsync2(), runAsync3()])
.then(function(data){
console.log(data);
});
//假如异步任务1执行的快,那异步任务1执行回调,任务2和任务3照常执行,但不回调
方法三
async函数,用async和await写,使得代码看起来更简洁更优雅,把异步数据写的更像同步数据,能用async函数就不用Promise函数
//获取奶茶的方法
function getTea() {
return new Promise(function (resolve) {
setTimeout(() => {
resolve("奶茶")
}, 1000)
})
}
//获取火锅的方法
function getHotpot(){
return new Promise(function(resolve){
setTimeout(()=>{
resolve("火锅") //执行成功,传出数据
},800)
})
}
//async函数 先吃火锅再喝奶茶 把异步数据写的更像同步数据
async function getData(){
//直接获得resolve传递出来的异步数据
let hotPot = await getHotpot();
console.log(hotPot)
let tea = await getTea();
console.log(tea)
}
网友评论