迭代器 生成器 Promise介绍
1. 迭代器
迭代器就是为实现对不同集合进行统一遍历操作的一种机制,只要给需要遍历的数据结构部署Iterator接口,通过调用该接口,或者使用消耗该接口的API实现遍历操作。
ES6为迭代器引入了一个隐式的标准化接口。Javascript许多内建的数据结构,例如Array、Map、Set、String、TypedArray、函数的 arguments 对象、NodeList 对象都具备 Iterator 接口。
Iterator接口主要为for of 使用,for of(遍历的是value
) 不同于for in(遍历的是key)
const arr = [4, 3, 2, 1];
for (let v of arr) {
console.log(v); // 4 3 2 1
}
可以通过在控制台打印一个Array实例,查看其原型上具有一个Symbol.iterator属性(Symbol.iterator其实是Symbol(‘Symbol.iterator’)的简写,属性名是Symbol类型代表着这个属性的唯一以及不可重写覆盖),它就是迭代器函数,执行这个函数,就会返回一个迭代器对象,对象下有一个next()方法。
1.1. next()迭代
在获得数组最后一位元素的时候,迭代器不会报告done:true,这时候需要再次调用next(),越过数组结尾的值,才能得到完成信号done:true。
通常情况下,在已经迭代完毕的迭代器对象上继续调用next方法会继续返回{value: undefined, done: true}而不会报错。
1.2. 实现自定义遍历的数据
自定义遍历obj的list数据,而非obj
const obj = {
name: 'gg',
list: ['a', 'b', 'c', 'd', 'e'],
[Symbol.iterator]() {
let index = 0;
return {
next: () => {
if (index < this.list.length) {
const result = { value: this.list[index], done: false };
index++;
return result;
} else return { value: undefined, done: true };
}
};
}
};
for (let v of obj) {
console.log(v);
}
2. 生成器
生成器就是一个特殊的函数,是针对于异步编程一个新的解决方案。function 和函数名之间加个 *
返回的是一个迭代器对象 可以使用next() 方法调用
yield 函数代码的分隔符
function* gen() {
console.log('1');
yield 'a'; // 函数代码的分隔符
console.log('2');
yield 'b';
console.log('3');
yield 'c';
}
let iterator = gen(); // 返回的是一个迭代器对象 可以使用next() 方法调用
iterator.next(); // 1
iterator.next(); // 2
iterator.next(); // 3
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
迭代器对象 即可使用for of
输出的为yield后面的代码
function* gen() {
yield 'a'; // 函数代码的分隔符
yield 'b';
yield 'c';
}
for (let v of gen()) {
console.log(v); // a b c
}
2.1. 生成器传递参数
next()方法传递的参数将作为上一个yield的返回值
function* gen(arg) {
console.log(arg);
let one = yield 111;
console.log(one);
let two = yield 222;
console.log(two);
let three = yield 333;
console.log(three);
}
let iterator = gen('AAA');
console.log(iterator.next());
console.log(iterator.next('BBB'));
console.log(iterator.next('CCC'));
console.log(iterator.next('DDD'));
2.2. 案例
2.2.1. 需求一
1s后输出111,接着2s后输出222,接着3s后输出333,总耗时 6s
(1) 传统写法(回调地狱)
setTimeout(() => {
console.log(111);
setTimeout(() => {
console.log(222);
setTimeout(() => {
console.log(333);
}, 3000);
}, 2000);
}, 1000);
(2) 生成器写法(优雅)
const one = () => {
setTimeout(() => {
console.log(111);
iterator.next();
}, 1000);
};
const two = () => {
setTimeout(() => {
console.log(222);
iterator.next();
}, 2000);
};
const three = () => {
setTimeout(() => {
console.log(333);
iterator.next();
}, 3000);
};
function* gen() {
yield one();
yield two();
yield three();
}
let iterator = gen();
iterator.next();
2.2.2. 需求二
通过用户信息返回订单信息返回商品信息s
const getUser = () => {
setTimeout(() => {
let data = 'user';
iterator.next(data);
}, 1000);
};
const getOrder = () => {
setTimeout(() => {
let data = 'order';
iterator.next(data);
}, 1000);
};
const getGood = () => {
setTimeout(() => {
let data = 'good';
iterator.next(data);
}, 1000);
};
function* gen() {
let user = yield getUser();
console.log(user);
let order = yield getOrder();
console.log(order);
let good = yield getGood();
console.log(good);
}
let iterator = gen();
iterator.next();
3. Promise
Promise 是ES6引入的异步编程的新解决方案。Promise是一个构造函数,用来封装异步操作,并可以获取成功.then()或失败.catch()的结果。
.then(a, b)可以有两个参数,a为成功,b为失败;b也可不写,使用.catch()返回错误
const p = new Promise((resolve, reject) => {
setTimeout(() => {
// let data = 'data';
// resolve(data);
let err = 'gg';
if (err) {
reject(err);
}
}, 1000);
});
p.then(
result => {
console.log(result);
},
err => {
console.error(err);
}
).catch(err => {
console.error(err);
});
3.1. 读取单个文件
(1)node 错误优先机制
const fs = require('fs');
fs.readFile('./1.txt', (err, data) => {
if (err) throw err;
console.log(data);
console.log(data.toString());
});
(2)使用promise封装,读取不存在的文件,报错
const p = new Promise((resolve, reject) => {
fs.readFile('./2.txt', (err, data) => {
if (err) {
reject(err);
}
resolve(data);
});
});
p.then(data => {
console.log(data);
}).catch(err => {
console.error(err);
});
3.2. Ajax
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
const xhr = new XMLHttpRequest();
xhr.open('get', 'http://ip-api.com/json/58.23.7.26?lang=zh-CN');
xhr.send();
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status <= 300) {
console.log(xhr.response);
} else {
console.error(xhr.status);
}
}
};
</script>
</body>
</html>
3.3. Promise封装
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
const p = new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('get', 'http://ip-api.com/json/58.23.7.26?lang=zh-CN');
xhr.send();
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status <= 300) {
resolve(xhr.response);
} else {
reject(xhr.status);
}
}
};
});
p.then(data => {
console.log(data);
}).catch(err => {
console.error(err);
});
</script>
</body>
</html>
3.4. then()
then可以链式调用,解决回调地狱的问题
如果return一个空或非promise类型的对象,状态为成功,值为return的值(不return则为undefined)
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok');
}, 1000);
});
const result = p
.then(data => {
console.log(data);
// 如果return一个空或非promise类型的对象,状态为成功,值为return的值(不return则为undefined)
// return 123;
})
.catch(err => {
console.error(err);
});
console.log(result);
return 一个promise对象(对象返回的状态即为then返回值的状态
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok');
}, 1000);
});
const result = p
.then(data => {
console.log(data);
// 如果return一个空或非promise类型的对象,状态为成功,值为return的值(不return则为undefined)
// return 123;
// return 一个promise对象(对象返回的状态即为then返回值的状态)
return new Promise((resolve, reject) => {
resolve('ok');
});
})
.catch(err => {
console.error(err);
});
console.log(result);
3.5. 读取多个文件
fs.readFile('./1.txt', (err, data1) => {
fs.readFile('./2.txt', (err, data2) => {
fs.readFile('./3.txt', (err, data3) => {
console.log(data1 + data2 + data3);
});
});
});
new Promise((resolve, reject) => {
fs.readFile('./1.txt', (err, data) => {
resolve(data.toString());
});
})
.then(value => {
return new Promise((resolve, reject) => {
fs.readFile('./2.txt', (err, data) => {
resolve([value, data.toString()]);
});
});
})
.then(value => {
return new Promise((resolve, reject) => {
fs.readFile('./3.txt', (err, data) => {
value.push(data.toString());
resolve(value);
});
});
})
.then(value => {
console.log(value);
});