异步的发展过程
-
第一个阶段:回调函数(callback)。一层一层的嵌套,会产生回调地狱,可读性不强,不便于后期维护
-
第二个阶段:promise。ES6提出的。promise对象,有三种状态:
pending
(进行中)、fulfilled
(已成功)和rejected
(已失败),用then方法来指定resolved(成功)状态的回调函数,用catch
方法指定rejected(失败)状态的回调函数。有两特征:1、状态不受外界影响;2、一旦状态改变,就不会再变,任何时候都可以得到这个结果 -
第三个阶段:genarator函数(生成器)。ES6 提供的一种异步编程解决方案。其有两个特征:一是,
function
关键字与函数名之间有一个星号;二是,函数体内部使用yield
表达式,定义不同的内部状态。调用genarator函数会返回一个迭代器(iterator),利用迭代器next方法来调用里面的函数,执行到yield会暂停,返回一个对象{value,done},value值是当前yield后面的值,也是next方法返回的值,done的值为布尔值,false表示函数未被执行完毕,true表示执行完毕。co模块或者自行封装辅助函数可以帮助自动执行genarator函数 -
第四个阶段:async 函数。ES2017 标准引入,是genarator函数的语法糖。会返回一个promise对象,可以使用
then
方法添加回调函数,当函数执行的时候,一旦遇到await
就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。async函数内部return
语句返回的值,会成为then
方法回调函数的参数
//按顺序输出[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
export default {
//第一阶段 回调函数 回调地狱
cb() {
let arr;
$.ajax({
type: "get",
url: "/test/1",
success(data) {
//data为请求成功之后服务端返回的数据
arr = data;
$.ajax({
type: "get",
url: "/test/2",
success(data) {
arr = [...arr, ...data];
$.ajax({
type: "get",
url: "/test/3",
success(data) {
arr = [...arr, ...data];
$.ajax({
type: "get",
url: "/test/4",
success(data) {
arr = [...arr, ...data];
// console.log(arr);
}
})
}
})
}
})
}
})
},
//第二阶段 promise/then
promise() {
let arr;
new Promise(resolve => {
$.ajax({
type: "get",
url: "/test/1",
success(data) {
//data为请求成功之后服务端返回的数据
arr = data;
resolve(arr);//resolve出去的就是success的返回值
}
})
}).then(arr => {
//then里面的arr接受的上一次resolve出来的值
return new Promise(resolve => {
$.ajax({
type: "get",
url: "/test/2",
success(data) {
arr = [...arr, ...data];//解构成一个新的数组
resolve(arr);
}
})
}).then(arr => {
return new Promise(resolve => {
$.ajax({
type: "get",
url: "/test/3",
success(data) {
arr = [...arr, ...data];
resolve(arr);
}
})
})
}).then(arr => {
return new Promise(resolve => {
$.ajax({
type: "get",
url: "/test/4",
success(data) {
arr = [...arr, ...data];
resolve(arr);
}
})
})
}).then(arr => console.log(arr))
})
},
//第三阶段 genarator函数 yield
//*表示这个函数是genarator函数
*gen() {
const a = yield new Promise(resolve => {
$.ajax({
type: "get",
url: "/test/1",
success: resolve
})
});
const b = yield new Promise(resolve => {
$.ajax({
type: "get",
url: "/test/2",
success: resolve
})
});
const c = yield new Promise(resolve => {
$.ajax({
type: "get",
url: "/test/3",
success: resolve
})
});
const d = yield new Promise(resolve => {
$.ajax({
type: "get",
url: "/test/4",
success: resolve
})
});
return [...a, ...b, ...c, ...d]
},
//第四阶段 async/await
async functionAsync() {
const a = await new Promise(resolve => {
$.ajax({
type: "get",
url: "/test/1",
success: resolve
})
});
const b = await new Promise(resolve => {
$.ajax({
type: "get",
url: "/test/2",
success: resolve
})
});
const c = await new Promise(resolve => {
$.ajax({
type: "get",
url: "/test/3",
success: resolve
})
});
const d = await new Promise(resolve => {
$.ajax({
type: "get",
url: "/test/4",
success: resolve
})
});
return [...a, ...b, ...c, ...d]
}
}
//genarator 函数
//yield可以暂停代码执行,即代码执行到yield就暂停执行
//yield后面跟的是next方法返回的value值
//yield是next方法暂停执行的点
//*表示这是一个genarator函数
function* gen() {
console.log("开始");
const a = yield 1;//代码执行到yield 1就暂停,下一次next调用时候开始给a赋值,赋值为next()括号里面传入的值
console.log(a);
const b = yield 2;
console.log(b);
const c = yield 3;
console.log(c);
return a + b + c;
}
//迭代器 next方法
const it = gen();
console.log(it);
console.log(it.next());//{value: 1, done: false} value是第一次yield后面的值,done:false表示genarator函数未执行完毕
console.log(it.next(2));//{value: 2, done: false} 第二次yield返回2 next里面传的值赋值给a,所以a输出2
console.log(it.next(3));
console.log(it.next(4));//{value: 9, done: true} 最后一次执行,先赋值c=4,紧接着输出的值为4,然后rerun结果9,genarator函数执行完毕,done的状态值为true
console.log(it.next());//{value: undefined, done: true} 执行完毕继续调用状态一直未true,value为undefined
//辅助函数
function run(gen) {
const it = gen();
function next(data) {
const { value, done } = it.next(data);
if (done) { return value };
//判断yield返回的是否是一个promise对象
if (Object.prototype.toString.call(value) === "[object Promise]") {
return value.then(data => next(data));
} else { return next(value) };
};
return next();
}
上面纯粹是自己总结的,由于模块挺多的,省略不少东西,暴露方法和引入以及输出语句等代码都省略了,敬请见谅!
需要详细了解的可以看看《ECMAScript 6 入门教程》