Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React 应用中 “神奇” 的多态—性能隐患 #3372

Merged
merged 3 commits into from Mar 12, 2018

Conversation

blizzardzheng
Copy link
Contributor

译文翻译完成,resolve #3314

@goldEli
Copy link
Contributor

goldEli commented Mar 5, 2018

校对认领

@fanyijihua
Copy link
Collaborator

@goldEli 好的呢 🍺

@weberpan
Copy link
Contributor

weberpan commented Mar 5, 2018

校对认领

@fanyijihua
Copy link
Collaborator

@weberpan 妥妥哒 🍻

Copy link
Contributor

@goldEli goldEli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@blizzardzheng 辛苦了 (^_^)

> * 校对者:

# Surprising polymorphism in React applications
# React 应用中 “神奇” 的多态—性能隐患
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React 应用中 “神奇” 的多态—性能隐患
=>
React 应用中 “神奇” 的多态 —— 性能隐患

破折号前后空格

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里我觉得之前确实初看也没想清楚,后面的解释应该是名词。性能隐患放前面吧。React 应用中的性能隐患 — 神奇的多态 这样更便于理解啦


The core of this mechanism are so-called _reducers_. Those are functions that map one state of the application to the next one according to a specific action — i.e. in response to user interaction. Using this core abstraction, complex state and reducers can be composed of simpler ones, which makes it easy to unit test the code in separation. Consider the following example from the [Redux documentation](http://redux.js.org/docs/basics/ExampleTodoList.html):
这种机制的核心被称作为 ``reducers``。 它们是一些能使用一个特定的 ``action`` 把应用的一个状态映射到下一个状态的函数。比如说为了响应用户的的交互行为,使用这种核心抽奖的概念,复杂的状态和 reducers 能被组合成简单形式,这使得它易于对各部分代码隔离做单元测试。我们仔细分析一下 [Redux 文档](http://redux.js.org/docs/basics/ExampleTodoList.html) 中的例子。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

“使用这种核心抽奖的概念”
抽奖 =》 抽象

@@ -35,7 +35,7 @@ const todo = (state = {}, action) => {
}
```

The `todo` reducer maps an existing `state` to a new state in response to a given `action`. The state is represented as plain old JavaScript object. Looking at this code from a performance perspective, it seems to follow the principles for monomorphic code, i.e. keeping the object shape the same.
这个名叫 `todo` reducer 根据给定的 `action` 把一个已有的 `state` 映射到了一个新的状态。这个状态的表示形式是一个纯的 JavaScript 旧对象。我们单从性能角度来看这段代码,他似乎是符合单态法则的,比如这个对象的形状(key/value)保持一致。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个状态的表示形式是一个纯的 JavaScript 旧对象
=》
这个状态就是一个普通的JavaScript对象

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

赞成 goldEli 的观点(不过你要注意前后空格)
这个状态就是一个普通的 JavaScript 对象

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不理解作者为啥对普通的 JavaScript 对象 写成old 而不是 normal 等词语来表达。

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

plain 和 old 两个词在这里限定怪怪的,一个已经表达了朴素对象,old不知道干啥,没有对应。总不能说是和前面的朴素对象2333

@@ -59,11 +59,11 @@ render(s1);
render(s2);
```

Speaking naively the property accesses in `render` should be monomorphic, i.e. the `state` objects should have the same shape — [map or hidden class in V8 speak](https://github.com/v8/v8/wiki/Design%20Elements#fast-property-access) — all the time, both `s1` and `s2` have `id`, `text` and `completed` properties in this order. However, running this code in the `d8` shell and tracing the ICs (inline caches), we observe that `render` sees different object shapes and the `state.id` and `state.text` property accesses become polymorphic:
表面上来看, `render` 中属性的获取应该是单态的,比如说 `state` 对象应该有相同的对象形状- [map 或者 V8 概念中的 hidden class 形式](https://github.com/v8/v8/wiki/Design%20Elements#fast-property-access) — 不管什么时候, `s1` `s2` 都拥有 `id`, `text` `completed` 属性并且它们有序。然而,当通过 `d8` 运行这段代码病跟踪代码的 ``ICs`` (内联缓存) 时,我们发现那个 `render` 表现出来的对象形状不相同, `state.id` `state.text` 的获取变成了多态形式:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

属性的获取
=》
访问属性

@@ -59,11 +59,11 @@ render(s1);
render(s2);
```

Speaking naively the property accesses in `render` should be monomorphic, i.e. the `state` objects should have the same shape — [map or hidden class in V8 speak](https://github.com/v8/v8/wiki/Design%20Elements#fast-property-access) — all the time, both `s1` and `s2` have `id`, `text` and `completed` properties in this order. However, running this code in the `d8` shell and tracing the ICs (inline caches), we observe that `render` sees different object shapes and the `state.id` and `state.text` property accesses become polymorphic:
表面上来看, `render` 中属性的获取应该是单态的,比如说 `state` 对象应该有相同的对象形状- [map 或者 V8 概念中的 hidden class 形式](https://github.com/v8/v8/wiki/Design%20Elements#fast-property-access) — 不管什么时候, `s1` `s2` 都拥有 `id`, `text` `completed` 属性并且它们有序。然而,当通过 `d8` 运行这段代码病跟踪代码的 ``ICs`` (内联缓存) 时,我们发现那个 `render` 表现出来的对象形状不相同, `state.id` `state.text` 的获取变成了多态形式:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

“当通过 d8 运行这段代码病跟踪代码的 ICs (内联缓存) 时”
病 =》 并

@@ -78,15 +78,15 @@ console.log("b is", b);
console.log("a and b have same map:", %HaveSameMap(a, b));
```

You can run this code in Node.js passing the `--allow-natives-syntax` command line flag (which enables the use of the `%HaveSameMap` intrinsic), i.e.:
你可以在 ``Node.js`` 运行命令后面加上 `--allow-natives-syntax` 标志跑这段代码(这个开关打开会使用 `%HaveSameMap` 这个内部方法跑),举个例子:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

去掉 “标志”


![](https://cdn-images-1.medium.com/max/800/1*fkbEgBWk74icFH1yZIH7Lw.png)

So polymorphism hides where objects are allocated via different (incompatible) object literals. This especially applies to common uses of `Object.assign`, for example
所以当对象初始化期间被分配不同的对象字面量时,迁移树就不同,``map`` 也就不同,多态就隐含的形成了。这一结论对大家普遍用的 `Object.assign`也适用,比如:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

迁移树就不同,map 也就不同
=》
转换树(transition tree)不同,map 也就不同

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

还是叫迁移树把,v8 有蛮多文献这么叫。不过后面的词保留可以的

@@ -98,15 +98,15 @@ console.log("b is", b);
console.log("a and b have same map:", %HaveSameMap(a, b));
```

still yields different maps, because the object `b` starts out as empty object (the `{}` literal) and `Object.assign` just slaps properties on it.
这段代码还是造成了不同的 ``map`` ,因为对象 `b` 是从一个空对象( `{}` 字面量) 创建的,而属性是等到`Object.assign` 才给他塞入。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

造成了 =》 产生了

塞入 =》 分配


![](https://cdn-images-1.medium.com/max/800/1*Xu-nIj21gj-GlHDkzsSOSA.png)

This also applies if you use spread properties and transpile it using Babel, because Babel — and probably other transpilers as well — use `Object.assign` for spread properties.
这也表明,当你使用 ``spread`` 语法处理属性,并且通过 Babel 来语法转译,就会遇到这个多态的问题。因为 Babel (其他的可能的转译器也一样), 对 ``spread`` 语法使用了 `Object.assign` 处理。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spread 指的是扩展运算符

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spread 字还是留着 不过可以加上拓展运算。


![](https://cdn-images-1.medium.com/max/800/1*F2x8lRcZ83pQDvftelFOgA.png)

One way to avoid this is to consistently use `Object.assign` so that all objects start from the empty object literal. But this can become a performance bottleneck in the state management logic:
有一种方法来避免这个产生就是一直保持使用 `Object.assign` ,使得所有对象从一个空的对象字面量开始。但是这也会导致这个状态管理逻辑存在性能瓶颈:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

有一种方法来避免这个产生就是一直保持使用 Object.assign ,使得所有对象从一个空的对象字面量开始
=》
有一种方法可以避免这个问题,就是使用 Object.assign ,并且所有对象都是从一个空的对象字面量开始的

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consistently 还是要翻出来

Copy link
Contributor

@weberpan weberpan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

翻译得挺好的 @leviding @blizzardzheng

@@ -2,14 +2,14 @@
> * 原文作者:[Benedikt Meurer](https://medium.com/@bmeurer?source=post_header_lockup)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/TODO/surprising-polymorphism-in-react-applications.md](https://github.com/xitu/gold-miner/blob/master/TODO/surprising-polymorphism-in-react-applications.md)
> * 译者:
> * 译者: [Candy Zheng](https://github.com/blizzardzheng)
> * 校对者:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


The core of this mechanism are so-called _reducers_. Those are functions that map one state of the application to the next one according to a specific action — i.e. in response to user interaction. Using this core abstraction, complex state and reducers can be composed of simpler ones, which makes it easy to unit test the code in separation. Consider the following example from the [Redux documentation](http://redux.js.org/docs/basics/ExampleTodoList.html):
这种机制的核心被称作为 ``reducers``。 它们是一些能使用一个特定的 ``action`` 把应用的一个状态映射到下一个状态的函数。比如说为了响应用户的的交互行为,使用这种核心抽奖的概念,复杂的状态和 reducers 能被组合成简单形式,这使得它易于对各部分代码隔离做单元测试。我们仔细分析一下 [Redux 文档](http://redux.js.org/docs/basics/ExampleTodoList.html) 中的例子。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

它们是一些能使用一个特定的 action 把应用的一个状态映射到下一个状态的函数。比如说为了响应用户的的交互行为,
=>
它们是一些能把应用从一个状态映射到下一个状态的函数,我们把触发这种映射的行为称为 action ,比如说对用户交互的响应。

这里 in response to user interaction 是属于上一句话的。

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

之前确实没细看这给点,那我感觉可以这样翻更符合作者本意: “它们是一些能根据一个特定的映射行为 action(例如对用户交互的响应)把应用从一个状态映射到下一个状态的函数”


The core of this mechanism are so-called _reducers_. Those are functions that map one state of the application to the next one according to a specific action — i.e. in response to user interaction. Using this core abstraction, complex state and reducers can be composed of simpler ones, which makes it easy to unit test the code in separation. Consider the following example from the [Redux documentation](http://redux.js.org/docs/basics/ExampleTodoList.html):
这种机制的核心被称作为 ``reducers``。 它们是一些能使用一个特定的 ``action`` 把应用的一个状态映射到下一个状态的函数。比如说为了响应用户的的交互行为,使用这种核心抽奖的概念,复杂的状态和 reducers 能被组合成简单形式,这使得它易于对各部分代码隔离做单元测试。我们仔细分析一下 [Redux 文档](http://redux.js.org/docs/basics/ExampleTodoList.html) 中的例子。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

使用这种核心抽奖的概念
=》
通过这种核心的抽象概念


The core of this mechanism are so-called _reducers_. Those are functions that map one state of the application to the next one according to a specific action — i.e. in response to user interaction. Using this core abstraction, complex state and reducers can be composed of simpler ones, which makes it easy to unit test the code in separation. Consider the following example from the [Redux documentation](http://redux.js.org/docs/basics/ExampleTodoList.html):
这种机制的核心被称作为 ``reducers``。 它们是一些能使用一个特定的 ``action`` 把应用的一个状态映射到下一个状态的函数。比如说为了响应用户的的交互行为,使用这种核心抽奖的概念,复杂的状态和 reducers 能被组合成简单形式,这使得它易于对各部分代码隔离做单元测试。我们仔细分析一下 [Redux 文档](http://redux.js.org/docs/basics/ExampleTodoList.html) 中的例子。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复杂的状态和 reducers 能被组合成简单形式
=》
复杂的状态和 reducers 可以用一堆简单的状态和 reducers 组成
或者
我们可以用一堆简单的状态和 reducers 组成起来满足复杂场景的需要

不是把复杂的组合成简单,而是用一堆简单的组合成复杂

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我这里说的其实也没错, 复杂能组合成简单形式。不是说复杂组合成简单。 不过你提出了说明翻的理解有点吃力,简单形式不够确切,be composed of 没翻译到位。那么不如翻译成, ”复杂的状态和 reducers 可以由一些更简单状态和 reducers 组成“

@@ -35,7 +35,7 @@ const todo = (state = {}, action) => {
}
```

The `todo` reducer maps an existing `state` to a new state in response to a given `action`. The state is represented as plain old JavaScript object. Looking at this code from a performance perspective, it seems to follow the principles for monomorphic code, i.e. keeping the object shape the same.
这个名叫 `todo` reducer 根据给定的 `action` 把一个已有的 `state` 映射到了一个新的状态。这个状态的表示形式是一个纯的 JavaScript 旧对象。我们单从性能角度来看这段代码,他似乎是符合单态法则的,比如这个对象的形状(key/value)保持一致。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

赞成 goldEli 的观点(不过你要注意前后空格)
这个状态就是一个普通的 JavaScript 对象


![](https://cdn-images-1.medium.com/max/800/1*FrfEaOkxshIj79wJDQyrIQ.png)

So where does this polymorphism comes from? It’s actually pretty subtle and has to do with the way V8 handles object literals. Each object literal — i.e. expression of the form `{a:va,...,z:vb}` defines a root map in the transition tree of maps (remember map is V8 speak for object shape). So if you use an empty object literal `{}` than the transition tree root is a map that doesn’t contain any properties, whereas if you use `{id:id, text:text, completed:completed}` object literal, then the transition tree root is a map that contains these three properties. Let’s look at a simplified example:
那么问题来了,这个多态是从哪里来的?它确实表面看上去一致但其实有微小差异,我们得从 V8 是如何处理对象字面量着手分析。V8 里,每个对象字面量 (比如 `{a:va,...,z:vb}` 形式的表达形式 ) 定义了一个初始的`` map`` (map V8 概念中特指对象的形状)这个 ``map`` 会在之后属性变动时迁移成其他形式的 ``map``。所以,如果你使用一个空对象字面量 {} 时,这颗迁移树的根是一个不包含任何属性的 ``map``,但如果你使用 `{id:id, text:text, completed:completed}` 形式的对象字面量,那么这个迁移树的根就会是一个包含这三个属性,让我们来看一个精简过的例子:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这颗 =》 这棵
建议 这棵、这个 统一起来

@@ -78,15 +78,15 @@ console.log("b is", b);
console.log("a and b have same map:", %HaveSameMap(a, b));
```

You can run this code in Node.js passing the `--allow-natives-syntax` command line flag (which enables the use of the `%HaveSameMap` intrinsic), i.e.:
你可以在 ``Node.js`` 运行命令后面加上 `--allow-natives-syntax` 标志跑这段代码(这个开关打开会使用 `%HaveSameMap` 这个内部方法跑),举个例子:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(这个开关打开会使用 %HaveSameMap 这个内部方法跑)
=》
(打开这个开关就可以使用内部方法 %HaveSameMap

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😓这里写快了,那我觉得翻译成 “开启即可应用内部方法 %HaveSameMap”

@@ -78,15 +78,15 @@ console.log("b is", b);
console.log("a and b have same map:", %HaveSameMap(a, b));
```

You can run this code in Node.js passing the `--allow-natives-syntax` command line flag (which enables the use of the `%HaveSameMap` intrinsic), i.e.:
你可以在 ``Node.js`` 运行命令后面加上 `--allow-natives-syntax` 标志跑这段代码(这个开关打开会使用 `%HaveSameMap` 这个内部方法跑),举个例子:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

举个例子
=》
例如

例子都是同个例子啦,就不用再举一个

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

233


![](https://cdn-images-1.medium.com/max/800/1*yzSaH_AE5z7r9PWBXlvwWg.png)

So despite these objects `a` and `b` looking the same — having the same properties with the same types in the same order — they don’t have the same map. The reason being that they have different transition trees, as illustrated by the following diagram:
尽管 `a` and `b` 这两个对象看上去是一样的—依次拥有相同的类型的属性,它们 map 结构并不一样。原因是它们的迁移树并不相同,我们可以看以下的示例来解释:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

看上去是一样的—依次拥有相同的类型的属性
=》
看上去是一样的 —— 依次拥有相同类型的属性

使用中文破折号并要有前后空格;把 的 去掉通顺点


![](https://cdn-images-1.medium.com/max/800/1*Xu-nIj21gj-GlHDkzsSOSA.png)

This also applies if you use spread properties and transpile it using Babel, because Babel — and probably other transpilers as well — use `Object.assign` for spread properties.
这也表明,当你使用 ``spread`` 语法处理属性,并且通过 Babel 来语法转译,就会遇到这个多态的问题。因为 Babel (其他的可能的转译器也一样), 对 ``spread`` 语法使用了 `Object.assign` 处理。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(其他的可能的转译器也一样)
=》
(其他的转译器可能也一样)

使用中文括号

@weberpan
Copy link
Contributor

weberpan commented Mar 7, 2018

@blizzardzheng @leviding 校对完成

@leviding
Copy link
Member

leviding commented Mar 8, 2018

@blizzardzheng 可以修改啦

@blizzardzheng
Copy link
Contributor Author

@leviding 改完了,项目太忙看的晚啦不好意思哈。 @weberpan @goldEli 辛苦两位老师啦233

@leviding leviding merged commit b1ead9c into xitu:master Mar 12, 2018
@leviding
Copy link
Member

@blizzardzheng 已经 merge 啦~ 快快麻溜发布到掘金然后给我发下链接,方便及时添加积分哟。

掘金翻译计划有自己的知乎专栏,你也可以投稿哈,推荐使用一个好用的插件
专栏地址:https://zhuanlan.zhihu.com/juejinfanyi

@blizzardzheng
Copy link
Contributor Author

@leviding https://juejin.im/post/5aa5ebe16fb9a028d04314b0 done,帮忙推荐推荐哈2333

@leviding
Copy link
Member

@goldEli @weberpan 校对认真,积分翻倍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

React 应用中 “神奇” 的多态—性能隐患
5 participants