typescript基础(七)(生成器/协程异步)

3,502 阅读3分钟

迭代器

迭代器与可迭代对象

迭代器: 一种特殊的可迭代对象,实现了迭代器协议。

可迭代对象:在javascript/Typescript中,要实现一个可迭代对象, 该对象必须实现 Symbol.iterator 方法(也可以说是遵循可迭代协议),当一个对象实现了Symbol.iterator方法时,我们就认为它是可迭代的。在javascript/Typescript中,内置类型:ArrayMapSetString都是实现了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 类型

www.tslang.cn/docs/handbo…

自ECMAScript 2015起,symbol成为了一种新的原生类型,就像numberstring一样。可以通过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->resolvedpending->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也支持。

asyncawait其实是Generator的语法糖。除了*换成asyncyield换成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
 */