Skip to content

Commit

Permalink
create fast MessageEvent (#3170)
Browse files Browse the repository at this point in the history
* create fast MessageEvent

* expose

* use

* fixup
  • Loading branch information
KhafraDev committed Apr 26, 2024
1 parent ed686fc commit 381f32c
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 10 deletions.
20 changes: 20 additions & 0 deletions benchmarks/websocket/messageevent.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { bench, group, run } from 'mitata'
import { createFastMessageEvent, MessageEvent as UndiciMessageEvent } from '../../lib/web/websocket/events.js'

const { port1, port2 } = new MessageChannel()

group('MessageEvent instantiation', () => {
bench('undici - fast MessageEvent init', () => {
return createFastMessageEvent('event', { data: null, ports: [port1, port2] })
})

bench('undici - MessageEvent init', () => {
return new UndiciMessageEvent('event', { data: null, ports: [port1, port2] })
})

bench('global - MessageEvent init', () => {
return new MessageEvent('event', { data: null, ports: [port1, port2] })
})
})

await run()
3 changes: 2 additions & 1 deletion index-fetch.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ module.exports.Headers = require('./lib/web/fetch/headers').Headers
module.exports.Response = require('./lib/web/fetch/response').Response
module.exports.Request = require('./lib/web/fetch/request').Request

const { CloseEvent, ErrorEvent, MessageEvent } = require('./lib/web/websocket/events')
const { CloseEvent, ErrorEvent, MessageEvent, createFastMessageEvent } = require('./lib/web/websocket/events')
module.exports.WebSocket = require('./lib/web/websocket/websocket').WebSocket
module.exports.CloseEvent = CloseEvent
module.exports.ErrorEvent = ErrorEvent
module.exports.MessageEvent = MessageEvent
module.exports.createFastMessageEvent = createFastMessageEvent

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

Expand Down
4 changes: 2 additions & 2 deletions lib/web/eventsource/eventsource.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const { makeRequest } = require('../fetch/request')
const { webidl } = require('../fetch/webidl')
const { EventSourceStream } = require('./eventsource-stream')
const { parseMIMEType } = require('../fetch/data-url')
const { MessageEvent } = require('../websocket/events')
const { createFastMessageEvent } = require('../websocket/events')
const { isNetworkError } = require('../fetch/response')
const { delay } = require('./util')
const { kEnumerableProperty } = require('../../core/util')
Expand Down Expand Up @@ -290,7 +290,7 @@ class EventSource extends EventTarget {
const eventSourceStream = new EventSourceStream({
eventSourceSettings: this.#state,
push: (event) => {
this.dispatchEvent(new MessageEvent(
this.dispatchEvent(createFastMessageEvent(
event.type,
event.options
))
Expand Down
2 changes: 1 addition & 1 deletion lib/web/websocket/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ function onSocketClose () {
// decode without BOM to the WebSocket connection close
// reason.
// TODO: process.nextTick
fireEvent('close', ws, CloseEvent, {
fireEvent('close', ws, (type, init) => new CloseEvent(type, init), {
wasClean, code, reason
})

Expand Down
23 changes: 22 additions & 1 deletion lib/web/websocket/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const { webidl } = require('../fetch/webidl')
const { kEnumerableProperty } = require('../../core/util')
const { kConstruct } = require('../../core/symbols')
const { MessagePort } = require('node:worker_threads')

/**
Expand All @@ -11,6 +12,11 @@ class MessageEvent extends Event {
#eventInit

constructor (type, eventInitDict = {}) {
if (type === kConstruct) {
super(arguments[1], arguments[2])
return
}

webidl.argumentLengthCheck(arguments, 1, { header: 'MessageEvent constructor' })

type = webidl.converters.DOMString(type)
Expand Down Expand Up @@ -73,8 +79,22 @@ class MessageEvent extends Event {
bubbles, cancelable, data, origin, lastEventId, source, ports
})
}

static createFastMessageEvent (type, init) {
const messageEvent = new MessageEvent(kConstruct, type, init)
messageEvent.#eventInit = init
messageEvent.#eventInit.data ??= null
messageEvent.#eventInit.origin ??= ''
messageEvent.#eventInit.lastEventId ??= ''
messageEvent.#eventInit.source ??= null
messageEvent.#eventInit.ports ??= []
return messageEvent
}
}

const { createFastMessageEvent } = MessageEvent
delete MessageEvent.createFastMessageEvent

/**
* @see https://websockets.spec.whatwg.org/#the-closeevent-interface
*/
Expand Down Expand Up @@ -299,5 +319,6 @@ webidl.converters.ErrorEventInit = webidl.dictionaryConverter([
module.exports = {
MessageEvent,
CloseEvent,
ErrorEvent
ErrorEvent,
createFastMessageEvent
}
11 changes: 6 additions & 5 deletions lib/web/websocket/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

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

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

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

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

if (reason) {
// TODO: process.nextTick
fireEvent('error', ws, ErrorEvent, {
fireEvent('error', ws, (type, init) => new ErrorEvent(type, init), {
error: new Error(reason)
})
}
Expand Down

0 comments on commit 381f32c

Please sign in to comment.