by Justin Falcone

贾斯汀·法尔科内(Justin Falcone)

Redux有何优点? (What’s So Great About Redux?)

Redux elegantly handles complex state interactions that are hard to express with React’s component state. It is essentially a message-passing system, like the kind seen in Object-Oriented programming, but implemented as a library instead of in the language itself¹. As in OOP, Redux inverts the responsibility of control from caller to receiver — the UI doesn’t directly manipulate the state but rather sends it a message for the state to interpret.

Redux优雅地处理了复杂的状态交互,这些交互很难用React的组件状态来表达。 它本质上是一个消息传递系统,类似于在面向对象的编程中看到的那种,但是实现为库而不是使用语言本身¹ 。 与在OOP中一样,Redux将控制的责任从调用者转变为接收者-UI并不直接操纵状态,而是向其发送消息以供状态解释。

Through this lens, a Redux store is an object, reducers are method handlers, and actions are messages. store.dispatch({ type: "foo", payload: "bar" }) is equivalent to Ruby's store.send(:foo, "bar"). Middleware are used in much the same way Aspect-Oriented Programming (e.g. Rails' before_action) and React-Redux's connect is dependency injection.

从这个角度来看,Redux存储是一个对象,reduce是方法处理程序,而action是消息。 store.dispatch({ type: "foo", payload: "bar" })等同于Ruby的store.send(:foo, "bar") 。 中间件的使用方式与面向方面的编程(例如,Rails的before_action )和React-Redux的connect是依赖注入相同。

为什么这是可取的? (Why is this desirable?)

  • The inversion of control described above ensures that the UI doesn’t need to be updated if the implementation of state transitions changes. Adding complex features like logging, undo or even time travel debugging are almost trivial. Integration tests are just a matter of testing that the right action is dispatched; the rest can be unit-tested.上面所述的控制反转可确保在状态转换的实现发生更改时,无需更新UI。 添加诸如日志记录,撤消甚至时间旅行调试之类的复杂功能几乎是微不足道的。 集成测试只是测试是否已分派正确的操作; 其余的可以进行单元测试。
  • React’s component state is pretty clunky for state that touches multiple parts of your app, such as user info and notifications. Redux gives you a state tree thats independent of your UI to handle these cross cutting concerns. Furthermore, having your state live outside of the UI makes things like persistence easier — you only need to deal with serializing to localStorage or URLs in a single place.对于涉及应用程序多个部分的状态,例如用户信息和通知,React的组件状态非常笨拙。 Redux为您提供了独立于您的UI的状态树,以处理这些交叉问题。 此外,将状态保留在UI之外还使持久性变得更容易-您只需要在一个地方处理序列化到localStorage或URL的问题。
  • Redux’s titular “reducers” provide incredible flexibility for handling actions — composition, multiple dispatch, even method_missing-style parsing.

    Redux的名义上的“减少器”为处理动作提供了令人难以置信的灵活性,包括组合,多重调度甚至method_missing样式的解析。

这些都是不寻常的情况。 普通情况如何? (These are all unusual cases. What about the common cases?)

Well, there’s the problem.

好吧,这里有问题。

  • An action could be interpreted as a complex state transition, but most of them set a single value. Redux apps tend to end up with a bunch of actions that set a single value; there’s a distinct reminder of manually writing setter functions in Java.

    动作可以解释为复杂的状态转换,但是大多数动作都设置一个值。 Redux应用程序最终会产生一系列设置单个值的操作。 有一个特别的提醒,那就是用Java手动编写setter函数。

  • A fragment of state could be used all over your app, but most state maps 1:1 with a single part of the UI. Putting that state in Redux instead of component state just adds indirection without abstraction.

    状态片段可以在您的整个应用程序中使用,但是大多数状态与UI的一部分是1:1映射的。 将该状态置于Redux中而不是组件状态中只会添加间接而无需抽象

  • A reducer function could do all sorts of metaprogramming weirdness, but in most cases it’s just single-dispatch on the action’s type field. This is fine in languages like Elm and Erlang, where pattern matching is terse and highly expressive, but rather clunky in JavaScript with switch statements.

    reducer函数可以完成各种元编程怪异,但是在大多数情况下,它只是对动作的type字段进行一次分派。 这在Elm和Erlang这样的语言中很好,在这些语言中模式匹配简洁且表达能力强,但在带有switch语句JavaScript中相当笨拙。

