ES6+ (中)
一、迭代器
-
所谓迭代就是逐个访问数据中各个成员的过程,在ES6中凡是能使用**for…of…**语句的对象,都叫做可迭代对象
-
迭代器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作
-
原生具备 iterator 接口的数据类型(可用 for of 遍历):
- Array
- Arguments
- Set
- Map
- String
- NodeList
- 需要注意的是Object不具备 iterator 接口
-
工作原理:
-
创建一个指针对象,指向当前数据结构的起始位置;
-
第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员;
-
接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员;
-
每调用 next 方法返回一个包含 value 和 done 属性的对象;
let arr = ['张三','李四','王五']; let iterator = arr[Symbol.iterator](); let result = iterator.next(); while(!result.done){ console.log(result.value); result = iterator.next() }
-
二、生成器
- 生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
2.1 创建生成器
-
生成器是一种返回迭代器的函数,通过function关键字后的星号( * )来表示
// *左右有没有空格都可以 function * generator(){ console.log('Hello generator!') } // 返回的是一个迭代器对象 console.log(generator())
2.2 调用生成器
-
调用生成器函数只会返回一个迭代器对象,所以还需要执行迭代器的next()方法才能执行生器中的代码
// 创建生成器 function * generator(){ console.log('Hello generator!') } // 返回迭代器 let iterator = generator(); // 执行迭代器的next()方法 iterator.next();
2.3 yield
-
yield的使用和return的使用没什么区别,只是yield会返回一个生成器
-
yield可以将生成器的代码分隔起多个部分,然后通过执行next()方法依次执行
function * generator(){ console.log('part one'); yield 1; console.log('part two'); yield 2; console.log('part three'); yield 3; console.log('part four'); } var iterator = generator(); console.log( iterator.next() ); // { done : false, value : 1 } console.log( iterator.next() ); // { done : false, value : 2 } console.log( iterator.next() ); // { done : false, value : 3 } console.log( iterator.next() ); // { done : true, value : undefined }
-
生成器返回的是迭代器对象,当然也可以通过for…of进行遍历,遍历的出来的结果为yield的值
// 创建生成器 function * generator(){ let num = 100; yield num; num++; yield num; num++; yield num; } // 返回迭代器 let iterator = generator(); // 遍历迭代器 for( v of iterator){ console.log(v); }
2.4 生成器异步编程应用
-
常见异步操作:
- 文件操作 : fs 文件读写
- 网络操作: ajax
- 数据库操作
- 定时器操作
- 事件操作
-
回调地狱问题:
-
有多个异步任务,每个任务执行时间是随机的?
setTimeout(function(){ console.log('任务一'); },Math.random() * 1000) setTimeout(function(){ console.log('任务二'); },Math.random() * 1000) setTimeout(function(){ console.log('任务三'); },Math.random() * 1000)
-
如何让这些异步任务,依次执行?普遍采用的方式就是回调嵌套,但如果嵌套的层次过多就会出现回调地狱的现象,代码看起来十分混乱,可读性极差。
setTimeout(function(){ console.log('任务一'); setTimeout(function(){ console.log('任务二'); setTimeout(function(){ console.log('任务三') },Math.random() * 1000) },Math.random() * 1000) },Math.random() * 1000)
-
生成器可以解决回调地狱的问题
function task1(){ setTimeout(function(){ console.log('任务一'); taskIterator.next(); },Math.random() * 1000) } function task2(){ setTimeout(function(){ console.log('任务二'); taskIterator.next(); },Math.random() * 1000) } function task3(){ setTimeout(function(){ console.log('任务三'); },Math.random() * 1000) } function * mytasks(){ yield task1(); yield task2(); yield task3(); } let taskIterator = mytasks(); taskIterator.next();
-
生成器参数传递问题
function task1(){ setTimeout(function(){ console.log('任务一'); taskIterator.next('结果1'); },Math.random() * 1000) } function task2(data){ console.log(data); setTimeout(function(){ console.log('任务二'); taskIterator.next('结果2'); },Math.random() * 1000) } function task3(data){ console.log(data); setTimeout(function(){ console.log('任务三'); taskIterator.next('结果3'); },Math.random() * 1000) } function * mytasks(){ let a = yield task1(); let b = yield task2(a); let c = yield task3(b); console.log(c); } let taskIterator = mytasks(); taskIterator.next();
-
三、Promise
Promise是ES6引入的异步编程的新的解决方案。
语法上Promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果
promise有三种状态:
- pending (进行中)
- resolve (成功)
- reject (失败)
3.1 基本用法
// 定义promise
const p = new Promise((resolve,reject){
// 异步操作 .......
if(成功){
resolve('成功结果');
}else{
reject('失败原因');
}
})
// 执行promise (方式一)
p.then(
data => {
// 获取成功结果
},
error => {
// 获取失败原因
}
)
// 执行promise (方式二)
p.then(data => {
// 获取成功结果
}).catch(error => {
// 获取失败原因
})
demo:
// 定义promise
const p = new Promise((resolve,reject) => {
// 异步操作 .......
setTimeout(function(){
let result = false;
if(result){
resolve('成功结果');
}else{
reject('失败原因');
}
})
})
// 执行promise方式一
p.then(
data => {
console.log(data);
},
error => {
console.log(error);
}
)
// 执行promise方式二(推荐)
p.then(data => {
console.log(data);
}).catch(error => {
console.log(error);
})
3.2 链式操作
-
then方法的返回结果是Promise对象,对象状态由回调函数的执行结果来决定
-
所以then方法是可以被链式调用的,利用这一特性可以解决异步编程的回调地狱问题
const p = new Promise((resolve,reject) => { setTimeout(function(){ console.log('任务一'); resolve('结果1') },Math.random() * 1000) }) p.then(data=>{ console.log(data); return new Promise((resolve,reject)=>{ setTimeout(function(){ console.log('任务二'); resolve('结果2') },Math.random() * 1000) }) }).then(data => { console.log(data); setTimeout(function(){ console.log('任务三'); console.log('结果3') },Math.random() * 1000) })
3.3 Promise.all([p1,p2,p3])
-
Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。
-
所有异步完成才会输出结果
-
只要有一个reject则会执行回调失败
-
需要特别注意的是,Promise.all获得的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的
const p1 = new Promise((resolve,reject) =>{ setTimeout(function(){ console.log('任务一'); resolve('结果1') },Math.random() * 1000) }) const p2= new Promise((resolve,reject) =>{ setTimeout(function(){ console.log('任务二'); resolve('结果2') },Math.random() * 1000) }) const p3 = new Promise((resolve,reject) =>{ setTimeout(function(){ console.log('任务二'); resolve('结果3') },Math.random() * 1000) }) let p = Promise.all([p1,p2,p3]); p.then(data=>{ console.log(data); }).catch(error=>{ console.log(error) })
3.4 Promise.race([p1,p2,p3])
-
顾名思义,Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态
const p1 = new Promise((resolve,reject) =>{ setTimeout(function(){ console.log('任务一'); resolve('结果1') },Math.random() * 1000) }) const p2= new Promise((resolve,reject) =>{ setTimeout(function(){ console.log('任务二'); resolve('结果2') },Math.random() * 1000) }) const p3 = new Promise((resolve,reject) =>{ setTimeout(function(){ console.log('任务二'); resolve('结果3') },Math.random() * 1000) }) let p = Promise.race([p1,p2,p3]); p.then(data=>{ console.log(data); }).catch(error=>{ console.log(error) })
四、async/await
async是对promise的一种扩展
async和await两种语法结合可以让异步代码像同步代码一样依次执行
4.1 async函数
-
async修饰的函数的返回值为promise对象
-
promise对象的结果由async函数的返回值决定
async function fun(){ return 'Hello'; // throw new Error('出错了') //return new Promise((resolve,reject) => { //resolve('成功') // reject('失败') //}) } //console.log(fun()); const p = fun(); p.then(data => { console.log(data) }).catch(error => { console.warn(error) })
4.2 await表达式
-
await 关键字只能用在async 函数中
-
await右侧的表达式一般为promise对象
-
await返回的是promise成功的值
-
await的promise失败了,就会抛出异常,需要通过try…catch…进行异常处理
// 定义promise const p = new Promise((resolve,reject) => { resolve('成功'); // reject('失败') }) // 定义async函数 async function fun(){ try{ let data = await p; console.log(data); }catch(error){ console.log(error); } } // 调用函数 fun();
4.3 解决回调地狱
// 异步任务1
function task1(){
return new Promise((resolve,reject) =>{
setTimeout(function(){
console.log('任务一');
resolve('结果1')
},Math.random() * 1000)
})
}
// 异步任务2
function task2(data){
console.log(data);
return new Promise((resolve,reject) =>{
setTimeout(function(){
console.log('任务二');
resolve('结果2')
},Math.random() * 1000)
})
}
// 异步任务3
function task3(data){
console.log(data);
return new Promise((resolve,reject) =>{
setTimeout(function(){
console.log('任务三');
resolve('结果3')
},Math.random() * 1000)
})
}
// async函数
async function fun(){
let result1 = await task1();
let result2 = await task2(result1);
let result3 = await task3(result2);
console.log(result3);
}
// 执行async函数
fun();
og(‘任务二’);
resolve(‘结果2’)
},Math.random() * 1000)
})
}
// 异步任务3
function task3(data){
console.log(data);
return new Promise((resolve,reject) =>{
setTimeout(function(){
console.log(‘任务三’);
resolve(‘结果3’)
},Math.random() * 1000)
})
}
// async函数
async function fun(){
let result1 = await task1();
let result2 = await task2(result1);
let result3 = await task3(result2);
console.log(result3);
}
// 执行async函数
fun();