迭代器
迭代器与可迭代对象
迭代器: 一种特殊的可迭代对象,实现了迭代器协议。
可迭代对象:在javascript/Typescript中,要实现一个可迭代对象, 该对象必须实现 Symbol.iterator 方法(也可以说是遵循可迭代协议),当一个对象实现了Symbol.iterator方法时,我们就认为它是可迭代的。在javascript/Typescript中,内置类型:Array,Map,Set,String都是实现了Symbol.iterator方法的。对象上的 Symbol.iterator函数负责返回供迭代的值。
// 数组
var arr = Array(1,2,3);
console.log(arr);
// 集合
var set1 = new Set([1,2,3,3,2,]);
console.log(set1);
var arr = [1,2,3]; // 工作中一般声明数组进行简写
console.log( arr[Symbol.iterator] );
console.log( arr[Symbol.iterator]() ); // 返回值就是一个迭代器
// tsc --target ES2020 main.ts
symbol 类型
自ECMAScript 2015起,symbol成为了一种新的原生类型,就像number和string一样。可以通过Symbol() 函数返回 symbol 类型的值。每个 symbol 值都是不可改变并且唯一的,所以开发中,Symbol非常适合做唯一key。(有点像集合)
const s1: symbol = Symbol();
const s2: symbol = Symbol('foo');
const s3: symbol = Symbol('foo');
console.log(s1);
console.log(s2);
console.log(s3);
console.log(s2 === s3); // false, 唯一,所以不相等
s3 = 123; // 不能再次赋值, 编译报错
// console.log(s3);
迭代器
在javascript中,一个对象只有实现了指定格式的next()方法才能成为迭代器。next必须返回值类型是 { value: any, done: boolean }。
迭代器一旦创建,迭代器对象就可以通过重复调用 next() 显式地迭代。
unction MyIterator(array) {
let nextIndex = 0;
return {
next() {
if(nextIndex >= array.length){
return {
done: true
}
}
return {
value: array[nextIndex++],
done: false
}
}
};
}
let it = MyIterator(['A', 'B', "C", "D"]);
console.log(it.next().value); // 'A'
console.log(it.next().value); // 'B'
console.log(it.next().value); // 'C'
console.log(it.next().value); // 'D'
console.log(it.next().done); // True
注意:此处的MyIterator没有实现可迭代协议,所以并非可迭代对象。
生成器的声明
生成器对象既是迭代器,也是可迭代对象。Generator其实是ES6对协程的一种实现。由于JavaScript是单线程语言,本身就是一个不停循环的执行器,所以它的协程是比较简单的,js中的线程和协程关系是 1:N,一个线程里同一时间只能有一个协程在执行。
必须有*才是生成器。
只有生成器可以用for-of,迭代器不可以,
var myIterable = {
*[Symbol.iterator](){
yield 1;
yield 2;
yield 3;
}
};
console.log(myIterable);
for( let item of myIterable){
console.log(item);
}
function* generatorFunction() {
console.log('开始执行');
yield 'Hello, ';
console.log('暂停后再次执行');
yield 'World!';
}
let gen = generatorFunction();
// console.log( gen.next() ); // {value: "Hello, ", done: false}
// console.log( gen.next() ); // {value: "World!", done: false}
// console.log( gen.next() ); // {value: undefined, done: true}
for(let item of gen){
console.log(item); // 这里返回的结果经过 for-of处理只会得到value的值
}
带有参数的生成器
function* gen() {
console.log('开始执行');
let res1 = yield 1;
console.log('中断后继续执行');
console.log(res1);
let res2 = yield 2;
console.log(res2);
let res3 = yield 3;
console.log(res3);
console.log('执行结束');
return 4
}
let gen1 = gen();
console.log( gen1.next() ); // 激活生成器
console.log(gen1.next('A'));
console.log(gen1.next('B'));
console.log(gen1.nex
异步回调函数
Promise是ES6开始支持的一个可以获取异步结果,并封装了一些异步操作的对象。有三个状态:
pending: 进行中, 初始状态。
resolved: 成功
rejected: 失败
并且这三个状态只有两种转换:pending->resolved、pending->rejected,不是成功就是失败,并没有多余的状态转换。这两种转换都是由异步返回的结果给定的,成功取回数据就是resolved,取数据出异常就是rejected。异步调用过程中,Promise不能在任务进行中取消,只能等结果返回。
unction aiohttp(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onload = () => resolve(JSON.parse(xhr.responseText));
xhr.onerror = () => reject(xhr.statusText);
xhr.send();
});
}
// resolve:成功;reject:失败两个参数
let ip = "123.112.18.111";
aiohttp(`http://ip-api.com/json/${ip}?lang=zh-CN`).then((response)=>{
console.log(response);
}).catch((error)=>{
console.log(error);
});
console.log("hello!");
基于协程实现异步编程
async和await是ES7的议案,TypeScript也支持。
async和await其实是Generator的语法糖。除了*换成async, yield换成await之外,最主要是async await内置了执行器,不用像Generator用那样next()一直往下执行。
function delay(): Promise<void>{
return new Promise<void>((resolve, reject)=>{
setTimeout(()=>resolve(), 2000)
});
}
async function run(){
console.info('start');
await delay(); // 这里的await就是yield,所以会交出程序的执行权
console.info('finish');
}
run();
console.info('run');
/*
start
run
finish
*/