But the really insidious thing is that when you spend all your time doing the boilerplate for common cases, you forget that better solutions for the special cases even exist. You encounter a complex state transition and solve it with a function that dispatches a dozen different value-setting actions. You duplicate state in the reducer rather than distributing a single state slice across the app. You copy and paste switch cases across multiple reducers instead of abstracting it into shared functions.

但是真正的阴险之处在于,当您花费所有时间来处理常见情况时,您会忘记甚至存在针对特殊情况的更好的解决方案。 您会遇到一个复杂的状态转换,并使用一个分派许多不同的值设置操作的函数来解决它。 您可以在化简器中复制状态,而不是在应用程序中分配单个状态片。 您可以跨多个化简器复制和粘贴切换案例,而不是将其抽象为共享函数。

It’s easy to dismiss this as mere “Operator Error” — they didn’t RTFM, A Poor Craftsman Blames His Tools — but the frequency of these problems should raise some concerns. What does it say about a tool if most people are using it wrong?

仅仅将其视为“操作员错误”就很容易了-他们没有RTFM,可怜的工匠责备他的工具-但是这些问题的发生频率应该引起一些担忧。 如果大多数人使用错误,对工具有何评价?

所以我应该只在常见情况下避免Redux并在特殊情况下保存它吗? (So should I just avoid Redux for the common cases and save it for the special ones?)

That’s the advice the Redux team will give you — and that’s the advice I give to my own team members: I tell them to avoid it until using setState becomes truly untenable. But I can’t bring myself to follow my own rules, ’cause there’s always some reason you want to use Redux. You might have a bunch of set_$foo actions, but setting any value also updates the URL, or resets some more transient value. Maybe you have a clear 1:1 mapping of state to UI, but you also want to have logging or undo.

这就是Redux团队会给您的建议—这就是我给自己的团队成员的建议:我告诉他们避免使用它,直到使用setState真正站不住脚。 但是我无法让自己遵循自己的规则,因为您总是有某些理由要使用Redux。 您可能有一堆set_$foo操作,但是设置任何值也会更新URL,或重置一些更临时的值。 也许您有清晰的1:1状态映射到UI,但您想进行日志记录或撤消操作。

The truth is that I don’t know how to write, much less teach, “good Redux.” Every app I’ve worked on is full of these Redux antipatterns, either because I couldn’t think of a better solution myself or because I couldn’t convince my teammates to change it. If the code of a Redux “expert” is mediocre, what hope does a novice have? If anything, I’m just trying to counterbalance the prevailing “Redux all the things!” approach in the hope that they will be able to understand Redux on their own terms.

事实是,我不知道该怎么写,更不用说 “好Redux”了。 我开发的每个应用程序都充满了这些Redux反模式,或者是因为我自己想不到更好的解决方案,或者因为我无法说服队友进行更改。 如果Redux“专家”的代码中等,那么新手会有什么希望? 如果有的话,我只是想抵消当时流行的“全部还原!” 希望他们能够以自己的方式理解Redux。

那么在那种情况下我该怎么办? (So what do I do in that case?)

Fortunately, Redux is flexible enough that third-party libraries can integrate with it to handle the common cases — Jumpstate for example. And to be clear, I don’t think it’s wrong for Redux to focus on the low-level stuff. But outsourcing these basic features to third parties creates an additional cognitive load and opportunity for bikeshedding — each user needs to essentially build their own framework from these parts.

幸运的是,Redux具有足够的灵活性,可以与第三方库集成以处理常见情况(例如Jumpstate) 。 需要明确的是,我认为Redux专注于低层次的东西并没有错。 但是,将这些基本功能外包给第三方会带来额外的认知负担和骑车脱落的机会-每个用户实际上都需要从这些部分构建自己的框架。

有些人喜欢这种事情。 (Some people are into that sort of thing.)

And I’m one of ‘em! But not everybody is. I personally love Redux and use it for just about everything that I do, but I also love trying out new Webpack configurations. I am not representative of the general population. I’m empowered by the flexibility to write my own abstractions on top of Redux, but how empowered am I by the abstractions written by some senior engineer who never documented them and quit six months ago?

