一、什么是回调地狱
- 以一堆 }) 结尾的金字塔,可称它为——“回调地狱”
- 在JS中我们经常会大量使用异步回调,例如使用ajax请求
二、如何解决回调地狱
(一)使用ES6中的Promise
- Promise有三种状态:pending/resolve/reject 。pending就是未决,resolve可以理解为成功,reject可以理解为拒绝
- Promise常用的三种方法:
- then 表示异步成功执行后的数据状态变为resolve
- catch 表示异步失败后执行的数据状态变为reject
- all表示把多个没有关系的Promise封装成一个Promise对象,使用then返回一个数组数据
例:使用Promise
//Promise 构造函数有两个变量:resolve 用于返回异步执行成功的函数;reject 用于返回异步执行失败的函数。配合then与catch一起使用
function f1(){
var promise=new Promise(function(resolve,reject){
setTimeout(function(){
resolve("promise yes");
},1000)
});
return promise;
}
//使用then获取上一步resolve返回的数据
function f2(){
return f1().then(function(data){
return data+"vue";
});
}
f2().then(function(data){
console.log(data);
});
console.log("hello world");
先输出 hello word 后输出promise yesvue,说明Promise是异步执行的
问题:若过多的使用then 也会照成新的执行流程问题
(二)使用ES6中的Generator(生成器)
在JavaScript中,任何一个函数只要开始执行,便无法停止下来直到执行完成;但是,Generator提供这种能力
例:使用Generator
//用Promise分装一个异步请求模拟ajax
function f1() {
let promise = new Promise(function(resolve, reject){
setTimeout(function () {
resolve("hello word");
})
});
return promise;
}
//构建一个生成器函数
function* f(){
let x = yield f1();
console.log("ni hao");
}
//获取生成器的值
var it = f();
it.next().value.then(function(data){
console.log(data);
});
console.log(123);
it.next();
console.log(it.next());
- 先用Promise分装一个异步请求模拟ajax。
- 构建一个生成器函数:在函数方法名前面加一个 * ,函数体中有一个yield关键字,它类似return,也是返回值。区别在于当程序执行到yield后会返回yield后面的表达式,并且程序暂停在这里保存当前值状态,程序只是暂停并没有中止。
- 获取生成器的值:使用next()方法可以获取到yield第一次暂停的值返回的是{ value: 值 done: true } value表示yield返回的值,done表示是否迭代完毕;也可使用next(10)给yield设置下次执行的值。
- 通过结果看到生成器也是异步执行。
执行结果如下:
(三)async/await (异步等待)
-
async 函数是 Generator 函数的语法糖;使用关键字 async 来表示,在函数内部使用 await 来表示异步。
-
相较于 Generator,async 函数的改进在于下面四点:
-
内置执行器:Generator 函数的执行必须依靠执行器,而 async 函数自带执行器,调用方式跟普通函数的调用一样
-
更好的语义:async 和 await 相较于 * 和 yield 更加语义化
-
更广的适用性:co 模块约定,yield 命令后面只能是 Thunk 函数或 Promise对象。而 async 函数的 await 命令后面则可以是 Promise 或 原始类型的值(Number,string,boolean,但这时等同于同步操作)
-
返回值是 Promise:async 函数返回值是 Promise 对象,比 Generator 函数返回的 Iterator 对象方便,可以直接使用 then() 方法进行调用
例:使用async/await
//封装异步请求
function f(){
return new Promise(function(resolve, reject) {
setTimeout(function(){
resolve("hello word");
},1000)
})
}
//使用异步函数
async function a(){
var data = await f();
return data;
}
//获取值
var a = a();
a.then(function(data){
console.log(data);
})
- 封装异步请求;
- 使用异步函数:函数前加async表示该函数为一异步函数,await 表示等待一个异步值的到来;
- 获取值:异步函数返回的是一个Promise对象,return返回的值通过使用then来进行获取。
执行结果如下: