Skip to content

Commit 381f32c

Browse files
authored
create fast MessageEvent (#3170)
* create fast MessageEvent * expose * use * fixup
1 parent ed686fc commit 381f32c

File tree

6 files changed

+53
-10
lines changed

6 files changed

+53
-10
lines changed

benchmarks/websocket/messageevent.mjs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { bench, group, run } from 'mitata'
2+
import { createFastMessageEvent, MessageEvent as UndiciMessageEvent } from '../../lib/web/websocket/events.js'
3+
4+
const { port1, port2 } = new MessageChannel()
5+
6+
group('MessageEvent instantiation', () => {
7+
bench('undici - fast MessageEvent init', () => {
8+
return createFastMessageEvent('event', { data: null, ports: [port1, port2] })
9+
})
10+
11+
bench('undici - MessageEvent init', () => {
12+
return new UndiciMessageEvent('event', { data: null, ports: [port1, port2] })
13+
})
14+
15+
bench('global - MessageEvent init', () => {
16+
return new MessageEvent('event', { data: null, ports: [port1, port2] })
17+
})
18+
})
19+
20+
await run()

index-fetch.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@ module.exports.Headers = require('./lib/web/fetch/headers').Headers
1717
module.exports.Response = require('./lib/web/fetch/response').Response
1818
module.exports.Request = require('./lib/web/fetch/request').Request
1919

20-
const { CloseEvent, ErrorEvent, MessageEvent } = require('./lib/web/websocket/events')
20+
const { CloseEvent, ErrorEvent, MessageEvent, createFastMessageEvent } = require('./lib/web/websocket/events')
2121
module.exports.WebSocket = require('./lib/web/websocket/websocket').WebSocket
2222
module.exports.CloseEvent = CloseEvent
2323
module.exports.ErrorEvent = ErrorEvent
2424
module.exports.MessageEvent = MessageEvent
25+
module.exports.createFastMessageEvent = createFastMessageEvent
2526

2627
module.exports.EventSource = require('./lib/web/eventsource/eventsource').EventSource
2728

lib/web/eventsource/eventsource.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const { makeRequest } = require('../fetch/request')
66
const { webidl } = require('../fetch/webidl')
77
const { EventSourceStream } = require('./eventsource-stream')
88
const { parseMIMEType } = require('../fetch/data-url')
9-
const { MessageEvent } = require('../websocket/events')
9+
const { createFastMessageEvent } = require('../websocket/events')
1010
const { isNetworkError } = require('../fetch/response')
1111
const { delay } = require('./util')
1212
const { kEnumerableProperty } = require('../../core/util')
@@ -290,7 +290,7 @@ class EventSource extends EventTarget {
290290
const eventSourceStream = new EventSourceStream({
291291
eventSourceSettings: this.#state,
292292
push: (event) => {
293-
this.dispatchEvent(new MessageEvent(
293+
this.dispatchEvent(createFastMessageEvent(
294294
event.type,
295295
event.options
296296
))

lib/web/websocket/connection.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ function onSocketClose () {
267267
// decode without BOM to the WebSocket connection close
268268
// reason.
269269
// TODO: process.nextTick
270-
fireEvent('close', ws, CloseEvent, {
270+
fireEvent('close', ws, (type, init) => new CloseEvent(type, init), {
271271
wasClean, code, reason
272272
})
273273

lib/web/websocket/events.js

+22-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
const { webidl } = require('../fetch/webidl')
44
const { kEnumerableProperty } = require('../../core/util')
5+
const { kConstruct } = require('../../core/symbols')
56
const { MessagePort } = require('node:worker_threads')
67

78
/**
@@ -11,6 +12,11 @@ class MessageEvent extends Event {
1112
#eventInit
1213

1314
constructor (type, eventInitDict = {}) {
15+
if (type === kConstruct) {
16+
super(arguments[1], arguments[2])
17+
return
18+
}
19+
1420
webidl.argumentLengthCheck(arguments, 1, { header: 'MessageEvent constructor' })
1521

1622
type = webidl.converters.DOMString(type)
@@ -73,8 +79,22 @@ class MessageEvent extends Event {
7379
bubbles, cancelable, data, origin, lastEventId, source, ports
7480
})
7581
}
82+
83+
static createFastMessageEvent (type, init) {
84+
const messageEvent = new MessageEvent(kConstruct, type, init)
85+
messageEvent.#eventInit = init
86+
messageEvent.#eventInit.data ??= null
87+
messageEvent.#eventInit.origin ??= ''
88+
messageEvent.#eventInit.lastEventId ??= ''
89+
messageEvent.#eventInit.source ??= null
90+
messageEvent.#eventInit.ports ??= []
91+
return messageEvent
92+
}
7693
}
7794

95+
const { createFastMessageEvent } = MessageEvent
96+
delete MessageEvent.createFastMessageEvent
97+
7898
/**
7999
* @see https://websockets.spec.whatwg.org/#the-closeevent-interface
80100
*/
@@ -299,5 +319,6 @@ webidl.converters.ErrorEventInit = webidl.dictionaryConverter([
299319
module.exports = {
300320
MessageEvent,
301321
CloseEvent,
302-
ErrorEvent
322+
ErrorEvent,
323+
createFastMessageEvent
303324
}

lib/web/websocket/util.js

+6-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
const { kReadyState, kController, kResponse, kBinaryType, kWebSocketURL } = require('./symbols')
44
const { states, opcodes } = require('./constants')
5-
const { MessageEvent, ErrorEvent } = require('./events')
5+
const { ErrorEvent, createFastMessageEvent } = require('./events')
66
const { isUtf8 } = require('node:buffer')
77

88
/* globals Blob */
@@ -51,15 +51,16 @@ function isClosed (ws) {
5151
* @see https://dom.spec.whatwg.org/#concept-event-fire
5252
* @param {string} e
5353
* @param {EventTarget} target
54+
* @param {(...args: ConstructorParameters<typeof Event>) => Event} eventFactory
5455
* @param {EventInit | undefined} eventInitDict
5556
*/
56-
function fireEvent (e, target, eventConstructor = Event, eventInitDict = {}) {
57+
function fireEvent (e, target, eventFactory = (type, init) => new Event(type, init), eventInitDict = {}) {
5758
// 1. If eventConstructor is not given, then let eventConstructor be Event.
5859

5960
// 2. Let event be the result of creating an event given eventConstructor,
6061
// in the relevant realm of target.
6162
// 3. Initialize event’s type attribute to e.
62-
const event = new eventConstructor(e, eventInitDict) // eslint-disable-line new-cap
63+
const event = eventFactory(e, eventInitDict)
6364

6465
// 4. Initialize any other IDL attributes of event as described in the
6566
// invocation of this algorithm.
@@ -110,7 +111,7 @@ function websocketMessageReceived (ws, type, data) {
110111
// 3. Fire an event named message at the WebSocket object, using MessageEvent,
111112
// with the origin attribute initialized to the serialization of the WebSocket
112113
// object’s url's origin, and the data attribute initialized to dataForEvent.
113-
fireEvent('message', ws, MessageEvent, {
114+
fireEvent('message', ws, createFastMessageEvent, {
114115
origin: ws[kWebSocketURL].origin,
115116
data: dataForEvent
116117
})
@@ -195,7 +196,7 @@ function failWebsocketConnection (ws, reason) {
195196

196197
if (reason) {
197198
// TODO: process.nextTick
198-
fireEvent('error', ws, ErrorEvent, {
199+
fireEvent('error', ws, (type, init) => new ErrorEvent(type, init), {
199200
error: new Error(reason)
200201
})
201202
}

0 commit comments

Comments
 (0)