我是他们之一! 但不是每个人都是。 我个人很喜欢Redux并将其用于我所做的几乎所有事情,但是我喜欢尝试新的Webpack配置。 我不代表一般人口。 我被灵活地写我自己的终极版之上的抽象权力 ,但如何授权由一些资深工程师谁没有记载他们不干半年前写的抽象我是谁?

It’s quite possible to never encounter the hard problems that Redux is particularly good at handling, particularly if you’re a junior on a team where those tickets go to the more senior engineers. Your experience of Redux is “that weird library everyone uses where you have to write everything three times.” Redux is simple enough that you can use it mechanically, without deep understanding, but that’s a joyless and unrewarding experience.

很有可能永远不会遇到Redux特别擅长处理的棘手问题,特别是如果您是团队中的初级人员,而这些票会交给高级工程师。 您对Redux的经验是“每个人都在使用怪异的库来编写所有内容三遍。” Redux非常简单,您可以在没有深入了解的情况下机械地使用它,但这是一种无聊又无益的体验。

This brings me back to a question I raised earlier: what does it say about a tool if most people are using it wrong? A quality hand tool isn’t just useful and durable — it feels good to use. The most comfortable place to hold it is the correct place to hold it. It is designed not just for its task but also its user. A quality tool reflects the toolsmith’s empathy for the crafter.

这使我回到我先前提出的一个问题:如果大多数人错误地使用工具,它对工具有什么看法? 优质的手动工具不仅有用且耐用,而且使用起来感觉很好。 握住它的最舒适的地方是正确的地方。 它不仅针对其任务而设计,而且还针对其用户而设计。 优质的工具反映了工具匠对Craft.io师的同情。

Where is our empathy? Why is “you’re doing it wrong” our reaction, and not “we could make this easier to use”?

我们的同情心在哪里? 为什么我们的React是“您做错了”,而不是“我们可以使其更易于使用”?

There’s a related phenomenon in functional programming circles I like to call the Curse of the Monad Tutorial: explaining how they work is trivial, but explaining why they are valuable is surprisingly difficult.

我喜欢将函数式编程圈子中的一个相关现象称为“ Monad教程诅咒” :解释它们的工作原理是微不足道的,但是解释为什么它们很有价值却令人惊讶地困难。

您是否认真地在本文中间删除了monad教程? (Are you seriously dropping a monad tutorial in the middle of this post?)

Monads are a common pattern in Haskell that’s used for working with a wide range of computation — lists, error handling, state, time, IO. There’s syntactic sugar, in the form of do notation, that allows you to represent sequences of monadic operations in a way that looks kind of like imperative code, much like how generators in javascript can make asynchronous code look synchronous.

Monad是Haskell中的一种常见模式,用于处理各种计算-列表,错误处理,状态,时间,IO。 有一种形式为do表示法的语法糖,它允许您以某种看起来像命令式代码的方式表示单子运算的序列,就像javascript中的生成器如何使异步代码看起来是同步的一样。

The first problem is that describing monads in terms of what they’re used for is inaccurate. Monads were introduced to Haskell to handle side effects and sequential computation, but monads as an abstract concept have nothing to do with side effects or sequences; they’re a set of rules for how a pair of functions should interact and have no inherent meaning. The concept of associativity applies to arithmetic and set operations and list concatenation and null propagation but it exists fully independent of them.

第一个问题是,根据单子的用途来描述单子是不准确的。 Monad被引入Haskell来处理副作用和顺序计算 ,但是monad作为一个抽象概念与副作用或序列无关。 它们是一对函数如何交互且没有内在含义的一组规则。 关联性的概念适用于算术和集合运算以及列表级联和空传播,但它完全独立于它们而存在。

The second problem is that any bite-sized example of a monadic approach to X is more verbose — and therefore at least visually more complex — than the imperative approach. Explicit option types a la Maybe are safer than checking for implicit null but result in more, uglier code. Error handling with Either types is often simpler to follow than code that can throw from anywhere, but throwing is certainly more concise than manually propagating values. And side effects — state, IO, etc. — are trivial in an imperative language. Functional programming enthusiasts (myself included) would argue that side effects are too easy in these languages but convincing someone that any kind of programming is too easy is a hard sell.

