什么是ios 函数响应式编程程

如何学习MVVM 和函数响应式编程_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
如何学习MVVM 和函数响应式编程
中国移动互联网行业领军品牌|
总评分0.0|
&&如何学习MVVM 和函数响应式编程
阅读已结束,如果下载本文需要使用0下载券
想免费下载更多文档?
定制HR最喜欢的简历
你可能喜欢响应式编程与响应式系统
-03%-12%-14%-35%-47%-53%-57%-61%-67%-74%-92%-94%
在恒久的迷惑与过多期待的海洋中,登上一组简单响应式设计原则的小岛。
下载 Konrad Malawski 的免费电子书,深入了解更多响应式技术的知识与好处。
自从 2013 年一起合作写了之后,我们看着响应式从一种几乎无人知晓的软件构建技术&&当时只有少数几个公司的边缘项目使用了这一技术&&最后成为中间件领域middleware field大佬们全平台战略中的一部分。本文旨在定义和澄清响应式各个方面的概念,方法是比较在响应式编程风格下和把响应式系统视作一个紧密整体的设计方法下编写代码的不同之处。
响应式是一组设计原则
响应式技术目前成功的标志之一是&响应式reactive&成为了一个热词,并且跟一些不同的事物与人联系在了一起&&常常伴随着像&流streaming&、&轻量级lightweight&和&实时real-time&这样的词。
举个例子:当我们看到一支运动队时(像棒球队或者篮球队),我们一般会把他们看成一个个单独个体的组合,但是当他们之间碰撞不出火花,无法像一个团队一样高效地协作时,他们就会输给一个&更差劲&的队伍。从这篇文章的角度来看,响应式是一组设计原则,一种关于系统架构与设计的思考方式,一种关于在一个分布式环境下,当实现技术(implementation techniques)、工具和设计模式都只是一个更大系统的一部分时如何设计的思考方式。
这个例子展示了不经考虑地将一堆软件拼揍在一起&&尽管单独来看,这些软件都很优秀&&和响应式系统之间的不同。在一个响应式系统中,正是不同组件(parts)间的相互作用让响应式系统如此不同,它使得不同组件能够独立地运作,同时又一致协作从而达到最终想要的结果。
一个响应式系统 是一种架构风格(architectural style),它允许许多独立的应用结合在一起成为一个单元,共同响应它们所处的环境,同时保留着对单元内其它应用的&感知&&&这能够表现为它能够做到放大/缩小规模(scale up/down),负载平衡,甚至能够主动地执行这些步骤。
以响应式的风格(或者说,通过响应式编程)写一个软件是可能的;然而,那也不过是拼图中的一块罢了。虽然在上面的提到的各个方面似乎都足以称其为&响应式的&,但仅就其它们自身而言,还不足以让一个系统成为响应式的。
当人们在软件开发与设计的语境下谈论&响应式&时,他们的意思通常是以下三者之一:
响应式系统(架构与设计)
响应式编程(基于声明的事件的)
函数响应式编程(FRP)
我们将调查这些做法与技术的意思,特别是前两个。更明确地说,我们会在使用它们的时候讨论它们,例如它们是怎么联系在一起的,从它们身上又能到什么样的好处&&特别是在为多核、云或移动架构搭建系统的情境下。
让我们先来说一说函数响应式编程吧,以及我们在本文后面不再讨论它的原因。
函数响应式编程(FRP)
函数响应式编程Functional reactive programming,通常被称作&FRP,是最常被误解的。FRP 在二十年前就被 Conal Elliott 了。但是最近这个术语却被错误地脚注1 用来描述一些像 Elm、Bacon.js 的技术以及其它技术中的响应式插件(RxJava、Rx.NET、 RxJS)。许多的库(libraries)声称他们支持 FRP,事实上他们说的并非响应式编程,因此我们不会再进一步讨论它们。
响应式编程
响应式编程Reactive programming,不要把它跟函数响应式编程混淆了,它是异步编程下的一个子集,也是一种范式,在这种范式下,由新信息的有效性(availability)推动逻辑的前进,而不是让一条执行线程(a thread-of-execution)去推动控制流(control flow)。
它能够把问题分解为多个独立的步骤,这些独立的步骤可以以异步且非阻塞(non-blocking)的方式被执行,最后再组合在一起产生一条工作流(workflow)&&它的输入和输出可能是非绑定的(unbounded)。
(Asynchronous)被牛津词典定义为&不在同一时刻存在或发生&,在我们的语境下,它意味着一条消息或者一个事件可发生在任何时刻,也有可能是在未来。这在响应式编程中是非常重要的一项技术,因为响应式编程允许[非阻塞式(non-blocking)]的执行方式&&执行线程在竞争一块共享资源时不会因为阻塞(blocking)而陷入等待(为了防止执行线程在当前的工作完成之前执行任何其它操作),而是在共享资源被占用的期间转而去做其它工作。阿姆达尔定律(Amdahl's Law) 脚注2 告诉我们,竞争是可伸缩性(scalability)最大的敌人,所以一个响应式系统应当在极少数的情况下才不得不做阻塞工作。
响应式编程一般是事件驱动(event-driven),相比之下,响应式系统则是消息驱动(message-driven)的&&事件驱动与消息驱动之间的差别会在文章后面阐明。
响应式编程库的应用程序接口(API)一般是以下二者之一:
基于回调的(Callback-based)&匿名的间接作用(side-effecting)回调函数被绑定在事件源(event sources)上,当事件被放入数据流(dataflow chain)中时,回调函数被调用。
声明式的(Declarative)&&通过函数的组合,通常是使用一些固定的函数,像&map、&filter、&fold 等等。
大部分的库会混合这两种风格,一般还带有基于流(stream-based)的操作符(operators),像 windowing、 counts、 triggers。
说响应式编程跟(dataflow programming)有关是很合理的,因为它强调的是数据流而不是控制流。
举几个为这种编程技术提供支持的的编程抽象概念:
&&一个值的容器,具有读共享/写独占(many-read/single-write)的语义,即使变量尚不可用也能够添加异步的值转换操作。
流(streams) - &&无限制的数据处理流,支持异步,非阻塞式,支持多个源与目的的反压转换管道(back-pressured transformation pipelines)。
&&依赖于输入、过程(procedures)或者其它单元的单赋值变量(single assignment variables)(存储单元),它能够自动更新值的改变。其中一个应用例子是表格软件&&一个单元的值的改变会像涟漪一样荡开,影响到所有依赖于它的函数,顺流而下地使它们产生新的值。
在 JVM 中,支持响应式编程的流行库有 Akka Streams、Ratpack、Reactor、RxJava 和 Vert.x 等等。这些库实现了响应式编程的规范,成为 JVM 上响应式编程库之间的互通标准(standard for interoperability),并且根据它自身的叙述是&&&一个为如何处理非阻塞式反压异步流提供标准的倡议&。
响应式编程的基本好处是:提高多核和多 CPU 硬件的计算资源利用率;根据阿姆达尔定律以及引申的 G&nther 的通用可伸缩性定律(G&nther&s Universal Scalability Law) 脚注3 ,通过减少序列化点(serialization points)来提高性能。
另一个好处是开发者生产效率,传统的编程范式都尽力想提供一个简单直接的可持续的方法来处理异步非阻塞式计算和 I/O。在响应式编程中,因活动(active)组件之间通常不需要明确的协作,从而也就解决了其中大部分的挑战。
响应式编程真正的发光点在于组件的创建跟工作流的组合。为了在异步执行上取得最大的优势,把(back-pressure)加进来是很重要,这样能避免过度使用,或者确切地说,避免无限度的消耗资源。
尽管如此,响应式编程在搭建现代软件上仍然非常有用,为了在更高层次上理解(reason about)一个系统,那么必须要使用到另一个工具:响应式架构reactive architecture&&设计响应式系统的方法。此外,要记住编程范式有很多,而响应式编程仅仅只是其中一个,所以如同其它工具一样,响应式编程并不是万金油,它不意图适用于任何情况。
事件驱动 vs. 消息驱动
如上面提到的,响应式编程&&专注于短时间的数据流链条上的计算&&因此倾向于事件驱动,而响应式系统&&关注于通过分布式系统的通信和协作所得到的弹性和韧性&&则是 脚注4 (或者称之为 消息式(messaging)&的)。
一个拥有长期存活的可寻址(long-lived addressable)组件的消息驱动系统跟一个事件驱动的数据流驱动模型的不同在于,消息具有固定的导向,而事件则没有。消息会有明确的(一个)去向,而事件则只是一段等着被观察(observe)的信息。另外,消息式(messaging)更适用于异步,因为消息的发送与接收和发送者和接收者是分离的。
响应式宣言中的术语表定义了两者之间:
一条消息就是一则被送往一个明确目的地的数据。一个事件则是达到某个给定状态的组件发出的一个信号。在一个消息驱动系统中,可寻址到的接收者等待消息的到来然后响应它,否则保持休眠状态。在一个事件驱动系统中,通知的监听者被绑定到消息源上,这样当消息被发出时它就会被调用。这意味着一个事件驱动系统专注于可寻址的事件源而消息驱动系统专注于可寻址的接收者。
分布式系统需要通过消息在网络上传输进行交流,以实现其沟通基础,与之相反,事件的发出则是本地的。在底层通过发送包裹着事件的消息来搭建跨网络的事件驱动系统的做法很常见。这样能够维持在分布式环境下事件驱动编程模型的相对简易性,并且在某些特殊的和合理的范围内的使用案例上工作得很好。
然而,这是有利有弊的:在编程模型的抽象性和简易性上得一分,在控制上就减一分。消息强迫我们去拥抱分布式系统的真实性和一致性&&像局部错误(partial failures),错误侦测(failure detection),丢弃/复制/重排序(dropped/duplicated/reordered)消息,最后还有一致性,管理多个并发真实性等等&&然后直面它们,去处理它们,而不是像过去无数次一样,藏在一个蹩脚的抽象面罩后&&假装网络并不存在(例如EJB、&、& 和&)。
这些在语义学和适用性上的不同在应用设计中有着深刻的含义,包括分布式系统的复杂性(complexity)中的 弹性(resilience)、 韧性(elasticity)、移动性(mobility)、位置透明性(location transparency)和 管理(management),这些在文章后面再进行介绍。
在一个响应式系统中,特别是使用了响应式编程技术的,这样的系统中就即有事件也有消息&&一个是用于沟通的强大工具(消息),而另一个则呈现现实(事件)。
响应式系统和架构
响应式系统 && 如同在《响应式宣言》中定义的那样&&是一组用于搭建现代系统&&已充分准备好满足如今应用程序所面对的不断增长的需求的现代系统&&的架构设计原则。
响应式系统的原则决对不是什么新东西,它可以被追溯到 70 和 80 年代 Jim Gray 和 Pat Helland 在(Tandem System)上和 Joe aomstrong 和 Robert Virding 在
上做出的重大工作。然而,这些人在当时都超越了时代,只有到了最近 5 - 10 年,技术行业才被不得不反思当前企业系统最好的开发实践活动并且学习如何将来之不易的响应式原则应用到今天这个多核、云计算和物联网的世界中。
响应式系统的基石是消息传递(message-passing),消息传递为两个组件之间创建一条暂时的边界,使得它们能够在 时间 上分离&&实现并发性&&和 空间(space)&&&实现分布式(distribution)与移动性(mobility)。这种分离是两个组件完全(isolation)以及实现 弹性(resilience)和 韧性(elasticity)基础的必需条件。
从程序到系统
这个世界的连通性正在变得越来越高。我们不再构建 程序 &&为单个操作子来计算某些东西的端到端逻辑&&而更多地在构建 系统 了。
系统从定义上来说是复杂的&&每一部分都包含多个组件,每个组件的自身或其子组件也可以是一个系统&&这意味着软件要正常工作已经越来越依赖于其它软件。
我们今天构建的系统会在多个计算机上操作,小型的或大型的,或少或多,相近的或远隔半个地球的。同时,由于人们的生活正变得越来越依赖于系统顺畅运行的有效性,用户的期望也变得越得越来越难以满足。
为了实现用户&&和企业&&能够依赖的系统,这些系统必须是 灵敏的(responsive)&,这样无论是某个东西提供了一个正确的响应,还是当需要一个响应时响应无法使用,都不会有影响。为了达到这一点,我们必须保证在错误( 弹性 )和欠载( 韧性 )下,系统仍然能够保持灵敏性。为了实现这一点,我们把系统设计为 消息驱动的 ,我们称其为 响应式系统 。
响应式系统的弹性
弹性是与 错误下 的灵敏性(responsiveness)有关的,它是系统内在的功能特性,是需要被设计的东西,而不是能够被动的加入系统中的东西。弹性是大于容错性的&&弹性无关于故障退化(graceful degradation)&&虽然故障退化对于系统来说是很有用的一种特性&&与弹性相关的是与从错误中完全恢复达到 自愈 的能力。这就需要组件的隔离以及组件对错误的包容,以免错误散播到其相邻组件中去&&否则,通常会导致灾难性的连锁故障。
因此构建一个弹性的、自愈(self-healing)系统的关键是允许错误被:容纳、具体化为消息,发送给其他(担当监管者(supervisors))的组件,从而在错误组件之外修复出一个安全环境。在这,消息驱动是其促成因素:远离高度耦合的、脆弱的深层嵌套的同步调用链,大家长期要么学会忍受其煎熬或直接忽略。解决的想法是将调用链中的错误管理分离,将客户端从处理服务端错误的责任中解放出来。
响应式系统的韧性
(Elasticity)是关于 欠载下的灵敏性(responsiveness)&的&&意味着一个系统的吞吐量在资源增加或减少时能够自动地相应增加或减少(scales up or down)(同样能够向内或外扩展(scales in or out))以满足不同的需求。这是利用云计算承诺的特性所必需的因素:使系统利用资源更加有效,成本效益更佳,对环境友好以及实现按次付费。
系统必须能够在不重写甚至不重新设置的情况下,适应性地&&即无需介入自动伸缩&&响应状态及行为,沟通负载均衡,故障转移(failover),以及升级。实现这些的就是 位置透明性(location transparency):使用同一个方法,同样的编程抽象,同样的语义,在所有向度中伸缩(scaling)系统的能力&&从 CPU 核心到数据中心。
如同《响应式宣言》所述:
一个极大地简化问题的关键洞见在于意识到我们都在使用分布式计算。无论我们的操作系统是运行在一个单一结点上(拥有多个独立的 CPU,并通过 QPI 链接进行交流),还是在一个节点集群(cluster of nodes)(独立的机器,通过网络进行交流)上。拥抱这个事实意味着在垂直方向上多核的伸缩与在水平方面上集群的伸缩并无概念上的差异。在空间上的解耦 [...],是通过异步消息传送以及运行时实例与其引用解耦从而实现的,这就是我们所说的位置透明性。
因此,不论接收者在哪里,我们都以同样的方式与它交流。唯一能够在语义上等同实现的方式是消息传送。
响应式系统的生产效率
既然大多数的系统生来即是复杂的,那么其中一个最重要的点即是保证一个系统架构在开发和维护组件时,最小程度地减低生产效率,同时将操作的 偶发复杂性(accidental complexity)降到最低。
这一点很重要,因为在一个系统的生命周期中&&如果系统的设计不正确&&系统的维护会变得越来越困难,理解、定位和解决问题所需要花费时间和精力会不断地上涨。
响应式系统是我们所知的最具 生产效率 的系统架构(在多核、云及移动架构的背景下):
错误的隔离为组件与组件之间裹上(LCTT 译注:当船遭到损坏进水时,舱壁能够防止水从损坏的船舱流入其他船舱),防止引发连锁错误,从而限制住错误的波及范围以及严重性。
监管者的层级制度提供了多个等级的防护,搭配以自我修复能力,避免了许多曾经在侦查(inverstigate)时引发的操作代价(cost)&&大量的瞬时故障(transient failures)。
消息传送和位置透明性允许组件被卸载下线、代替或重新布线(rerouted)同时不影响终端用户的使用体验,并降低中断的代价、它们的相对紧迫性以及诊断和修正所需的资源。
复制减少了数据丢失的风险,减轻了数据检索(retrieval)和存储的有效性错误的影响。
韧性允许在使用率波动时保存资源,允许在负载很低时,最小化操作开销,并且允许在负载增加时,最小化运行中断(outgae)或紧急投入(urgent investment)伸缩性的风险。
因此,响应式系统使生成系统(creation systems)很好的应对错误、随时间变化的负载&&同时还能保持低运营成本。
响应式编程与响应式系统的关联
响应式编程是一种管理内部逻辑(internal logic)和数据流转换(dataflow transformation)的好技术,在本地的组件中,做为一种优化代码清晰度、性能以及资源利用率的方法。响应式系统,是一组架构上的原则,旨在强调分布式信息交流并为我们提供一种处理分布式系统弹性与韧性的工具。
只使用响应式编程常遇到的一个问题,是一个事件驱动的基于回调的或声明式的程序中两个计算阶段的高度耦合(tight coupling),使得 弹性 难以实现,因此时它的转换链通常存活时间短,并且它的各个阶段&&回调函数或组合子(combinator)&&是匿名的,也就是不可寻址的。
这意味着,它通常在内部处理成功与错误的状态而不会向外界发送相应的信号。这种寻址能力的缺失导致单个阶段(stages)很难恢复,因为它通常并不清楚异常应该,甚至不清楚异常可以,发送到何处去。
另一个与响应式系统方法的不同之处在于单纯的响应式编程允许 时间 上的解耦(decoupling),但不允许 空间 上的(除非是如上面所述的,在底层通过网络传送消息来分发(distribute)数据流)。正如叙述的,在时间上的解耦使 并发性 成为可能,但是是空间上的解耦使 分布(distribution)和 移动性(mobility)&(使得不仅仅静态拓扑可用,还包括了动态拓扑)成为可能的&&而这些正是 韧性 所必需的要素。
位置透明性的缺失使得很难以韧性方式对一个基于适应性响应式编程技术的程序进行向外扩展,因为这样就需要分附加工具,例如消息总线(message bus),数据网格(data grid)或者在顶层的定制网络协议(bespoke network protocol)。而这点正是响应式系统的消息驱动编程的闪光的地方,因为它是一个包含了其编程模型和所有伸缩向度语义的交流抽象概念,因此降低了复杂性与认知超载。
对于基于回调的编程,常会被提及的一个问题是写这样的程序或许相对来说会比较简单,但最终会引发一些真正的后果。
例如,对于基于匿名回调的系统,当你想理解它们,维护它们或最重要的是在生产供应中断(production outages)或错误行为发生时,你想知道到底发生了什么、发生在哪以及为什么发生,但此时它们只提供极少的内部信息。
为响应式系统设计的库与平台(例如&&项目和&&平台)学到了这一点,它们依赖于那些更容易理解的长期存活的可寻址组件。当错误发生时,根据导致错误的消息可以找到唯一的组件。当可寻址的概念存在组件模型的核心中时,监控方案(monitoring solution)就有了一个 有意义 的方式来呈现它收集的数据&&利用传播(propagated)的身份标识。
一个好的编程范式的选择,一个选择实现像可寻址能力和错误管理这些东西的范式,已经被证明在生产中是无价的,因它在设计中承认了现实并非一帆风顺,接受并拥抱错误的出现 而不是毫无希望地去尝试避免错误。
总而言之,响应式编程是一个非常有用的实现技术,可以用在响应式架构当中。但是记住这只能帮助管理一部分:异步且非阻塞执行下的数据流管理&&通常只在单个结点或服务中。当有多个结点时,就需要开始认真地考虑像数据一致性(data consistency)、跨结点沟通(cross-node communication)、协调(coordination)、版本控制(versioning)、编制(orchestration)、错误管理(failure management)、关注与责任(concerns and responsibilities)分离等等的东西&&也即是:系统架构。
因此,要最大化响应式编程的价值,就把它作为构建响应式系统的工具来使用。构建一个响应式系统需要的不仅是在一个已存在的遗留下来的软件栈(software stack)上抽象掉特定的操作系统资源和少量的异步 API 和(circuit breakers)。此时应该拥抱你在创建一个包含多个服务的分布式系统这一事实&&这意味着所有东西都要共同合作,提供一致性与灵敏的体验,而不仅仅是如预期工作,但同时还要在发生错误和不可预料的负载下正常工作。
企业和中间件供应商在目睹了应用响应式所带来的企业利润增长后,同样开始拥抱响应式。在本文中,我们把响应式系统做为企业最终目标进行描述&&假设了多核、云和移动架构的背景&&而响应式编程则从中担任重要工具的角色。
响应式编程在内部逻辑及数据流转换的组件层次上为开发者提高了生产率&&通过性能与资源的有效利用实现。而响应式系统在构建 原生云(cloud native)&和其它大型分布式系统的系统层次上为架构师及 DevOps 从业者提高了生产率&&通过弹性与韧性。我们建议在响应式系统设计原则中结合响应式编程技术。
参考 Conal Elliott,FRP 的发明者,见。
揭示了系统理论上的加速会被一系列的子部件限制,这意味着系统在新的资源加入后会出现收益递减(diminishing returns)。&
Neil G&nter 的(Universal Scalability Law)是理解并发与分布式系统的竞争与协作的重要工具,它揭示了当新资源加入到系统中时,保持一致性的开销会导致不好的结果。
消息可以是同步的(要求发送者和接受者同时存在),也可以是异步的(允许他们在时间上解耦)。其语义上的区别超出本文的讨论范围。
译者: 校对:
组织编译, 荣誉推出
上一篇:下一篇:
评论功能关闭
根据国家法律法规要求,本站暂时关闭文章评论功能。开放时间不确定。我们将谋求一种可以让大家更好的发表意见的方式。
根据国家法律法规要求,只有实名认证后才可以发表评论。
共计翻译: 10 篇
| 共计贡献: 647 天
贡献时间: -&
在恒久的迷惑与过多期待的海洋中,登上一组简单响应式设计原则的小岛。
分享到微信
打开微信,点击顶部的“╋”,
使用“扫一扫”将网页分享至微信。
请将我们加入您的广告过滤器的白名单,请支持开源站点。谢谢您。你的对象可能是个函数!Max 函数式编程学习7 months ago得到 multiClickStream 后,subscribe 它,就可以监听到数据流中的值:multiClickStream.subscribe(function (numclicks) {
console.log(numclicks);
上述对 stream 的函数式操作,去掉换行后: “stream.buffer().map().filter()”连起来看丝般顺滑。如果把 “.” 改为 “-”:“stream - buffer() - map() - filter()”是不是看着跟连连看编程很像了?以
为例:上图即是那段 RxJS 代码的
版本,功能一样的。一次单击时,并不会从 stream 最后输出,最后的 print log 里显示的仍是之前的一次3连击。如果来一发4连击,则会通过 filter,最终得到: 可以看到,上图中绿色部分的 map 与 filter,细节的处理并不太“函数式”,还是像在用命令式告诉机器如何执行指令,而不是优雅的书写函数。伯克利大学的新音乐与音频技术研究中心,Center for New Music and Audio Technologies (CNMAT),设计开发了一套 Max 的 Library —— ODOT。ODOT 基于 OSC,就是那个熟悉的 Open Sound Control。首先,重点在于利用了 OSC 对数据的封装格式,name - value 结构。其次,OSC 数据可以方便的在程序内从一个模块流向另一个模块,甚至从硬件 Arduino,通过网络,流向 Max、Processing、C、Java 等软件模块。用 ODOT 重构上文的 map 与 filter 模块,如下图所示: o.pack 是把流入的 stream 数据,封装成 OSC 格式。而后边两句,就是很直观的函数书写了:/data = length(/data) ; //取长度
o.if /data &= 2 ; //过滤2以上的数据。
ODOT 还可以实现更多函数式特征的功能。高阶函数: 递归:此图自下方参考论文另,利用 OSC 数据结构,ODOT 其实还可以实现面向对象的风格,可参考下方论文。ODOT 下载:参考论文:谢谢阅读。-----------------------不要慌,再回味一下开篇定场诗里的精华:Today 500 bugs will be fixed, tomorrow another 500 will appear.微信公众号:浮生开方 on Slack: 赞赏还没有人赞赏,快来当第一个赞赏的人吧!1收藏分享举报文章被以下专栏收录不要方,真青年是不会方的。推荐阅读{&debug&:false,&apiRoot&:&&,&paySDK&:&https:\u002F\\u002Fapi\u002Fjs&,&wechatConfigAPI&:&\u002Fapi\u002Fwechat\u002Fjssdkconfig&,&name&:&production&,&instance&:&column&,&tokens&:{&X-XSRF-TOKEN&:null,&X-UDID&:null,&Authorization&:&oauth c3cef7c66aa9e6a1e3160e20&}}{&database&:{&Post&:{&&:{&isPending&:false,&contributes&:[{&sourceColumn&:{&lastUpdated&:,&description&:&Creative coder's gossip.&,&permission&:&COLUMN_PUBLIC&,&memberId&:69330,&contributePermission&:&COLUMN_PUBLIC&,&translatedCommentPermission&:&all&,&canManage&:true,&intro&:&不要方,真青年是不会方的。&,&urlToken&:&floatlab&,&id&:28550,&imagePath&:&v2-2eaeba7a2a123eb4d15f.jpg&,&slug&:&floatlab&,&applyReason&:&0&,&name&:&浮生开方&,&title&:&浮生开方&,&url&:&https:\u002F\\u002Ffloatlab&,&commentPermission&:&COLUMN_ALL_CAN_COMMENT&,&canPost&:true,&created&:,&state&:&COLUMN_NORMAL&,&followers&:13,&avatar&:{&id&:&v2-2eaeba7a2a123eb4d15f&,&template&:&https:\u002F\\u002F{id}_{size}.jpg&},&activateAuthorRequested&:false,&following&:false,&imageUrl&:&https:\u002F\\u002Fv2-2eaeba7a2a123eb4d15f_l.jpg&,&articlesCount&:7},&state&:&accepted&,&targetPost&:{&titleImage&:&https:\u002F\\u002Fv2-9067b7abbdb73ea3ed3d_r.jpg&,&lastUpdated&:,&imagePath&:&v2-9067b7abbdb73ea3ed3d.jpg&,&permission&:&ARTICLE_PUBLIC&,&topics&:[,164465],&summary&:&先来一首定场诗:There is a cycle, a rhythm to the universe.Today one program will be popular, tomorrow another.\u003Cstrong\u003EToday 500 bugs will be fixed, tomorrow another 500 will appear.\u003C\u002Fstrong\u003ETo understand life is to know that the rhythm exists.To understa…&,&copyPermission&:&ARTICLE_COPYABLE&,&translatedCommentPermission&:&all&,&likes&:0,&origAuthorId&:0,&publishedTime&:&T20:00:46+08:00&,&sourceUrl&:&&,&urlToken&:,&id&:2736215,&withContent&:false,&slug&:,&bigTitleImage&:false,&title&:&你的对象可能是个函数!Max 函数式编程学习&,&url&:&\u002Fp\u002F&,&commentPermission&:&ARTICLE_ALL_CAN_COMMENT&,&snapshotUrl&:&&,&created&:,&comments&:0,&columnId&:28550,&content&:&&,&parentId&:0,&state&:&ARTICLE_PUBLISHED&,&imageUrl&:&https:\u002F\\u002Fv2-9067b7abbdb73ea3ed3d_r.jpg&,&author&:{&bio&:&Creative Coder@INT++ n' Float Lab&,&isFollowing&:false,&hash&:&2a55fb1b7f5995d9fdad7e818e61599a&,&uid&:20,&isOrg&:false,&slug&:&contra&,&isFollowed&:false,&description&:&Creative Coder@INT++ n' Float Lab.\nApp, web, game, audio, visual, VR\u002FAR.\nInteraction installation, projection, immersive experience, exhibition.\n\n公众号:浮生开方、浮生插电\n网站:http:\u002F\u002Ffloat.cc&,&name&:&Contra&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Fcontra&,&avatar&:{&id&:&v2-82b2a141501fad65c33f78f4061b8ddb&,&template&:&https:\u002F\\u002F50\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},&memberId&:69330,&excerptTitle&:&&,&voteType&:&ARTICLE_VOTE_CLEAR&},&id&:614189}],&title&:&你的对象可能是个函数!Max 函数式编程学习&,&author&:&contra&,&content&:&\u003Cp\u003E先来一首定场诗:\u003C\u002Fp\u003E\u003Cp\u003EThere is a cycle, a rhythm to the universe.\u003C\u002Fp\u003E\u003Cp\u003EToday one program will be popular, tomorrow another.\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003EToday 500 bugs will be fixed, tomorrow another 500 will appear.\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003ETo understand life is to know that the rhythm exists.\u003C\u002Fp\u003E\u003Cp\u003ETo understand Zen is to live outside this rhythm,\u003C\u002Fp\u003E\u003Cp\u003Edetached from the everyday concerns of life.\u003C\u002Fp\u003E\u003Cp\u003EOnly then can the mind be free.\u003C\u002Fp\u003E\u003Cp\u003E---- 摘自《The Tao of Programming(编程之道)》\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cbr\u003E\u003Cp\u003E\u003Cstrong\u003E面向对象编程\u003C\u002Fstrong\u003E(Object-Oriented Programming - OOP)理论认为,“\u003Cstrong\u003E万物皆对象\u003C\u002Fstrong\u003E”。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cem\u003E不是搞对象的对象。\u003Cbr\u003E\u003C\u002Fem\u003E\u003Cem\u003E其实严格地说,搞对象的对象,好像也是对象。\u003C\u002Fem\u003E\u003C\u002Fp\u003E\u003Cp\u003E面向对象可能是学校和企业产品上使用最多的编程范式。\u003Cbr\u003E一旦被洗脑,很难掰回来。如:\u003Cstrong\u003E对象说的永远是对的。\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cbr\u003E\u003Cp\u003E近几年开始接触和使用\u003Cstrong\u003E函数式响应式编程\u003C\u002Fstrong\u003E(Functional Reactive Programming - FRP)。\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cp\u003EFRP组合了响应式编程(Reactive Programming - RP)与函数式编程(Functional Programming - FP)。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E响应式编程\u003C\u002Fstrong\u003E RP:侧重于处理异步数据流,可以监听数据流并做出响应。
\u003C\u002Fp\u003E\u003Cp\u003E比如Excel的单元格,可以包含类似\&=B1+C1\&的公式,这类单元格的值会依据其他单元格(B1和C1)的值的变化而变化 。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\\u002Fv2-99ba217b2b6d9b381f3c_b.png\& data-rawwidth=\&1280\& data-rawheight=\&720\& class=\&origin_image zh-lightbox-thumb\& width=\&1280\& data-original=\&https:\u002F\\u002Fv2-99ba217b2b6d9b381f3c_r.png\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='1280'%20height='720'&&\u002Fsvg&\& data-rawwidth=\&1280\& data-rawheight=\&720\& class=\&origin_image zh-lightbox-thumb lazy\& width=\&1280\& data-original=\&https:\u002F\\u002Fv2-99ba217b2b6d9b381f3c_r.png\& data-actualsrc=\&https:\u002F\\u002Fv2-99ba217b2b6d9b381f3c_b.png\&\u003E\u003Ci\u003E图片出处见水印\u003C\u002Fi\u003E\u003C\u002Fp\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\\u002Fv2-b1a119bba5e1ec8e20ce25_b.jpg\& data-rawwidth=\&1366\& data-rawheight=\&768\& class=\&origin_image zh-lightbox-thumb\& width=\&1366\& data-original=\&https:\u002F\\u002Fv2-b1a119bba5e1ec8e20ce25_r.jpg\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='1366'%20height='768'&&\u002Fsvg&\& data-rawwidth=\&1366\& data-rawheight=\&768\& class=\&origin_image zh-lightbox-thumb lazy\& width=\&1366\& data-original=\&https:\u002F\\u002Fv2-b1a119bba5e1ec8e20ce25_r.jpg\& data-actualsrc=\&https:\u002F\\u002Fv2-b1a119bba5e1ec8e20ce25_b.jpg\&\u003E\u003Cp\u003E响应式编程处理流、监听流、根据流迅速做出响应。\u003Cbr\u003E这一点,我在幼年自学截拳道时就懂了:\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E“Be water, my friend. ”\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cbr\u003E\u003Cp\u003E\u003Cstrong\u003E函数式编程 \u003C\u002Fstrong\u003EFP:更像是在做数学运算。\u003Cbr\u003E“把运算过程尽量写成一系列嵌套的函数调用”(\u003Ca href=\&http:\u002F\\u002F?target=http%3A\u002F\\u002Fblog\u002F\u002Ffunctional_programming.html\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003E函数式编程初探 - 阮一峰的网络日志\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E)。\u003C\u002Fp\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\\u002Fv2-d1fead78c_b.png\& data-rawwidth=\&450\& data-rawheight=\&220\& class=\&origin_image zh-lightbox-thumb\& width=\&450\& data-original=\&https:\u002F\\u002Fv2-d1fead78c_r.png\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='450'%20height='220'&&\u002Fsvg&\& data-rawwidth=\&450\& data-rawheight=\&220\& class=\&origin_image zh-lightbox-thumb lazy\& width=\&450\& data-original=\&https:\u002F\\u002Fv2-d1fead78c_r.png\& data-actualsrc=\&https:\u002F\\u002Fv2-d1fead78c_b.png\&\u003E\u003Cp\u003E注意,上图函数 f(x) 的输入参数 x,也可以是另一个函数。\u003C\u002Fp\u003E\u003Cp\u003E尽管对\u003Cstrong\u003E函数式响应式编程\u003C\u002Fstrong\u003E FRP 不算太陌生,也曾使用 ReactCocoa Objective-C 上线过几款 App,将 signal,map,subscribe 等等用的不亦乐乎。\u003C\u002Fp\u003E\u003Cp\u003E但是\u003Cstrong\u003E从 “万物皆对象”,切换到 “万物皆函数”\u003C\u002Fstrong\u003E,还是有点懵。\u003C\u002Fp\u003E\u003Cp\u003E尤其在融会贯通了 OOP 和 FP 后,想到“\u003Cstrong\u003E其实你的对象是个函数\u003C\u002Fstrong\u003E”,更是大写的锟斤拷烫烫烫。 \u003Cbr\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\\u002Fv2-1b8e971d4ea28e2a197e3_b.png\& data-rawwidth=\&500\& data-rawheight=\&326\& class=\&origin_image zh-lightbox-thumb\& width=\&500\& data-original=\&https:\u002F\\u002Fv2-1b8e971d4ea28e2a197e3_r.png\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='500'%20height='326'&&\u002Fsvg&\& data-rawwidth=\&500\& data-rawheight=\&326\& class=\&origin_image zh-lightbox-thumb lazy\& width=\&500\& data-original=\&https:\u002F\\u002Fv2-1b8e971d4ea28e2a197e3_r.png\& data-actualsrc=\&https:\u002F\\u002Fv2-1b8e971d4ea28e2a197e3_b.png\&\u003E\u003Cem\u003E图片出处见水印\u003C\u002Fem\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cbr\u003E\u003Cp\u003E所以还是把理论丢一边,例子摆中间:\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\\u002Fv2-069d2d91c5c9a6a3190bff9c2b481c8f_b.png\& data-rawwidth=\&512\& data-rawheight=\&719\& class=\&origin_image zh-lightbox-thumb\& width=\&512\& data-original=\&https:\u002F\\u002Fv2-069d2d91c5c9a6a3190bff9c2b481c8f_r.png\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='512'%20height='719'&&\u002Fsvg&\& data-rawwidth=\&512\& data-rawheight=\&719\& class=\&origin_image zh-lightbox-thumb lazy\& width=\&512\& data-original=\&https:\u002F\\u002Fv2-069d2d91c5c9a6a3190bff9c2b481c8f_r.png\& data-actualsrc=\&https:\u002F\\u002Fv2-069d2d91c5c9a6a3190bff9c2b481c8f_b.png\&\u003E\u003Cp\u003E此图源自很火的一篇 FRP 教程:\u003Cbr\u003E《The introduction to Reactive Programming you've been missing》\u003Cbr\u003E\u003Ca href=\&http:\u002F\\u002F?target=https%3A\u002F\\u002Fstaltz\u002F868e7e9bc2a7b8c1f754\& class=\& external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003E\u003Cspan class=\&invisible\&\u003Ehttps:\u002F\u002F\u003C\u002Fspan\u003E\u003Cspan class=\&visible\&\\u002Fstaltz\u002F\u003C\u002Fspan\u003E\u003Cspan class=\&invisible\&\u003E868e7e9bc2a7b8c1f754\u003C\u002Fspan\u003E\u003Cspan class=\&ellipsis\&\u003E\u003C\u002Fspan\u003E\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E\u003C\u002Fp\u003E\u003Cp\u003E图中的黑色箭头线条,即代表 stream,数据流。\u003C\u002Fp\u003E\u003Cblockquote\u003E\u003Cp\u003E “灰色的矩形是把一个 stream 转换成另一个 stream 的函数。我们会每隔 250ms 把所有 click stream 都缓冲在一个数组里面,这是 buffer(stream.throttle(250ms)) 所要做的事情。\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cp\u003E于是,我们得到的是一个包含多个数组的 stream,接着调用 map() 函数,把每个数组都映射成一个整数(数组的长度)。\u003C\u002Fp\u003E\u003Cp\u003E随后,我们调用 filter(x &= 2) 来过滤掉那些长度为 1 的数组。\u003C\u002Fp\u003E\u003Cp\u003E综上,我们只需要3次操作就能得到我们想要的 stream 。最后,我们调用 subscribe() 来监听,响应我们想要做的事情。”\u003Cbr\u003E\u003C\u002Fp\u003E\u003C\u002Fblockquote\u003E\u003Cp\u003E此段引自知乎。\u003Cbr\u003E\u003Ca href=\&https:\u002F\\u002Fp\u002F\& class=\&internal\&\u003E可能是最好的 Rx 初学者教程 - 知乎专栏\u003C\u002Fa\u003E\u003C\u002Fp\u003E\u003Cp\u003E实现这一段数据流的转换,用 RxJS 来写的话,只需要这样4行:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Evar multiClickStream = clickStream\n
.buffer(function() { return clickStream.throttle(250); })\n
.map(function(list) { return list. })\n
.filter(function(x) { return x &= 2; });\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E得到 multiClickStream 后,subscribe 它,就可以监听到数据流中的值:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003EmultiClickStream.subscribe(function (numclicks) {\n
console.log(numclicks);\n)};\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cbr\u003E\u003Cp\u003E上述对 stream 的函数式操作,去掉换行后: \u003Cbr\u003E“\u003Cstrong\u003Estream.buffer().map().filter()\u003C\u002Fstrong\u003E”\u003Cbr\u003E连起来看丝般顺滑。\u003C\u002Fp\u003E\u003Cp\u003E如果把 “.” 改为 “-”:\u003Cbr\u003E“\u003Cstrong\u003Estream - buffer() - map() - filter()\u003C\u002Fstrong\u003E”\u003Cbr\u003E是不是看着跟连连看编程很像了?\u003C\u002Fp\u003E\u003Cp\u003E以 \u003Ca href=\&http:\u002F\\u002F?target=https%3A\\u002F\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003EMax\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E 为例:\u003C\u002Fp\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\\u002Fv2-2373ecedacb3ee39532a_b.png\& data-rawwidth=\&410\& data-rawheight=\&675\& class=\&content_image\& width=\&410\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='410'%20height='675'&&\u002Fsvg&\& data-rawwidth=\&410\& data-rawheight=\&675\& class=\&content_image lazy\& width=\&410\& data-actualsrc=\&https:\u002F\\u002Fv2-2373ecedacb3ee39532a_b.png\&\u003E\u003Cp\u003E上图即是那段 RxJS 代码的 \u003Ca href=\&http:\u002F\\u002F?target=https%3A\\u002F\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003EMax\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E 版本,功能一样的。\u003Cbr\u003E一次单击时,并不会从 stream 最后输出,最后的 print log 里显示的仍是之前的一次3连击。\u003C\u002Fp\u003E\u003Cp\u003E如果来一发4连击,则会通过 filter,最终得到: \u003C\u002Fp\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\\u002Fv2-0602979cfdbf18c316f3f_b.png\& data-rawwidth=\&416\& data-rawheight=\&266\& class=\&content_image\& width=\&416\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='416'%20height='266'&&\u002Fsvg&\& data-rawwidth=\&416\& data-rawheight=\&266\& class=\&content_image lazy\& width=\&416\& data-actualsrc=\&https:\u002F\\u002Fv2-0602979cfdbf18c316f3f_b.png\&\u003E\u003Cp\u003E可以看到,上图中绿色部分的 map 与 filter,细节的处理并不太“函数式”,还是像在用命令式告诉机器如何执行指令,而不是优雅的书写函数。\u003Cbr\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cp\u003E伯克利大学的新音乐与音频技术研究中心,Center for New Music and Audio Technologies (\u003Cb\u003ECNMAT\u003C\u002Fb\u003E),设计开发了一套 Max 的 Library —— \u003Cb\u003EODOT\u003C\u002Fb\u003E。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cb\u003EODOT 基于 OSC\u003C\u002Fb\u003E,就是那个熟悉的 Open Sound Control。\u003C\u002Fp\u003E\u003Cp\u003E首先,重点在于利用了 OSC 对数据的封装格式,name - value 结构。\u003C\u002Fp\u003E\u003Cp\u003E其次,OSC 数据可以方便的在程序内从一个模块流向另一个模块,甚至从硬件 Arduino,通过网络,流向 Max、Processing、C、Java 等软件模块。\u003C\u002Fp\u003E\u003Cp\u003E用 ODOT 重构上文的 map 与 filter 模块,如下图所示: \u003C\u002Fp\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\\u002Fv2-d5ae6d80b57bd2fd38f458_b.png\& data-rawwidth=\&499\& data-rawheight=\&224\& class=\&origin_image zh-lightbox-thumb\& width=\&499\& data-original=\&https:\u002F\\u002Fv2-d5ae6d80b57bd2fd38f458_r.png\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='499'%20height='224'&&\u002Fsvg&\& data-rawwidth=\&499\& data-rawheight=\&224\& class=\&origin_image zh-lightbox-thumb lazy\& width=\&499\& data-original=\&https:\u002F\\u002Fv2-d5ae6d80b57bd2fd38f458_r.png\& data-actualsrc=\&https:\u002F\\u002Fv2-d5ae6d80b57bd2fd38f458_b.png\&\u003E\u003Cp\u003Eo.pack 是把流入的 stream 数据,封装成 OSC 格式。\u003Cbr\u003E而后边两句,就是很直观的函数书写了:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u002Fdata = length(\u002Fdata) ; \u002F\u002F取长度\n\no.if \u002Fdata &= 2 ; \u002F\u002F过滤2以上的数据。\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cbr\u003E\u003Cp\u003E\u003Cstrong\u003EODOT 还可以实现更多函数式特征的功能\u003C\u002Fstrong\u003E。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E高阶函数\u003C\u002Fstrong\u003E: \u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\\u002Fv2-c1fb931c87ac13b5f75dc5e858a3b6bb_b.png\& data-rawwidth=\&284\& data-rawheight=\&139\& class=\&content_image\& width=\&284\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='284'%20height='139'&&\u002Fsvg&\& data-rawwidth=\&284\& data-rawheight=\&139\& class=\&content_image lazy\& width=\&284\& data-actualsrc=\&https:\u002F\\u002Fv2-c1fb931c87ac13b5f75dc5e858a3b6bb_b.png\&\u003E\u003Cstrong\u003E递归\u003C\u002Fstrong\u003E:\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\\u002Fv2-b05e52d3d96fcbe87580c28fdd822f1b_b.png\& data-rawwidth=\&492\& data-rawheight=\&150\& class=\&origin_image zh-lightbox-thumb\& width=\&492\& data-original=\&https:\u002F\\u002Fv2-b05e52d3d96fcbe87580c28fdd822f1b_r.png\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='492'%20height='150'&&\u002Fsvg&\& data-rawwidth=\&492\& data-rawheight=\&150\& class=\&origin_image zh-lightbox-thumb lazy\& width=\&492\& data-original=\&https:\u002F\\u002Fv2-b05e52d3d96fcbe87580c28fdd822f1b_r.png\& data-actualsrc=\&https:\u002F\\u002Fv2-b05e52d3d96fcbe87580c28fdd822f1b_b.png\&\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\\u002Fv2-bf073efef27feb7b0995622bde159265_b.png\& data-rawwidth=\&359\& data-rawheight=\&244\& class=\&content_image\& width=\&359\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='359'%20height='244'&&\u002Fsvg&\& data-rawwidth=\&359\& data-rawheight=\&244\& class=\&content_image lazy\& width=\&359\& data-actualsrc=\&https:\u002F\\u002Fv2-bf073efef27feb7b0995622bde159265_b.png\&\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cem\u003E此图自下方参考论文\u003C\u002Fem\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cbr\u003E\u003Cp\u003E另,利用 OSC 数据结构,\u003Cstrong\u003EODOT 其实还可以实现面向对象的风格\u003C\u002Fstrong\u003E,可参考下方论文。\u003Cbr\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003EODOT 下载\u003C\u002Fstrong\u003E:\u003Cbr\u003E\u003Ca href=\&http:\u002F\\u002F?target=http%3A\u002F\u002Fcnmat.berkeley.edu\u002Fdownloads\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003EDownloads | CNMAT\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E参考论文\u003C\u002Fstrong\u003E:\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Ca href=\&http:\u002F\\u002F?target=http%3A\u002F\\u002Fwritings\u002Fodot_nime_Fodot_nime_2011.pdf\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003E《Composability for Musical Gesture Signal Processing using new OSC-based Object and Functional Programming Extensions to Max\u002FMSP》\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Ca href=\&http:\u002F\\u002F?target=http%3A\u002F\u002Fquod.lib.umich.edu\u002Fcgi\u002Fp\u002Fpod\u002Fdod-idx\u002Fdynamic-instance-based-object-oriented-programming-in-maxmsp.pdf%3Fc%3Dicmc%3Bidno%3Dbbp9\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003E《DYNAMIC, INSTANCE-BASED, OBJECT-ORIENTED PROGRAMMING IN MAX\u002FMSP USING OPEN SOUND CONTROL MESSAGE DELEGATION》\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E\u003Cbr\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cbr\u003E谢谢阅读。\u003C\u002Fp\u003E\u003Cp\u003E-----------------------\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cp\u003E不要慌,再回味一下开篇定场诗里的精华:\u003Cbr\u003E\u003Cb\u003EToday 500 bugs will be fixed, tomorrow another 500 will appear.\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\\u002Fv2-ddec646d2caf72aa372c7a4ecb46bfb7_b.png\& data-rawwidth=\&596\& data-rawheight=\&598\& class=\&origin_image zh-lightbox-thumb\& width=\&596\& data-original=\&https:\u002F\\u002Fv2-ddec646d2caf72aa372c7a4ecb46bfb7_r.png\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='596'%20height='598'&&\u002Fsvg&\& data-rawwidth=\&596\& data-rawheight=\&598\& class=\&origin_image zh-lightbox-thumb lazy\& width=\&596\& data-original=\&https:\u002F\\u002Fv2-ddec646d2caf72aa372c7a4ecb46bfb7_r.png\& data-actualsrc=\&https:\u002F\\u002Fv2-ddec646d2caf72aa372c7a4ecb46bfb7_b.png\&\u003E\u003Cbr\u003E\u003Cp\u003E微信公众号:浮生开方\u003Cbr\u003E\u003Ca href=\&http:\u002F\\u002F?target=http%3A\u002F\u002Fhudo.it\u002F\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003EHUDO.IT\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E on Slack: \u003Ca href=\&http:\u002F\\u002F?target=https%3A\u002F\\u002F\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E\u003C\u002Fp\u003E&,&updated&:new Date(&T12:00:46.000Z&),&canComment&:false,&commentPermission&:&anyone&,&commentCount&:0,&collapsedCount&:0,&likeCount&:1,&state&:&published&,&isLiked&:false,&slug&:&&,&lastestTipjarors&:[],&isTitleImageFullScreen&:false,&rating&:&none&,&titleImage&:&https:\u002F\\u002Fv2-9067b7abbdb73ea3ed3d_r.jpg&,&links&:{&comments&:&\u002Fapi\u002Fposts\u002F2Fcomments&},&reviewers&:[],&topics&:[{&url&:&https:\u002F\\u002Ftopic\u002F&,&id&:&&,&name&:&函数式编程&},{&url&:&https:\u002F\\u002Ftopic\u002F&,&id&:&&,&name&:&面向对象编程&},{&url&:&https:\u002F\\u002Ftopic\u002F&,&id&:&&,&name&:&Functional Reactive Programming&}],&adminClosedComment&:false,&titleImageSize&:{&width&:1120,&height&:351},&href&:&\u002Fapi\u002Fposts\u002F&,&excerptTitle&:&&,&column&:{&slug&:&floatlab&,&name&:&浮生开方&},&tipjarState&:&activated&,&tipjarTagLine&:&万物皆可赞赏&,&sourceUrl&:&&,&pageCommentsCount&:0,&tipjarorCount&:0,&annotationAction&:[],&hasPublishingDraft&:false,&snapshotUrl&:&&,&publishedTime&:&T20:00:46+08:00&,&url&:&\u002Fp\u002F&,&lastestLikers&:[{&bio&:&一个脱离了高级趣味的人&,&isFollowing&:false,&hash&:&2c488bdc1c3e8cdce1636ff&,&uid&:12,&isOrg&:false,&slug&:&airwing-97&,&isFollowed&:false,&description&:&&,&name&:&翅膀&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Fairwing-97&,&avatar&:{&id&:&4fe80e92aaf2b43c79a48f&,&template&:&https:\u002F\\u002F50\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false}],&summary&:&\u003Cimg src=\&http:\u002F\\u002Fv2-b1a119bba5e1ec8e20ce25_200x112.jpg\& data-rawwidth=\&1366\& data-rawheight=\&768\& class=\&origin_image inline-img zh-lightbox-thumb\& data-original=\&http:\u002F\\u002Fv2-b1a119bba5e1ec8e20ce25_r.jpg\&\u003E先来一首定场诗:There is a cycle, a rhythm to the universe.Today one program will be popular, tomorrow another.\u003Cstrong\u003EToday 500 bugs will be fixed, tomorrow another 500 will appear.\u003C\u002Fstrong\u003ETo understand life is to know that the rhythm exists.To understa…&,&reviewingCommentsCount&:0,&meta&:{&previous&:{&isTitleImageFullScreen&:false,&rating&:&none&,&titleImage&:&https:\u002F\\u002F50\u002Fv2-5310ddba482ef6fa74b0d_xl.jpg&,&links&:{&comments&:&\u002Fapi\u002Fposts\u002F2Fcomments&},&topics&:[{&url&:&https:\u002F\\u002Ftopic\u002F&,&id&:&&,&name&:&新媒体互动&},{&url&:&https:\u002F\\u002Ftopic\u002F&,&id&:&&,&name&:&Adobe Flash&},{&url&:&https:\u002F\\u002Ftopic\u002F&,&id&:&&,&name&:&触摸板&}],&adminClosedComment&:false,&href&:&\u002Fapi\u002Fposts\u002F&,&excerptTitle&:&&,&author&:{&bio&:&Creative Coder@INT++ n' Float Lab&,&isFollowing&:false,&hash&:&2a55fb1b7f5995d9fdad7e818e61599a&,&uid&:20,&isOrg&:false,&slug&:&contra&,&isFollowed&:false,&description&:&Creative Coder@INT++ n' Float Lab.\nApp, web, game, audio, visual, VR\u002FAR.\nInteraction installation, projection, immersive experience, exhibition.\n\n公众号:浮生开方、浮生插电\n网站:http:\u002F\u002Ffloat.cc&,&name&:&Contra&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Fcontra&,&avatar&:{&id&:&v2-82b2a141501fad65c33f78f4061b8ddb&,&template&:&https:\u002F\\u002F50\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},&column&:{&slug&:&floatlab&,&name&:&浮生开方&},&content&:&\u003Cp\u003E本次周末DEMO,是一个互动触摸墙原型。\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cp\u003E成品视频:\u003C\u002Fp\u003E\u003Ca class=\&video-box\& href=\&http:\u002F\\u002F?target=https%3A\u002F\\u002Fx\u002Fpage\u002Fe0390oxew7g.html\& target=\&_blank\& data-video-id=\&\& data-video-playable=\&\& data-name=\&Interactive w' electric paint_腾讯视频\& data-poster=\&https:\u002F\\u002Fqqvideo_ori\u002F0\u002Fe0390oxew7g_228_128\u002F0\& data-lens-id=\&\&\u003E
\u003Cimg class=\&thumbnail\& src=\&https:\u002F\\u002Fqqvideo_ori\u002F0\u002Fe0390oxew7g_228_128\u002F0\&\u003E
\u003Cspan class=\&content\&\u003E
\u003Cspan class=\&title\&\u003EInteractive w' electric paint_腾讯视频\u003Cspan class=\&z-ico-extern-gray\&\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&z-ico-extern-blue\&\u003E\u003C\u002Fspan\u003E\u003C\u002Fspan\u003E
\u003Cspan class=\&url\&\u003E\u003Cspan class=\&z-ico-video\&\u003E\u003C\u002Fspan\u003Ehttps:\u002F\\u002Fx\u002Fpage\u002Fe0390oxew7g.html\u003C\u002Fspan\u003E
\u003C\u002Fspan\u003E
\u003C\u002Fa\u003E
\u003Cbr\u003E\u003Cul\u003E\u003Cli\u003E\u003Cp\u003E器材:\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cul\u003E\u003Cli\u003E\u003Cp\u003E导电墨水笔\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003EMakey Makey\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E画纸\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E投影仪\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E程序:Adobe Animate\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E视觉:PS 手绘 + AE\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cbr\u003E\u003Cbr\u003E\u003Cp\u003E\u003Cstrong\u003E---- 导电墨水 ----\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E关于墙体的互动方案,雷达,家里玩太贵;摄像头CV识别,缺少触摸感;最终选用了导电墨水:\u003C\u002Fp\u003E\u003Cp\u003E\u003Ca class=\&video-box\& href=\&http:\u002F\\u002F?target=https%3A\u002F\\u002Fx\u002Fpage\u002Ff03095j7fwo.html\& target=\&_blank\& data-video-id=\&\& data-video-playable=\&\& data-name=\&Bare Conductive - Electric Paint_腾讯视频\& data-poster=\&https:\u002F\\u002Fqqvideo_ori\u002F0\u002Ff03095j7fwo_228_128\u002F0\& data-lens-id=\&\&\u003E
\u003Cimg class=\&thumbnail\& src=\&https:\u002F\\u002Fqqvideo_ori\u002F0\u002Ff03095j7fwo_228_128\u002F0\&\u003E
\u003Cspan class=\&content\&\u003E
\u003Cspan class=\&title\&\u003EBare Conductive - Electric Paint_腾讯视频\u003Cspan class=\&z-ico-extern-gray\&\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&z-ico-extern-blue\&\u003E\u003C\u002Fspan\u003E\u003C\u002Fspan\u003E
\u003Cspan class=\&url\&\u003E\u003Cspan class=\&z-ico-video\&\u003E\u003C\u002Fspan\u003Ehttps:\u002F\\u002Fx\u002Fpage\u002Ff03095j7fwo.html\u003C\u002Fspan\u003E
\u003C\u002Fspan\u003E
\u003C\u002Fa\u003E
\u003Cbr\u003EBare Conductive这一款导电墨水笔,淘宝一支百元左右:\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cfigure\u003E\u003Cimg src=\&http:\u002F\\u002Fv2-1fb2b225a2f8a2c72188f_b.jpg\& data-rawwidth=\&1200\& data-rawheight=\&900\& class=\&origin_image zh-lightbox-thumb\& width=\&1200\& data-original=\&http:\u002F\\u002Fv2-1fb2b225a2f8a2c72188f_r.jpg\&\u003E\u003C\u002Ffigure\u003E\u003Cp\u003E为保护家里墙面,拿白板+画纸代替。\u003C\u002Fp\u003E\u003Cp\u003E第一层纸,画好导电线路:\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cfigure\u003E\u003Cimg src=\&http:\u002F\\u002Fv2-fbfcb54dd6fe_b.jpg\& data-rawwidth=\&3264\& data-rawheight=\&2448\& class=\&origin_image zh-lightbox-thumb\& width=\&3264\& data-original=\&http:\u002F\\u002Fv2-fbfcb54dd6fe_r.jpg\&\u003E\u003C\u002Ffigure\u003E\u003Cp\u003E再铺一层纸,触摸位置挖个简单粗暴的洞:\u003Cfigure\u003E\u003Cimg src=\&http:\u002F\\u002Fv2-50456eefb9b75c7a9d8c2d8e8e4e9b8e_b.jpg\& data-rawwidth=\&3264\& data-rawheight=\&2448\& class=\&origin_image zh-lightbox-thumb\& width=\&3264\& data-original=\&http:\u002F\\u002Fv2-50456eefb9b75c7a9d8c2d8e8e4e9b8e_r.jpg\&\u003E\u003C\u002Ffigure\u003E\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cbr\u003E\u003Cp\u003E\u003Cstrong\u003E---- Makey Makey ----\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cfigure\u003E\u003Cimg src=\&http:\u002F\\u002Fv2-bed7a2765cb8d_b.jpg\& data-rawwidth=\&500\& data-rawheight=\&265\& class=\&origin_image zh-lightbox-thumb\& width=\&500\& data-original=\&http:\u002F\\u002Fv2-bed7a2765cb8d_r.jpg\&\u003E\u003C\u002Ffigure\u003E\u003Cp\u003E\u003Cem\u003E图自\u003Ca href=\&http:\u002F\\u002F?target=http%3A\\& class=\& external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003E\u003Cspan class=\&invisible\&\u003Ehttp:\u002F\u002F\u003C\u002Fspan\u003E\u003Cspan class=\&visible\&\\u003C\u002Fspan\u003E\u003Cspan class=\&invisible\&\u003E\u003C\u002Fspan\u003E\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E\u003C\u002Fem\u003E\u003C\u002Fp\u003E\u003Ca class=\&video-box\& href=\&http:\u002F\\u002F?target=https%3A\u002F\\u002Fx\u002Fpage\u002Fy0323j22nup.html\& target=\&_blank\& data-video-id=\&\& data-video-playable=\&\& data-name=\&美国MakeyMakey万能创意键盘_标清_腾讯视频\& data-poster=\&https:\u002F\\u002Fqqvideo_ori\u002F0\u002Fy0323j22nup_228_128\u002F0\& data-lens-id=\&\&\u003E
\u003Cimg class=\&thumbnail\& src=\&https:\u002F\\u002Fqqvideo_ori\u002F0\u002Fy0323j22nup_228_128\u002F0\&\u003E
\u003Cspan class=\&content\&\u003E
\u003Cspan class=\&title\&\u003E美国MakeyMakey万能创意键盘_标清_腾讯视频\u003Cspan class=\&z-ico-extern-gray\&\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&z-ico-extern-blue\&\u003E\u003C\u002Fspan\u003E\u003C\u002Fspan\u003E
\u003Cspan class=\&url\&\u003E\u003Cspan class=\&z-ico-video\&\u003E\u003C\u002Fspan\u003Ehttps:\u002F\\u002Fx\u002Fpage\u002Fy0323j22nup.html\u003C\u002Fspan\u003E
\u003C\u002Fspan\u003E
\u003C\u002Fa\u003E
\u003Cbr\u003E\u003Cp\u003E\u003Cem\u003E\u003Cfigure\u003E\u003Cimg src=\&http:\u002F\\u002Fv2-e84e22e8d4d18613e2ed_b.jpg\& data-rawwidth=\&500\& data-rawheight=\&444\& class=\&origin_image zh-lightbox-thumb\& width=\&500\& data-original=\&http:\u002F\\u002Fv2-e84e22e8d4d18613e2ed_r.jpg\&\u003E\u003C\u002Ffigure\u003E图自\u003Ca href=\&http:\u002F\\u002F?target=http%3A\\& class=\& external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003E\u003Cspan class=\&invisible\&\u003Ehttp:\u002F\u002F\u003C\u002Fspan\u003E\u003Cspan class=\&visible\&\\u003C\u002Fspan\u003E\u003Cspan class=\&invisible\&\u003E\u003C\u002Fspan\u003E\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E\u003C\u002Fem\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cbr\u003EMakey Makey直接映射的就是键盘,所以接好线路即可:\u003Cfigure\u003E\u003Cimg src=\&http:\u002F\\u002Fv2-cab2e1ce84ad009d4cf7c_b.jpg\& data-rawwidth=\&2170\& data-rawheight=\&1852\& class=\&origin_image zh-lightbox-thumb\& width=\&2170\& data-original=\&http:\u002F\\u002Fv2-cab2e1ce84ad009d4cf7c_r.jpg\&\u003E\u003C\u002Ffigure\u003E\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cbr\u003E\u003Cp\u003E\u003Cstrong\u003E---- 程序 ----\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E控制及呈现的程序,平台选用 Adobe Animate,看着眼生?它以前叫 Flash 。\u003C\u002Fp\u003E\u003Cp\u003E在 Animate 里所见即所得的做 Layout,以及导入动画序列帧。\u003Cfigure\u003E\u003Cimg src=\&http:\u002F\\u002Fv2-cd5c2ab6dd58a_b.png\& data-rawwidth=\&1460\& data-rawheight=\&851\& class=\&origin_image zh-lightbox-thumb\& width=\&1460\& data-original=\&http:\u002F\\u002Fv2-cd5c2ab6dd58a_r.png\&\u003E\u003C\u002Ffigure\u003E\u003C\u002Fp\u003E\u003Cp\u003E代码部分,用 Javascript API,而非as3,这样可将项目发布成 HTML5+Canvas 的 Web 形式,而非传统的 swf Flash。\u003C\u002Fp\u003E\u003Cp\u003E发布成 Web,就非常灵活了。Web 页面托管在开发机上,而连接 Makey Makey 和投影的是另一台更轻便的笔记本,联局域网打开页面网址就行。\u003C\u002Fp\u003E\u003Cp\u003E调试时,若另一头开发机有了修改,这边直接刷新页面即可更新。\u003C\u002Fp\u003E\u003Cp\u003E最后将做好的画面投影到墙(画纸)上,触摸区与画纸上挖的洞对准(可以先投影,再挖洞,方便校准):\u003Cfigure\u003E\u003Cimg src=\&http:\u002F\\u002Fv2-3ab7eace3aff13bc9afa74a23c8bb135_b.jpg\& data-rawwidth=\&1280\& data-rawheight=\&960\& class=\&origin_image zh-lightbox-thumb\& width=\&1280\& data-original=\&http:\u002F\\u002Fv2-3ab7eace3aff13bc9afa74a23c8bb135_r.jpg\&\u003E\u003C\u002Ffigure\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cbr\u003E最终效果即如开头视频所示。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E\u003Cbr\u003E---- 项目分工 ----\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E花婶:采购 + 画导电线 + 布展 + 手绘 + 动画\u003C\u002Fp\u003E\u003Cp\u003EContra:Animate 编程 + 喝茶\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cp\u003E谢谢阅读\u003C\u002Fp\u003E\u003Cp\u003E-----------\n\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cp\u003E不要慌,300字够了,撤。\n\u003C\u002Fp\u003E\u003Cp\u003E微信公众号:浮生开方\u003Cbr\u003E\u003Ca href=\&http:\u002F\\u002F?target=http%3A\u002F\u002Fhudo.it\u002F\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003EHUDO.IT\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E on Slack: \u003Ca href=\&http:\u002F\\u002F?target=https%3A\u002F\\u002F\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E\u003C\u002Fp\u003E&,&state&:&published&,&sourceUrl&:&&,&pageCommentsCount&:0,&canComment&:false,&snapshotUrl&:&&,&slug&:,&publishedTime&:&T16:57:40+08:00&,&url&:&\u002Fp\u002F&,&title&:&周末DEMO:物美价廉的家用互动触摸墙&,&summary&:&本次周末DEMO,是一个互动触摸墙原型。 成品视频: 器材:导电墨水笔Makey Makey画纸投影仪程序:Adobe Animate视觉:PS 手绘 + AE \u003Cstrong\u003E---- 导电墨水 ----\u003C\u002Fstrong\u003E关于墙体的互动方案,雷达,家里玩太贵;摄像头CV识别,缺少触摸感;最终选用了导电墨水: Bare Conduct…&,&reviewingCommentsCount&:0,&meta&:{&previous&:null,&next&:null},&commentPermission&:&anyone&,&commentsCount&:0,&likesCount&:0},&next&:{&isTitleImageFullScreen&:false,&rating&:&none&,&titleImage&:&https:\u002F\\u002F50\u002Fv2-ca747f1bf_xl.jpg&,&links&:{&comments&:&\u002Fapi\u002Fposts\u002F2Fcomments&},&topics&:[{&url&:&https:\u002F\\u002Ftopic\u002F&,&id&:&&,&name&:&Docker&},{&url&:&https:\u002F\\u002Ftopic\u002F&,&id&:&&,&name&:&容器虚拟化&}],&adminClosedComment&:false,&href&:&\u002Fapi\u002Fposts\u002F&,&excerptTitle&:&&,&author&:{&bio&:&Creative Coder@INT++ n' Float Lab&,&isFollowing&:false,&hash&:&2a55fb1b7f5995d9fdad7e818e61599a&,&uid&:20,&isOrg&:false,&slug&:&contra&,&isFollowed&:false,&description&:&Creative Coder@INT++ n' Float Lab.\nApp, web, game, audio, visual, VR\u002FAR.\nInteraction installation, projection, immersive experience, exhibition.\n\n公众号:浮生开方、浮生插电\n网站:http:\u002F\u002Ffloat.cc&,&name&:&Contra&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Fcontra&,&avatar&:{&id&:&v2-82b2a141501fad65c33f78f4061b8ddb&,&template&:&https:\u002F\\u002F50\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},&column&:{&slug&:&floatlab&,&name&:&浮生开方&},&content&:&\u003Ca href=\&http:\u002F\\u002F?target=https%3A\u002F\\u002Fdocker-mac\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003EDocker For Mac\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E 在mount本地文件时,有很大的性能问题,本文介绍两种实测有效的性能提升方法。\u003Cbr\u003E\u003Cblockquote\u003E什么是Docker for Mac:\u003Cbr\u003EDocker for Mac is an easy-to-install desktop app for building, debugging and testing Dockerized apps on a Mac. Docker for Mac is a complete development environment deeply integrated with the MacOS Hypervisor framework, networking and filesystem. Docker for Mac is the fastest and most reliable way to run Docker on a Mac.\u003C\u002Fblockquote\u003E\u003Cbr\u003E关于D4M性能问题的详细讨论,见这里:\u003Cbr\u003E\u003Ca href=\&http:\u002F\\u002F?target=https%3A\\u002Fdocker\u002Ffor-mac\u002Fissues\u002F77\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003EFile access in mounted volumes extremely slow · Issue #77 · docker\u002Ffor-mac\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E\u003Cbr\u003E\u003Cbr\u003E里边提到了几种解决方案:\u003Cbr\u003E- docker-machine-nfs: \u003Ca href=\&http:\u002F\\u002F?target=https%3A\\u002Fadlogix\u002Fdocker-machine-nfs\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003Eadlogix\u002Fdocker-machine-nfs\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E\u003Cbr\u003E- d4m-nfs: \u003Ca href=\&http:\u002F\\u002F?target=https%3A\\u002FIFSight\u002Fd4m-nfs\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003EIFSight\u002Fd4m-nfs\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E\u003Cbr\u003E- docker-sync: \u003Ca href=\&http:\u002F\\u002F?target=https%3A\\u002FEugenMayer\u002Fdocker-sync\u002F\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003EEugenMayer\u002Fdocker-sync\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E\u003Cbr\u003E- 使用edge版的Docker for Mac\u003Cbr\u003E\u003Cbr\u003E实测了以下两种:\u003Cbr\u003E\u003Cb\u003E1. docker-sync\u003C\u002Fb\u003E\u003Cbr\u003E\u003Ca href=\&http:\u002F\\u002F?target=https%3A\\u002FEugenMayer\u002Fdocker-sync\u002F\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003EEugenMayer\u002Fdocker-sync\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E\u003Cbr\u003E使用docker-sync后,性能确有明显提升。\u003Cbr\u003E但我在具体开发中遇到一个问题:\u003Cbr\u003E用了docker-sync后,从Docker容器里建一个目录xfolder,在容器外本地往该目录xfolder里添加几个文件,这些文件无法同步到Docker容器里。\u003Cbr\u003E反之则可以,即先从本地创建目录,再从Docker容器里往该目录里添加文件,则这些文件会正常同步到本地。\u003Cbr\u003E该问题在官方issues里也有记录:\u003Cbr\u003E\u003Ca href=\&http:\u002F\\u002F?target=https%3A\\u002FEugenMayer\u002Fdocker-sync\u002Fissues\u002F410\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003E0.4.6 not syncing both directions on macOS 10.11.6 · Issue #410 · EugenMayer\u002Fdocker-sync\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E\u003Cbr\u003E\u003Cbr\u003E\u003Cb\u003E2. 使用edge版的Docker for Mac\u003C\u002Fb\u003E\u003Cbr\u003E实测性能提升效果也不错,与docker-sync接近。\u003Cbr\u003E卸载stable版的Docker,安装\u003Ca href=\&http:\u002F\\u002F?target=https%3A\u002F\\u002Feditions\u002Fcommunity\u002Fdocker-ce-desktop-mac\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003Eedge版\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E。\u003Cbr\u003E\u003Cimg src=\&http:\u002F\\u002Fv2-cd2cb556dae45f094511_b.png\& data-rawwidth=\&164\& data-rawheight=\&134\& class=\&content_image\& width=\&164\&\u003E\u003Cbr\u003E安装后,在docker-compose.yml中要mount的volumes处,增加cached标记即可:\u003Cbr\u003E\u003Cimg src=\&http:\u002F\\u002Fv2-91d99c7d50ad7c25ab6ff8ddb38b5f30_b.png\& data-rawwidth=\&337\& data-rawheight=\&109\& class=\&content_image\& width=\&337\&\u003E\u003Cbr\u003E详细介绍直接见:\u003Cbr\u003E\u003Ca href=\&http:\u002F\\u002F?target=https%3A\\u002Fdocker\u002Ffor-mac\u002Fissues\u002F77\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003EFile access in mounted volumes extremely slow · Issue #77 · docker\u002Ffor-mac\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E\u003Cbr\u003E\u003Cbr\u003E\u003Cp\u003E谢谢阅读\u003Cbr\u003E\u003Ci\u003E题图引自 \u003Ca href=\&http:\u002F\\u002F?target=http%3A\\& class=\& external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003E\u003Cspan class=\&invisible\&\u003Ehttp:\u002F\u002F\u003C\u002Fspan\u003E\u003Cspan class=\&visible\&\\u003C\u002Fspan\u003E\u003Cspan class=\&invisible\&\u003E\u003C\u002Fspan\u003E\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E\u003C\u002Fi\u003E\u003C\u002Fp\u003E\u003Cp\u003E-----------\u003C\u002Fp\u003E\u003Cp\u003E不要慌,300字够了,撤。\u003C\u002Fp\u003E\u003Cp\u003E微信公众号:浮生开方\u003Cbr\u003E\u003Ca href=\&http:\u002F\\u002F?target=http%3A\u002F\u002Fhudo.it\u002F\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003EHUDO.IT\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E on Slack: \u003Ca href=\&http:\u002F\\u002F?target=https%3A\u002F\\u002F\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E\u003C\u002Fp\u003E&,&state&:&published&,&sourceUrl&:&&,&pageCommentsCount&:0,&canComment&:false,&snapshotUrl&:&&,&slug&:,&publishedTime&:&T10:58:32+08:00&,&url&:&\u002Fp\u002F&,&title&:&如何提升Docker for Mac性能&,&summary&:&\u003Ca href=\&https:\u002F\\u002Fdocker-mac\& data-editable=\&true\& data-title=\&Docker For Mac\& class=\&\&\u003EDocker For Mac\u003C\u002Fa\u003E 在mount本地文件时,有很大的性能问题,本文介绍两种实测有效的性能提升方法。 什么是Docker for Mac: Docker for Mac is an easy-to-install desktop app for building, debugging and testing Dockerized apps on a Mac. Docker for Mac …&,&reviewingCommentsCount&:0,&meta&:{&previous&:null,&next&:null},&commentPermission&:&anyone&,&commentsCount&:0,&likesCount&:0}},&annotationDetail&:null,&commentsCount&:0,&likesCount&:1,&FULLINFO&:true}},&User&:{&contra&:{&isFollowed&:false,&name&:&Contra&,&headline&:&Creative Coder@INT++ n' Float Lab.\nApp, web, game, audio, visual, VR\u002FAR.\nInteraction installation, projection, immersive experience, exhibition.\n\n公众号:浮生开方、浮生插电\n网站:http:\u002F\u002Ffloat.cc&,&avatarUrl&:&https:\u002F\\u002F50\u002Fv2-82b2a141501fad65c33f78f4061b8ddb_s.jpg&,&isFollowing&:false,&type&:&people&,&slug&:&contra&,&bio&:&Creative Coder@INT++ n' Float Lab&,&hash&:&2a55fb1b7f5995d9fdad7e818e61599a&,&uid&:20,&isOrg&:false,&description&:&Creative Coder@INT++ n' Float Lab.\nApp, web, game, audio, visual, VR\u002FAR.\nInteraction installation, projection, immersive experience, exhibition.\n\n公众号:浮生开方、浮生插电\n网站:http:\u002F\u002Ffloat.cc&,&badge&:{&identity&:null,&bestAnswerer&:null},&profileUrl&:&https:\u002F\\u002Fpeople\u002Fcontra&,&avatar&:{&id&:&v2-82b2a141501fad65c33f78f4061b8ddb&,&template&:&https:\u002F\\u002F50\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false}},&Comment&:{},&favlists&:{}},&me&:{},&global&:{&experimentFeatures&:{&ge3&:&ge3_9&,&ge2&:&ge2_1&,&nwebStickySidebar&:&sticky&,&androidPassThroughPush&:&all&,&newMore&:&new&,&liveReviewBuyBar&:&live_review_buy_bar_2&,&liveStore&:&ls_a2_b2_c1_f2&,&qawebThumbnailAbtest&:&old&,&searchHybridTabs&:&without-tabs&,&iOSEnableFeedModuleWWANAritclePreRender&:&iOS_FeedModule_WWAN_PreRender_Enable&,&isOffice&:&false&,&liveDetailWechatBanner&:&Live_detail_wechat_banner_1&,&newLiveFeedMediacard&:&old&,&homeUi2&:&default&,&recommendationAbtest&:&old&,&marketTab&:&market_tab_old&,&qrcodeLogin&:&qrcode&,&isShowUnicomFreeEntry&:&unicom_free_entry_off&,&newMobileColumnAppheader&:&new_header&,&androidDbRecommendAction&:&open&,&zcmLighting&:&zcm&,&favAct&:&default&,&appStoreRateDialog&:&close&,&mobileQaPageProxyHeifetz&:&m_qa_page_nweb&,&default&:&None&,&androidDbFeedRepinSelection&:&open&,&wechatShareModal&:&wechat_share_modal_show&,&qaStickySidebar&:&sticky_sidebar&,&androidProfilePanel&:&panel_b&,&nwebWriteAnswer&:&experiment&}},&columns&:{&next&:{},&floatlab&:{&following&:false,&canManage&:false,&href&:&\u002Fapi\u002Fcolumns\u002Ffloatlab&,&name&:&浮生开方&,&creator&:{&slug&:&contra&},&url&:&\u002Ffloatlab&,&slug&:&floatlab&,&avatar&:{&id&:&v2-2eaeba7a2a123eb4d15f&,&template&:&https:\u002F\\u002F{id}_{size}.jpg&}}},&columnPosts&:{},&columnSettings&:{&colomnAuthor&:[],&uploadAvatarDetails&:&&,&contributeRequests&:[],&contributeRequestsTotalCount&:0,&inviteAuthor&:&&},&postComments&:{},&postReviewComments&:{&comments&:[],&newComments&:[],&hasMore&:true},&favlistsByUser&:{},&favlistRelations&:{},&promotions&:{},&switches&:{&couldSetPoster&:false},&draft&:{&titleImage&:&&,&titleImageSize&:{},&isTitleImageFullScreen&:false,&canTitleImageFullScreen&:false,&title&:&&,&titleImageUploading&:false,&error&:&&,&content&:&&,&draftLoading&:false,&globalLoading&:false,&pendingVideo&:{&resource&:null,&error&:null}},&drafts&:{&draftsList&:[],&next&:{}},&config&:{&userNotBindPhoneTipString&:{}},&recommendPosts&:{&articleRecommendations&:[],&columnRecommendations&:[]},&env&:{&edition&:{&baidu&:false,&yidianzixun&:false,&qqnews&:false},&isAppView&:false,&appViewConfig&:{&content_padding_top&:128,&content_padding_bottom&:56,&content_padding_left&:16,&content_padding_right&:16,&title_font_size&:22,&body_font_size&:16,&is_dark_theme&:false,&can_auto_load_image&:true,&app_info&:&OS=iOS&},&isApp&:false,&userAgent&:{&ua&:&Mozilla\u002F5.0 (compatible, MSIE 11, Windows NT 6.3; Trident\u002F7.0; rv:11.0) like Gecko&,&browser&:{&name&:&IE&,&version&:&11&,&major&:&11&},&engine&:{&version&:&7.0&,&name&:&Trident&},&os&:{&name&:&Windows&,&version&:&8.1&},&device&:{},&cpu&:{}}},&message&:{&newCount&:0},&

我要回帖

更多关于 响应式编程 的文章

 

随机推荐