A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/vuejs/vue/commit/2a5fb41d1cd7445b6aacd2e888df1b397b1899dd below:

re-implement mergeVNodeHook to prevent memory leak (fix #4990) · vuejs/vue@2a5fb41 · GitHub

File tree Expand file treeCollapse file tree 6 files changed

+79

-55

lines changed

Filter options

Expand file treeCollapse file tree 6 files changed

+79

-55

lines changed Original file line number Diff line number Diff line change

@@ -1,18 +1,34 @@

1 1

/* @flow */

2 2 3 -

export function mergeVNodeHook (def: Object, hookKey: string, hook: Function, key: string) {

4 -

key = key + hookKey

5 -

const injectedHash: Object = def.__injected || (def.__injected = {})

6 -

if (!injectedHash[key]) {

7 -

injectedHash[key] = true

8 -

const oldHook: ?Function = def[hookKey]

9 -

if (oldHook) {

10 -

def[hookKey] = function () {

11 -

oldHook.apply(this, arguments)

12 -

hook.apply(this, arguments)

13 -

}

3 +

import { remove } from 'shared/util'

4 +

import { createFnInvoker } from './update-listeners'

5 + 6 +

export function mergeVNodeHook (def: Object, hookKey: string, hook: Function) {

7 +

let invoker

8 +

const oldHook = def[hookKey]

9 + 10 +

function wrappedHook () {

11 +

hook.apply(this, arguments)

12 +

// important: remove merged hook to ensure it's called only once

13 +

// and prevent memory leak

14 +

remove(invoker.fns, wrappedHook)

15 +

}

16 + 17 +

if (!oldHook) {

18 +

// no existing hook

19 +

invoker = createFnInvoker([wrappedHook])

20 +

} else {

21 +

/* istanbul ignore if */

22 +

if (oldHook.fns && oldHook.merged) {

23 +

// already a merged invoker

24 +

invoker = oldHook

25 +

invoker.fns.push(wrappedHook)

14 26

} else {

15 -

def[hookKey] = hook

27 +

// existing plain hook

28 +

invoker = createFnInvoker([oldHook, wrappedHook])

16 29

}

17 30

}

31 + 32 +

invoker.merged = true

33 +

def[hookKey] = invoker

18 34

}

Original file line number Diff line number Diff line change

@@ -19,25 +19,20 @@ const normalizeEvent = cached((name: string): {

19 19

}

20 20

})

21 21 22 -

function createEventHandle (fn: Function | Array<Function>): {

23 -

fn: Function | Array<Function>;

24 -

invoker: Function;

25 -

} {

26 -

const handle = {

27 -

fn,

28 -

invoker: function () {

29 -

const fn = handle.fn

30 -

if (Array.isArray(fn)) {

31 -

for (let i = 0; i < fn.length; i++) {

32 -

fn[i].apply(null, arguments)

33 -

}

34 -

} else {

35 -

// return handler return value for single handlers

36 -

return fn.apply(null, arguments)

22 +

export function createFnInvoker (fns: Function | Array<Function>): Function {

23 +

function invoker () {

24 +

const fns = invoker.fns

25 +

if (Array.isArray(fns)) {

26 +

for (let i = 0; i < fns.length; i++) {

27 +

fns[i].apply(null, arguments)

37 28

}

29 +

} else {

30 +

// return handler return value for single handlers

31 +

return fns.apply(null, arguments)

38 32

}

39 33

}

40 -

return handle

34 +

invoker.fns = fns

35 +

return invoker

41 36

}

42 37 43 38

export function updateListeners (

@@ -58,19 +53,19 @@ export function updateListeners (

58 53

vm

59 54

)

60 55

} else if (!old) {

61 -

if (!cur.invoker) {

62 -

cur = on[name] = createEventHandle(cur)

56 +

if (!cur.fns) {

57 +

cur = on[name] = createFnInvoker(cur)

63 58

}

64 -

add(event.name, cur.invoker, event.once, event.capture)

59 +

add(event.name, cur, event.once, event.capture)

65 60

} else if (cur !== old) {

66 -

old.fn = cur

61 +

old.fns = cur

67 62

on[name] = old

68 63

}

69 64

}

70 65

for (name in oldOn) {

71 66

if (!on[name]) {

72 67

event = normalizeEvent(name)

73 -

remove(event.name, oldOn[name].invoker, event.capture)

68 +

remove(event.name, oldOn[name], event.capture)

74 69

}

75 70

}

76 71

}

Original file line number Diff line number Diff line change

@@ -1,8 +1,8 @@

1 1

/* @flow */

2 2 3 +

import { emptyNode } from 'core/vdom/patch'

3 4

import { resolveAsset } from 'core/util/options'

4 5

import { mergeVNodeHook } from 'core/vdom/helpers/index'

5 -

import { emptyNode } from 'core/vdom/patch'

6 6 7 7

export default {

8 8

create: updateDirectives,

@@ -54,7 +54,7 @@ function _update (oldVnode, vnode) {

54 54

}

55 55

}

56 56

if (isCreate) {

57 -

mergeVNodeHook(vnode.data.hook || (vnode.data.hook = {}), 'insert', callInsert, 'dir-insert')

57 +

mergeVNodeHook(vnode.data.hook || (vnode.data.hook = {}), 'insert', callInsert)

58 58

} else {

59 59

callInsert()

60 60

}

@@ -65,7 +65,7 @@ function _update (oldVnode, vnode) {

65 65

for (let i = 0; i < dirsWithPostpatch.length; i++) {

66 66

callHook(dirsWithPostpatch[i], 'componentUpdated', vnode, oldVnode)

67 67

}

68 -

}, 'dir-postpatch')

68 +

})

69 69

}

70 70 71 71

if (!isCreate) {

Original file line number Diff line number Diff line change

@@ -47,7 +47,7 @@ export function extractTransitionData (comp: Component): Object {

47 47

// extract listeners and pass them directly to the transition methods

48 48

const listeners: ?Object = options._parentListeners

49 49

for (const key in listeners) {

50 -

data[camelize(key)] = listeners[key].fn

50 +

data[camelize(key)] = listeners[key]

51 51

}

52 52

return data

53 53

}

@@ -132,11 +132,12 @@ export default {

132 132

// component instance. This key will be used to remove pending leaving nodes

133 133

// during entering.

134 134

const id: string = `__transition-${this._uid}-`

135 -

const key: string = child.key = child.key == null

135 +

child.key = child.key == null

136 136

? id + child.tag

137 137

: isPrimitive(child.key)

138 138

? (String(child.key).indexOf(id) === 0 ? child.key : id + child.key)

139 139

: child.key

140 + 140 141

const data: Object = (child.data || (child.data = {})).transition = extractTransitionData(this)

141 142

const oldRawChild: VNode = this._vnode

142 143

const oldChild: VNode = getRealChild(oldRawChild)

@@ -158,16 +159,14 @@ export default {

158 159

mergeVNodeHook(oldData, 'afterLeave', () => {

159 160

this._leaving = false

160 161

this.$forceUpdate()

161 -

}, key)

162 +

})

162 163

return placeholder(h, rawChild)

163 164

} else if (mode === 'in-out') {

164 165

let delayedLeave

165 166

const performLeave = () => { delayedLeave() }

166 -

mergeVNodeHook(data, 'afterEnter', performLeave, key)

167 -

mergeVNodeHook(data, 'enterCancelled', performLeave, key)

168 -

mergeVNodeHook(oldData, 'delayLeave', leave => {

169 -

delayedLeave = leave

170 -

}, key)

167 +

mergeVNodeHook(data, 'afterEnter', performLeave)

168 +

mergeVNodeHook(data, 'enterCancelled', performLeave)

169 +

mergeVNodeHook(oldData, 'delayLeave', leave => { delayedLeave = leave })

171 170

}

172 171

}

173 172 Original file line number Diff line number Diff line change

@@ -10,6 +10,7 @@ import { RANGE_TOKEN, CHECKBOX_RADIO_TOKEN } from 'web/compiler/directives/model

10 10

// user-attached handlers.

11 11

function normalizeEvents (on) {

12 12

let event

13 +

/* istanbul ignore if */

13 14

if (on[RANGE_TOKEN]) {

14 15

// IE input[type=range] only supports `change` event

15 16

event = isIE ? 'change' : 'input'

Original file line number Diff line number Diff line change

@@ -83,11 +83,7 @@ export function enter (vnode: VNodeWithData, toggleDisplay: ?() => void) {

83 83

}

84 84 85 85

const expectsCSS = css !== false && !isIE9

86 -

const userWantsControl =

87 -

enterHook &&

88 -

// enterHook may be a bound method which exposes

89 -

// the length of original fn as _length

90 -

(enterHook._length || enterHook.length) > 1

86 +

const userWantsControl = getHookAgumentsLength(enterHook)

91 87 92 88

const cb = el._enterCb = once(() => {

93 89

if (expectsCSS) {

@@ -116,7 +112,7 @@ export function enter (vnode: VNodeWithData, toggleDisplay: ?() => void) {

116 112

pendingNode.elm._leaveCb()

117 113

}

118 114

enterHook && enterHook(el, cb)

119 -

}, 'transition-insert')

115 +

})

120 116

}

121 117 122 118

// start enter transition

@@ -181,11 +177,7 @@ export function leave (vnode: VNodeWithData, rm: Function) {

181 177

} = data

182 178 183 179

const expectsCSS = css !== false && !isIE9

184 -

const userWantsControl =

185 -

leave &&

186 -

// leave hook may be a bound method which exposes

187 -

// the length of original fn as _length

188 -

(leave._length || leave.length) > 1

180 +

const userWantsControl = getHookAgumentsLength(leave)

189 181 190 182

const explicitLeaveDuration = isObject(duration) ? duration.leave : duration

191 183

if (process.env.NODE_ENV !== 'production' && explicitLeaveDuration != null) {

@@ -271,6 +263,27 @@ function isValidDuration (val) {

271 263

return typeof val === 'number' && !isNaN(val)

272 264

}

273 265 266 +

/**

267 +

* Normalize a transition hook's argument length. The hook may be:

268 +

* - a merged hook (invoker) with the original in .fns

269 +

* - a wrapped component method (check ._length)

270 +

* - a plain function (.length)

271 +

*/

272 +

function getHookAgumentsLength (fn: Function): boolean {

273 +

if (!fn) return false

274 +

const invokerFns = fn.fns

275 +

if (invokerFns) {

276 +

// invoker

277 +

return getHookAgumentsLength(

278 +

Array.isArray(invokerFns)

279 +

? invokerFns[0]

280 +

: invokerFns

281 +

)

282 +

} else {

283 +

return (fn._length || fn.length) > 1

284 +

}

285 +

}

286 + 274 287

function _enter (_: any, vnode: VNodeWithData) {

275 288

if (!vnode.data.show) {

276 289

enter(vnode)

You can’t perform that action at this time.


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4