读编程与类型系统笔记06_函数类型的高级应用

1. 装饰器模式

1.1. 扩展对象的行为,而不必修改对象的类

1.2. 装饰的对象可以执行其原始实现没有提供的功能

1.3. 优势

1.3.1. 支持单一职责原则

1.3.1.1. 每个类只应该承担一种职责

1.4. 经典实现

1.4.1. 一个IComponent接口

1.4.2. 一个具体实现,即ConcreteComponent

1.4.3. 使用额外行为来增强IComponent的Decorator

1.4.3.1. 例如:添加单例行为

1.4.4. 特点

1.4.4.1. 一个接口

1.4.4.1.1. 接口声明了多个方法,就无法使用一个函数类型来替代接口

1.4.4.2. 两个类

1.4.4.3. 每个类一个方法

1.4.4.3.1. 具体操作
1.4.4.3.2. 装饰器

1.5. 函数装饰器

1.5.1. 接口改为一个函数类型

1.5.1.1. 示例:该类型的函数不接受实参,返回一个Widget:() => Widget

1.5.2. 一个具体实现的类替换为简单函数

1.5.3. 一个新函数singletonDecorator()

1.5.3.1. 接受一个WidgetFactory类型的函数

1.5.3.2. 返回另外一个WidgetFactory类型的函数

1.5.3.3. 采用lambda实现

1.5.4. 特点

1.5.4.1. 一个函数类型

1.5.4.1.1. 工厂函数类型

1.5.4.2. 两个函数

1.5.4.2.1. 工厂函数
1.5.4.2.2. 装饰器函数

1.6. 闭包

1.6.1. lambda捕获

1.6.1.1. lambda内捕获的一个外部变量

1.6.2. 编程语言通过闭包来实现lambda捕获

1.6.3. 闭包记录了创建该函数时的环境

1.6.3.1. 可以在不同调用之间维护状态

1.6.4. lambda引用了函数的局部变量

1.6.4.1. 其生存期将大于创建它的函数

1.6.4.2. 函数的局部变量在调用函数时创建,在函数返回时销毁

1.6.5. 保留了其外层函数的一些状态信息的lambda

1.6.6. 只有存在高阶函数,闭包才有意义

1.6.6.1. 不能从一个函数中返回另一个函数,就不存在要捕获的环境

1.6.6.2. 所有函数都在全局作用域内,所以全局作用域就是它们的环境

1.6.6.2.1. 函数只能引用全局变量

1.6.7. 对象代表一组方法的某个状态

1.6.8. 闭包则代表捕获到某个状态的函数

2. 计数器

2.1. 全局计数器

2.1.1. 一个引用全局变量的简单函数

2.1.2. 缺点

2.1.2.1. 计数器的值没有被恰当封装

2.1.2.2. 不能使用计数器的两个独立的实例

2.2. 面向对象的计数器

2.2.1. 多个独立的计数器

2.3. 函数式计数器

2.3.1. 代码比面向对象版本的更加简洁

2.4. 可恢复的计数器

2.4.1. 可恢复的函数

2.4.1.1. 跟踪自己状态的函数,在被调用时,不会从头运行,而是从上一次返回时所在的状态恢复执行

2.4.2. 不使用关键字return来退出函数

2.4.3. 使用关键字yield

2.4.3.1. 必须把函数声明为一个生成器

2.4.3.2. 其返回类型必须是可迭代的迭代器

2.4.3.3. 在函数名称的前面加上星号来声明生成器

2.4.4. TypeScript语法

2.4.5. 生成器通过特殊语法来创建可恢复的函数

2.4.6. 生成器不是返回控制权,而是交出控制权

3. 异步

3.1. 按顺序运行代码可能导致不可接受的延迟

3.2. 回调

3.2.1. 作为实参提供给异步函数的一个函数

3.2.2. 也可以从异步函数那里收到实参

3.3. 异步执行模型

3.3.1. 线程

3.3.2. 事件循环

3.3.2.1. 使用一个队列

3.3.2.2. 异步函数将被加入队列

3.3.2.3. 它们自己也可以将其他函数排队

3.3.2.4. 只要队列不为空,队列中的第一个函数就将被取出来执行

3.3.2.5. 优点

3.3.2.5.1. I/O操作等待数据时让它们排队的效果很好
3.3.2.5.2. 不需要同步,因为所有代码在一个线程上运行

3.3.2.6. 缺点

3.3.2.6.1. 对于运行时间长,但是不能被拆分为多个操作的任务,效果不好
3.3.2.6.2. CPU密集的操作会造成阻塞
3.3.2.6.2.1. CPU密集的操作(如复杂计算)不能被排队
3.3.2.6.2.2. 需要CPU周期
3.3.2.6.2.3. 没有等待数据

3.4. 简化异步代码

3.4.1. promise

3.4.1.1. 将来某个时刻可用的值的一个代理

3.4.1.2. 在生成该值的代码运行之前,其他代码可以使用该promise设置在该值可用后如何处理该值,在发生错误时如何处理,甚至取消将来的执行

3.4.1.3. 让代码的可读性相比使用回调时更好

3.4.1.4. 状态

3.4.1.4.1. 等待(pending)
3.4.1.4.1.1. 已被创建,但还没有完成
3.4.1.4.2. 完成(settled)
3.4.1.4.2.1. 已经调用了,并提供了一个值,此时将调用continuation
3.4.1.4.3. 拒绝(rejected)
3.4.1.4.3.1. 调用reject()或者抛出错误

3.4.1.4.3.1.1. 当前的promise会被拒绝

3.4.1.4.3.1.2. 通过then()链接到该promise的其他所有promise都会被拒绝

3.4.1.5. 组合promise

3.4.1.5.1. Promise.all()
3.4.1.5.1.1. 一组promise作为实参
3.4.1.5.1.2. 返回当提供的所有promise都完成后完成的一个promise
3.4.1.5.2. Promise.race()
3.4.1.5.2.1. 一组promise作为实参
3.4.1.5.2.2. 返回当提供的任何一个promise完成时完成的一个promise

3.4.2. continuation

3.4.2.1. 在promise的结果可用后调用的函数

3.4.2.2. 并非必须返回一个promise

3.4.2.2.1. 不是总会链接异步函数
3.4.2.2.2. 可以同步执行
3.4.2.2.3. 自动转换为Promise

3.4.2.3. 每个continuation放到一个单独的函数中,并通过then()把它们链接起来

3.4.3. 函数promise提供给我们某个类型T的值,以及指定从T到其他某个类型U的函数((value: T)=> U)的能力,当承诺被履行,我们得到了值以后,将调用这个函数(它就是continuation)

3.4.4. JavaScript(及TypeScript)采用Promise类型实现

3.4.5. C#采用Task实现

3.4.6. JAVA采用CompletableFuture实现

3.4.7. async/await

3.4.7.1. 代码的可读性更好

3.4.7.1.1. 异步代码读起来类似于同步代码

3.4.7.2. 把所有代码写到一个函数中,每当调用另外一个返回promise的函数,就等待(await)其结果,然后在得到结果后继续执行

3.4.7.3. 异常将从await调用抛出,可在try/catch语句中捕获

3.4.7.4. 不使用then()提供continuation

3.4.7.5. 语法糖

posted @ 2023-01-13 08:35  躺柒  阅读(35)  评论(0编辑  收藏  举报