第二个问题是,比起命令式方法,对X的单子方法的任何一口大小的示例都更加冗长-因此至少在视觉上更为复杂。 显式选项类型Maybe比检查隐式null更安全,但会导致代码更丑陋。 与可以从任何地方throw代码相比,使用Either类型的错误处理通常更容易遵循,但是抛出肯定比手动传播值更简洁。 在命令式语言中,副作用(状态,IO等)微不足道。 函数式编程爱好者(包括我本人)会认为,这些语言的副作用太容易了 ,但是要说服某人任何类型的编程都太容易了,这是一件很难的事。

The real value is only visible at the macro scale — not just that any one of these use cases follows the monad laws, but that all of them follow the same laws. A set of operations that works in one case can work in every case: zipping a pair of lists into a list of pairs is “the same thing” as merging a pair of promises into a single promise that completes with a pair of results.

真正的价值仅在宏观尺度上可见-不仅这些用例中的任何一个都遵循monad定律,而且所有用例都遵循相同的定律。 在每种情况下都可以使用一组操作在每种情况下都可以工作:将一对列表压缩成对列表是“同一件事”,就像将一对promise合并为一个带有一对结果的promise一样。

这要去哪里吗 (Is this going somewhere?)

The point is that Redux has the same problem — it’s difficult to teach not because it’s difficult but rather because it’s so simple. Understanding is not a matter of having knowledge so much as trusting the core idea in such a way that we can derive everything else through induction.

关键是Redux也有同样的问题-很难教,不是因为难,而是因为它是如此简单 。 理解并不仅仅是拥有知识,而是以一种可以通过归纳推导出其他一切的方式来信任核心思想。

It’s hard to share this understanding because the core ideas are banal truisms (avoid side effects) or abstract to the point of meaninglessness ((prevState, action) => nextState). Any single concrete example doesn't help; they showcase Redux's verbosity without demonstrating its expressivity.

很难分享这种理解,因为核心思想是平庸的无私(避免副作用)或抽象到毫无意义的程度( (prevState, action) => nextSt ate)。 任何一个具体的例子都无济于事。 他们展示了Redux的冗长性,却没有表现出它的表现力。

Once we are ✨enlightened✨ a lot of us immediately forget what it felt like beforehand. We forget that our enlightenment came only through our own repeated failures and misunderstandings.

一旦“开悟”了,我们很多人会立即忘记事先的感觉。 我们忘记了,我们的启蒙只是来自我们自己反复的失败和误解。

那你有什么建议呢? (So what do you propose?)

I would like us to admit we have a problem. Redux is simple, but it is not easy. This is a valid design choice, but it is nevertheless a tradeoff. Many people would benefit from a tool that traded some of the simplicity for ease-of-use. But large chunks of the community won’t even acknowledge that a tradeoff has been made!

我希望我们承认我们有问题。 Redux很简单,但并不容易 。 这是一个有效的设计选择,但仍然是一个折衷方案。 许多人将受益于将一些简单性换成易用性的工具。 但是社区的大部分人甚至都不承认已经进行了权衡!

I think it’s interesting to contrast React and Redux because while React is a vastly more complicated piece of software and has a significantly larger API surface, it somehow feels easier to use and understand. The only absolutely necessary API features of react are React.createElement and ReactDOM.render — state, component lifecycle, even DOM events could have been handled elsewhere. Building these features into React made it more complicated, but they also made it better.

我认为将React和Redux进行对比很有趣,因为尽管React是一款非常复杂的软件,并且具有更大的API界面,但从某种程度上来说,它更易于使用和理解。 React.createElement唯一绝对必要的API功能是React.createElementReactDOM.render状态,组件生命周期,甚至DOM事件也可以在其他地方处理。 将这些功能构建到React中使它变得更加复杂,但是它们也使它变得更好

“Atomic state” is an abstract concept that can inform your work once you understand it, but setState is a method you can call on a React component that does atomic state management on your behalf, whether you understand it or not. It’s not a perfect solution — it’s less efficient than replacing state outright or mutating and forcing an update, and it has some footguns when it’s called asynchronously — but React is vastly better with setState as a callable method rather than a vocabulary term.

“原子状态”是一个抽象概念,可以在您理解工作后通知您,但setState是一种方法,您可以调用React组件来代表您执行原子状态管理,无论您是否理解。 这不是一个完美的解决方案-它效率不如直接替换状态或更改并强制更新有效,并且在异步调用时具有一些先发优势-但是React使用setState作为可调用方法而不是词汇术语要好得多。

