-
Notifications
You must be signed in to change notification settings - Fork 31k
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
events: simplify on implementation #41851
Changes from all commits
9098447
893e88b
fc717a8
d8decf1
87008a0
0eeb646
d68a516
659d3d8
5e6c085
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
'use strict'; | ||
const common = require('../common.js'); | ||
const readline = require('readline'); | ||
const { Readable } = require('stream'); | ||
|
||
const bench = common.createBenchmark(main, { | ||
n: [1e1, 1e2, 1e3, 1e4, 1e5, 1e6], | ||
}); | ||
|
||
const loremIpsum = `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. | ||
Dui accumsan sit amet nulla facilisi morbi tempus iaculis urna. | ||
Eget dolor morbi non arcu risus quis varius quam quisque. | ||
Lacus viverra vitae congue eu consequat ac felis donec. | ||
Amet porttitor eget dolor morbi non arcu. | ||
Velit ut tortor pretium viverra suspendisse. | ||
Mauris nunc congue nisi vitae suscipit tellus. | ||
Amet nisl suscipit adipiscing bibendum est ultricies integer. | ||
Sit amet dictum sit amet justo donec enim diam. | ||
Condimentum mattis pellentesque id nibh tortor id aliquet lectus proin. | ||
Diam in arcu cursus euismod quis viverra nibh. | ||
Rest of line`; | ||
|
||
function getLoremIpsumStream(repetitions) { | ||
const readable = Readable({ | ||
objectMode: true, | ||
}); | ||
let i = 0; | ||
readable._read = () => readable.push( | ||
i++ >= repetitions ? null : loremIpsum | ||
); | ||
return readable; | ||
} | ||
|
||
async function main({ n }) { | ||
bench.start(); | ||
let lineCount = 0; | ||
|
||
const iterable = readline.createInterface({ | ||
input: getLoremIpsumStream(n), | ||
}); | ||
|
||
// eslint-disable-next-line no-unused-vars | ||
for await (const _ of iterable) { | ||
lineCount++; | ||
} | ||
bench.end(lineCount); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,7 +25,7 @@ async function basic() { | |
for await (const event of iterable) { | ||
const current = expected.shift(); | ||
|
||
assert.deepStrictEqual(current, event); | ||
assert.deepStrictEqual(event, current); | ||
|
||
if (expected.length === 0) { | ||
break; | ||
|
@@ -113,39 +113,6 @@ async function throwInLoop() { | |
assert.strictEqual(ee.listenerCount('error'), 0); | ||
} | ||
|
||
async function next() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why these tests deleted? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They don't work with an async generator implementation. Please do have a look at it. But I can't find a way to make that test pass with an async generator and assuming async generators are "correct" then the test is "incorrect". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
What is the output with the async iterator implementation? These tests specifically check that if the user asked for two events and then closed the iterator they still get those two events and not one event and then the iterator closing. That behavior is quite explicit - though we can talk about changing it (it'd be a breaking change though I doubt a lot of users are relying on this behavior) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So the problem here is the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Discussion starting roughly here: https://github.com/nodejs/node/pull/27994/files#diff-330bdd22a188135540523f69deb4f9563e03b00a913cd369e1ee84d899f178a9 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't see? Bad link? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know about the specifics of this but it seems weird to me that we want to achieve a behaviour which is not achievable with an async generator. Feels a bit like outside of spec. Maybe I'm a bit too hung up on assuming async generator is the "correct" way. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Not dropping these events is why the implementation didn't use an async generator initially - it's OK to change that if you think the simplification is worth losing that API guarantee. It's true users who There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think so. But I'm not sure if my opinion is sufficient here. I don't understand why we wanted this API guarantee to begin with. |
||
const ee = new EventEmitter(); | ||
const iterable = on(ee, 'foo'); | ||
|
||
process.nextTick(function() { | ||
ee.emit('foo', 'bar'); | ||
ee.emit('foo', 42); | ||
iterable.return(); | ||
}); | ||
|
||
const results = await Promise.all([ | ||
iterable.next(), | ||
iterable.next(), | ||
iterable.next(), | ||
]); | ||
|
||
assert.deepStrictEqual(results, [{ | ||
value: ['bar'], | ||
done: false | ||
}, { | ||
value: [42], | ||
done: false | ||
}, { | ||
value: undefined, | ||
done: true | ||
}]); | ||
|
||
assert.deepStrictEqual(await iterable.next(), { | ||
value: undefined, | ||
done: true | ||
}); | ||
} | ||
|
||
async function nextError() { | ||
const ee = new EventEmitter(); | ||
const iterable = on(ee, 'foo'); | ||
|
@@ -177,44 +144,6 @@ async function nextError() { | |
assert.strictEqual(ee.listeners('error').length, 0); | ||
} | ||
|
||
async function iterableThrow() { | ||
const ee = new EventEmitter(); | ||
const iterable = on(ee, 'foo'); | ||
|
||
process.nextTick(() => { | ||
ee.emit('foo', 'bar'); | ||
ee.emit('foo', 42); // lost in the queue | ||
iterable.throw(_err); | ||
}); | ||
|
||
const _err = new Error('kaboom'); | ||
let thrown = false; | ||
|
||
assert.throws(() => { | ||
// No argument | ||
iterable.throw(); | ||
}, { | ||
message: 'The "EventEmitter.AsyncIterator" property must be' + | ||
' an instance of Error. Received undefined', | ||
name: 'TypeError' | ||
}); | ||
|
||
const expected = [['bar'], [42]]; | ||
|
||
try { | ||
for await (const event of iterable) { | ||
assert.deepStrictEqual(event, expected.shift()); | ||
} | ||
} catch (err) { | ||
thrown = true; | ||
assert.strictEqual(err, _err); | ||
} | ||
assert.strictEqual(thrown, true); | ||
assert.strictEqual(expected.length, 0); | ||
assert.strictEqual(ee.listenerCount('foo'), 0); | ||
assert.strictEqual(ee.listenerCount('error'), 0); | ||
} | ||
|
||
async function eventTarget() { | ||
const et = new EventTarget(); | ||
const tick = () => et.dispatchEvent(new Event('tick')); | ||
|
@@ -370,9 +299,7 @@ async function run() { | |
error, | ||
errorDelayed, | ||
throwInLoop, | ||
next, | ||
nextError, | ||
iterableThrow, | ||
eventTarget, | ||
errorListenerCount, | ||
nodeEventTarget, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the behavior here is to drop all events when the iterator is returned right?
So if I
.next()
5 times and then.return
I would get{ done: true, value: undefined }
on all 5?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, I believe so