Both the Redux team and the community are strongly opposed to expanding Redux’s API surface area, but the current approach of gluing a bunch of tiny libraries together is tedious even for experts and incomprehensible for beginners. If Redux cannot expand to have built-in support for the common cases, it needs a “blessed” framework to take that place. Jumpsuit could be a good start — it reifies the concepts of “actions” and “state” into callable functions while still preserving their many-to-many nature — but the actual library doesn’t matter as much as the act of blessing itself.

Redux团队和社区都强烈反对扩大Redux的API表面积 ,但是当前将一堆小库粘合在一起的方法即使对于专家来说也是乏味的,对于初学者来说也是难以理解的。 如果Redux无法扩展以提供对常见情况的内置支持,则它需要一个“有福的”框架来代替。 连身裤可能是一个好的开始-它将“动作”和“状态”的概念重新定义为可调用函数,同时仍保留它们的多对多性质-但是实际的库与祝福自己的行为无关紧要。

The irony in all this is that Redux’s raison d’etre is “Developer Experience”: Dan built Redux because he wanted to understand and recreate Elm’s time-traveling debugger. But as it developed its own identity — as it grew into the React ecosystem’s de facto OOP runtime — it gave up some of that focus on DX in exchange for configurability. This allowed the Redux ecosystem to bloom, but there’s a conspicuous absence where a humane, curated framework should be. Are we, the Redux community, ready to create it?

具有讽刺意味的是,Redux的存在理由是“开发人员体验”:Dan创建Redux是因为他想了解并重新创建Elm的时间旅行调试器。 但是随着它发展出自己的身份-成长为React生态系统的事实上的OOP运行时-它放弃了对DX的某些关注,以换取可配置性。 这使Redux生态系统得以蓬勃发展,但是显然应该缺少人性化,精心策划的框架。 我们Redux社区是否已准备好创建它?

Thanks to Matthew McVickar, a pile of moss, Eric Wood, Matt DuLeone, and Patrick Thomson for review.

感谢Matthew McVickar , 一堆苔藓 , Eric Wood , Matt DuLeone和Patrick Thomson的审查。

Footnotes:

脚注:

[1] Why do you make a distinction between react / JS and object oriented programming? JavaScript IS object oriented, just not class-based.

[1]为什么您要区分React / JS和面向对象的编程? JavaScript是面向对象的,只是不是基于类的。

Object-Oriented programming, like functional programming, is a methodology, not a language feature. Some languages support this style better than others, or have a standard library that’s designed for the style, but if you’re sufficiently dedicated to the task, you can write in an object-oriented style in any language.

像功能编程一样,面向对象的编程是一种方法,而不是语言功能。 某些语言比其他语言更好地支持此样式,或者具有针对该样式设计的标准库,但是如果您对这项任务有足够的投入,则可以使用任何语言以面向对象的样式编写。

JavaScript has a data structure it calls an Object, and most values in the language can be treated like objects, in the sense that there are methods you can call on every value except for null and undefined. But before Proxies came in ES6, every "method" call on an object was a dictionary lookup; foo.bar is always going to find a property named "bar" on foo or its prototype chain. Contrast this with a language like Ruby, where foo.bar sends the message :bar to foo -- this message can be intercepted and interpreted, it doesn't have to be a dictionary lookup.

JavaScript具有一个称为对象的数据结构,该语言中的大多数值都可以像对象一样对待,从某种意义上说,除了nullundefined之外,您可以对每个值调用方法。 但是在Proxies出现在ES6中之前,对对象的每个“方法”调用都是字典查找。 foo.bar总是会在foo或其原型链上找到名为“ bar”的属性。 将此与Ruby之类的语言进行对比,其中foo.bar将消息:bar发送到foo -该消息可以被拦截解释 ,而不必是字典查找。

Redux is essentially a slower but more sophisticated object system on top of JavaScript’s existing one, where reducers and middleware act as interpreters and interceptors around the JavaScript object that actually holds the state. [back]

Redux本质上是JavaScript现有系统之上的一个较慢但更复杂的对象系统,在其中,化简器和中间件充当了实际上持有状态JavaScript对象周围的解释器和拦截器。 [ 返回 ]

翻译自: https://www.freecodecamp.org/news/whats-so-great-about-redux-ac16f1cc0f8b/

Redux有何优点?相关推荐

  1. [译] ⚛ React 状态管理工具博物馆

    原文地址:⚛ The React State Museum: ⚡️View the hottest state management libs for React 原文作者:Gant Laborde ...

  2. 从 RxJS 到 Flink:如何处理数据流?

    简介:前端开发的本质是什么?响应式编程相对于 MVVM 或者 Redux 有什么优点?响应式编程的思想是否可以应用到后端开发中?本文以一个新闻网站为例,阐述在前端开发中如何使用响应式编程思想:再以计算 ...

  3. [译] SpaceAce 了解一下,一个新的前端状态管理库

    原文地址:Introducing SpaceAce, a new kind of front-end state library 原文作者:Jon Abrams 译文出自:掘金翻译计划 本文永久链接: ...

  4. jsonp react 获取返回值_必须要会的 50 个React 面试题(下)

    翻译:疯狂的技术宅 原文:https://www.edureka.co/blog/interview-questions/react-interview-questions 29. 你对受控组件和非受 ...

  5. 整理的最新的前端面试题必问集锦 (持续更新)

    前端面试必问 一.HTML+CSS 1.HTML 001.标签上title属性与alt属性的区别是什么? title: 仔显示图片的时候,鼠标以上可以显示一些信息,一般为建议.提示类型 alt : 当 ...

  6. 2023常见的前端面试题(附加解答)

    仅供参考,也是到处收集而来,如有不对的地方可以指点修改,后续追加的面试题在最后 JS 1.说一下innerHTML 与 innerText的作用与区别? 作用:都可以获取或者设置元素的内容 区别:in ...

  7. React 常见面试题

    React 面试题 以下是面试官最有可能问到的 50 个 React 面试题和答案.为方便你学习,我对它们进行了分类: 基本知识 React 组件 React Redux React 路由 基本知识 ...

  8. React面试题最全

    1.什么是虚拟DOM? 虚拟DOM是真实DOM在内存中的表示,ul的表示形式保存在内存中,并且与实际的DOM同步,这是一个发生在渲染函数被调用和元素在屏幕上显示的步骤,整个过程被称为调和 2.类组件和 ...

  9. 2023版最新最全React面试题

    React 作为前端使用最多的框架,必然是面试的重点.我们接下来主要从 React 的使用方式.源码层面和周边生态(如 redux, react-router 等)等几个方便来进行总结. 1. 使用方 ...

最新文章

  1. 极光推送后台php接口,极光推送Jpush(v2)接口 服务端PHP版本的REST API推送类
  2. UI 和 UX,区别在哪里?
  3. Qracle学习:排序
  4. 使命召唤手游迎来欧阳娜娜,这阵容够豪华,玩家期待吗?
  5. C# 断点续传原理与实现
  6. Pandas 文本数据方法 cat()
  7. PyTorch报错“/.../Loss.cu: ... [59,0,0] Assertion input_val >= zero input_val <= one failed.”
  8. Java监听器Listener使用说明
  9. 4.Node.js 微信消息管理
  10. 光缆成端接头的含义是指
  11. matlab导出prn文件怎么打开,prn文件怎么打开?prn是什么意思?
  12. 向量积的坐标运算公式推导_向量积坐标表示公式
  13. shell 脚本中日期运算
  14. 用Win10自带SSH实现免密登录Linux
  15. 博弈论 —— 海盗分金
  16. T1113 整理药名
  17. Android最牛的开源整理
  18. [导入]梦幻快车(DreamMail) v4.0 正式版 ?
  19. 中国经济增长预期上调至8.5%;亚马逊药店提供常见处方药;中国外汇储备激增236亿美元…| 洞悉跨境
  20. 直线导轨防尘处理方案有哪些?

热门文章

  1. MapXtreme2004 vs2005的官方回答
  2. Chrome无法播放m3u8格式的直播视频流的问题解决
  3. 如何测试数据库表空间不足场景
  4. iBatis.Net异步多线程 操作Ibatis报错
  5. 触发器批量更新 用游标,一个一个处理
  6. 数字模拟信号 单双信道传输
  7. c#做端口转发程序支持正向连接和反向链接
  8. 赋值语句 变量的地址相关 : RUNOOB python练习题7
  9. 聊聊flink Table的OrderBy及Limit
  10. ios开发之--UIDocumentInteractionController的使用(实现更多分享服务)