Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
张重言
deno
提交
81905a86
D
deno
项目概览
张重言
/
deno
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
deno
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
81905a86
编写于
2月 10, 2020
作者:
C
Chris Knight
提交者:
GitHub
2月 10, 2020
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: Event emitter node polyfill (#3944)
上级
e1105a15
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
814 addition
and
23 deletion
+814
-23
std/node/README.md
std/node/README.md
+1
-1
std/node/events.ts
std/node/events.ts
+383
-0
std/node/events_test.ts
std/node/events_test.ts
+403
-0
std/node/module.ts
std/node/module.ts
+6
-2
std/node/os.ts
std/node/os.ts
+4
-20
std/node/util.ts
std/node/util.ts
+17
-0
未找到文件。
std/node/README.md
浏览文件 @
81905a86
...
...
@@ -16,7 +16,7 @@ deno standard library as it's a compatiblity module.
-
[ ] crypto
-
[ ] dgram
-
[ ] dns
-
[
] events
-
[
x
] events
-
[x] fs _partly_
-
[ ] http
-
[ ] http2
...
...
std/node/events.ts
0 → 100644
浏览文件 @
81905a86
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// Copyright (c) 2019 Denolibs authors. All rights reserved. MIT license.
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
import
{
validateIntegerRange
}
from
"
./util.ts
"
;
export
interface
WrappedFunction
extends
Function
{
listener
:
Function
;
}
/**
* See also https://nodejs.org/api/events.html
*/
export
default
class
EventEmitter
{
public
static
defaultMaxListeners
=
10
;
private
maxListeners
:
number
|
undefined
;
private
_events
:
Map
<
string
|
symbol
,
Array
<
Function
|
WrappedFunction
>>
;
public
constructor
()
{
this
.
_events
=
new
Map
();
}
private
_addListener
(
eventName
:
string
|
symbol
,
listener
:
Function
|
WrappedFunction
,
prepend
:
boolean
):
this
{
this
.
emit
(
"
newListener
"
,
eventName
,
listener
);
if
(
this
.
_events
.
has
(
eventName
))
{
const
listeners
=
this
.
_events
.
get
(
eventName
)
as
Array
<
Function
|
WrappedFunction
>
;
if
(
prepend
)
{
listeners
.
unshift
(
listener
);
}
else
{
listeners
.
push
(
listener
);
}
}
else
{
this
.
_events
.
set
(
eventName
,
[
listener
]);
}
const
max
=
this
.
getMaxListeners
();
if
(
max
>
0
&&
this
.
listenerCount
(
eventName
)
>
max
)
{
const
warning
=
new
Error
(
`Possible EventEmitter memory leak detected.
${
this
.
listenerCount
(
eventName
)}
${
eventName
.
toString
()}
listeners.
Use emitter.setMaxListeners() to increase limit`
);
warning
.
name
=
"
MaxListenersExceededWarning
"
;
console
.
warn
(
warning
);
}
return
this
;
}
/** Alias for emitter.on(eventName, listener). */
public
addListener
(
eventName
:
string
|
symbol
,
listener
:
Function
|
WrappedFunction
):
this
{
return
this
.
_addListener
(
eventName
,
listener
,
false
);
}
/**
* Synchronously calls each of the listeners registered for the event named
* eventName, in the order they were registered, passing the supplied
* arguments to each.
* @return true if the event had listeners, false otherwise
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public
emit
(
eventName
:
string
|
symbol
,
...
args
:
any
[]):
boolean
{
if
(
this
.
_events
.
has
(
eventName
))
{
const
listeners
=
(
this
.
_events
.
get
(
eventName
)
as
Function
[]).
slice
();
// We copy with slice() so array is not mutated during emit
for
(
const
listener
of
listeners
)
{
try
{
listener
.
apply
(
this
,
args
);
}
catch
(
err
)
{
this
.
emit
(
"
error
"
,
err
);
}
}
return
true
;
}
else
if
(
eventName
===
"
error
"
)
{
const
errMsg
=
args
.
length
>
0
?
args
[
0
]
:
Error
(
"
Unhandled error.
"
);
throw
errMsg
;
}
return
false
;
}
/**
* Returns an array listing the events for which the emitter has
* registered listeners.
*/
public
eventNames
():
[
string
|
symbol
]
{
return
Array
.
from
(
this
.
_events
.
keys
())
as
[
string
|
symbol
];
}
/**
* Returns the current max listener value for the EventEmitter which is
* either set by emitter.setMaxListeners(n) or defaults to
* EventEmitter.defaultMaxListeners.
*/
public
getMaxListeners
():
number
{
return
this
.
maxListeners
||
EventEmitter
.
defaultMaxListeners
;
}
/**
* Returns the number of listeners listening to the event named
* eventName.
*/
public
listenerCount
(
eventName
:
string
|
symbol
):
number
{
if
(
this
.
_events
.
has
(
eventName
))
{
return
(
this
.
_events
.
get
(
eventName
)
as
Function
[]).
length
;
}
else
{
return
0
;
}
}
private
_listeners
(
target
:
EventEmitter
,
eventName
:
string
|
symbol
,
unwrap
:
boolean
):
Function
[]
{
if
(
!
target
.
_events
.
has
(
eventName
))
{
return
[];
}
const
eventListeners
:
Function
[]
=
target
.
_events
.
get
(
eventName
)
as
Function
[];
return
unwrap
?
this
.
unwrapListeners
(
eventListeners
)
:
eventListeners
.
slice
(
0
);
}
private
unwrapListeners
(
arr
:
Function
[]):
Function
[]
{
const
unwrappedListeners
:
Function
[]
=
new
Array
(
arr
.
length
)
as
Function
[];
for
(
let
i
=
0
;
i
<
arr
.
length
;
i
++
)
{
unwrappedListeners
[
i
]
=
arr
[
i
][
"
listener
"
]
||
arr
[
i
];
}
return
unwrappedListeners
;
}
/** Returns a copy of the array of listeners for the event named eventName.*/
public
listeners
(
eventName
:
string
|
symbol
):
Function
[]
{
return
this
.
_listeners
(
this
,
eventName
,
true
);
}
/**
* Returns a copy of the array of listeners for the event named eventName,
* including any wrappers (such as those created by .once()).
*/
public
rawListeners
(
eventName
:
string
|
symbol
):
Array
<
Function
|
WrappedFunction
>
{
return
this
.
_listeners
(
this
,
eventName
,
false
);
}
/** Alias for emitter.removeListener(). */
public
off
(
eventName
:
string
|
symbol
,
listener
:
Function
):
this
{
return
this
.
removeListener
(
eventName
,
listener
);
}
/**
* Adds the listener function to the end of the listeners array for the event
* named eventName. No checks are made to see if the listener has already
* been added. Multiple calls passing the same combination of eventName and
* listener will result in the listener being added, and called, multiple
* times.
*/
public
on
(
eventName
:
string
|
symbol
,
listener
:
Function
|
WrappedFunction
):
this
{
return
this
.
addListener
(
eventName
,
listener
);
}
/**
* Adds a one-time listener function for the event named eventName. The next
* time eventName is triggered, this listener is removed and then invoked.
*/
public
once
(
eventName
:
string
|
symbol
,
listener
:
Function
):
this
{
const
wrapped
:
WrappedFunction
=
this
.
onceWrap
(
eventName
,
listener
);
this
.
on
(
eventName
,
wrapped
);
return
this
;
}
// Wrapped function that calls EventEmitter.removeListener(eventName, self) on execution.
private
onceWrap
(
eventName
:
string
|
symbol
,
listener
:
Function
):
WrappedFunction
{
const
wrapper
=
function
(
this
:
{
eventName
:
string
|
symbol
;
listener
:
Function
;
rawListener
:
Function
;
context
:
EventEmitter
;
},
...
args
:
any
[]
// eslint-disable-line @typescript-eslint/no-explicit-any
):
void
{
this
.
context
.
removeListener
(
this
.
eventName
,
this
.
rawListener
);
this
.
listener
.
apply
(
this
.
context
,
args
);
};
const
wrapperContext
=
{
eventName
:
eventName
,
listener
:
listener
,
rawListener
:
wrapper
,
context
:
this
};
const
wrapped
=
wrapper
.
bind
(
wrapperContext
);
wrapperContext
.
rawListener
=
wrapped
;
wrapped
.
listener
=
listener
;
return
wrapped
as
WrappedFunction
;
}
/**
* Adds the listener function to the beginning of the listeners array for the
* event named eventName. No checks are made to see if the listener has
* already been added. Multiple calls passing the same combination of
* eventName and listener will result in the listener being added, and
* called, multiple times.
*/
public
prependListener
(
eventName
:
string
|
symbol
,
listener
:
Function
|
WrappedFunction
):
this
{
return
this
.
_addListener
(
eventName
,
listener
,
true
);
}
/**
* Adds a one-time listener function for the event named eventName to the
* beginning of the listeners array. The next time eventName is triggered,
* this listener is removed, and then invoked.
*/
public
prependOnceListener
(
eventName
:
string
|
symbol
,
listener
:
Function
):
this
{
const
wrapped
:
WrappedFunction
=
this
.
onceWrap
(
eventName
,
listener
);
this
.
prependListener
(
eventName
,
wrapped
);
return
this
;
}
/** Removes all listeners, or those of the specified eventName. */
public
removeAllListeners
(
eventName
?:
string
|
symbol
):
this
{
if
(
this
.
_events
===
undefined
)
{
return
this
;
}
if
(
this
.
_events
.
has
(
eventName
))
{
const
listeners
=
(
this
.
_events
.
get
(
eventName
)
as
Array
<
Function
|
WrappedFunction
>
).
slice
();
// Create a copy; We use it AFTER it's deleted.
this
.
_events
.
delete
(
eventName
);
for
(
const
listener
of
listeners
)
{
this
.
emit
(
"
removeListener
"
,
eventName
,
listener
);
}
}
else
{
const
eventList
:
[
string
|
symbol
]
=
this
.
eventNames
();
eventList
.
map
((
value
:
string
|
symbol
)
=>
{
this
.
removeAllListeners
(
value
);
});
}
return
this
;
}
/**
* Removes the specified listener from the listener array for the event
* named eventName.
*/
public
removeListener
(
eventName
:
string
|
symbol
,
listener
:
Function
):
this
{
if
(
this
.
_events
.
has
(
eventName
))
{
const
arr
:
Array
<
Function
|
WrappedFunction
>
=
this
.
_events
.
get
(
eventName
);
let
listenerIndex
=
-
1
;
for
(
let
i
=
arr
.
length
-
1
;
i
>=
0
;
i
--
)
{
// arr[i]["listener"] is the reference to the listener inside a bound 'once' wrapper
if
(
arr
[
i
]
==
listener
||
arr
[
i
][
"
listener
"
]
==
listener
)
{
listenerIndex
=
i
;
break
;
}
}
if
(
listenerIndex
>=
0
)
{
arr
.
splice
(
listenerIndex
,
1
);
this
.
emit
(
"
removeListener
"
,
eventName
,
listener
);
if
(
arr
.
length
===
0
)
{
this
.
_events
.
delete
(
eventName
);
}
}
}
return
this
;
}
/**
* By default EventEmitters will print a warning if more than 10 listeners
* are added for a particular event. This is a useful default that helps
* finding memory leaks. Obviously, not all events should be limited to just
* 10 listeners. The emitter.setMaxListeners() method allows the limit to be
* modified for this specific EventEmitter instance. The value can be set to
* Infinity (or 0) to indicate an unlimited number of listeners.
*/
public
setMaxListeners
(
n
:
number
):
this
{
validateIntegerRange
(
n
,
"
maxListeners
"
,
0
);
this
.
maxListeners
=
n
;
return
this
;
}
}
/**
* Creates a Promise that is fulfilled when the EventEmitter emits the given
* event or that is rejected when the EventEmitter emits 'error'. The Promise
* will resolve with an array of all the arguments emitted to the given event.
*/
export
function
once
(
emitter
:
EventEmitter
|
EventTarget
,
name
:
string
// eslint-disable-next-line @typescript-eslint/no-explicit-any
):
Promise
<
any
[]
>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
if
(
emitter
instanceof
EventTarget
)
{
// EventTarget does not have `error` event semantics like Node
// EventEmitters, we do not listen to `error` events here.
emitter
.
addEventListener
(
name
,
(...
args
)
=>
{
resolve
(
args
);
},
{
once
:
true
,
passive
:
false
,
capture
:
false
}
);
return
;
}
else
if
(
emitter
instanceof
EventEmitter
)
{
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const
eventListener
=
(...
args
:
any
[]):
void
=>
{
if
(
errorListener
!==
undefined
)
{
emitter
.
removeListener
(
"
error
"
,
errorListener
);
}
resolve
(
args
);
};
let
errorListener
:
Function
;
// Adding an error listener is not optional because
// if an error is thrown on an event emitter we cannot
// guarantee that the actual event we are waiting will
// be fired. The result could be a silent way to create
// memory or file descriptor leaks, which is something
// we should avoid.
if
(
name
!==
"
error
"
)
{
// eslint-disable-next-line @typescript-eslint/no-explicit-any
errorListener
=
(
err
:
any
):
void
=>
{
emitter
.
removeListener
(
name
,
eventListener
);
reject
(
err
);
};
emitter
.
once
(
"
error
"
,
errorListener
);
}
emitter
.
once
(
name
,
eventListener
);
return
;
}
});
}
std/node/events_test.ts
0 → 100644
浏览文件 @
81905a86
import
{
test
}
from
"
../testing/mod.ts
"
;
import
{
assert
,
assertEquals
,
fail
,
assertThrows
}
from
"
../testing/asserts.ts
"
;
import
EventEmitter
,
{
WrappedFunction
,
once
}
from
"
./events.ts
"
;
const
shouldNeverBeEmitted
:
Function
=
()
=>
{
fail
(
"
Should never be called
"
);
};
test
({
name
:
'
When adding a new event, "eventListener" event is fired before adding the listener
'
,
fn
()
{
let
eventsFired
=
[];
const
testEmitter
=
new
EventEmitter
();
testEmitter
.
on
(
"
newListener
"
,
event
=>
{
if
(
event
!==
"
newListener
"
)
{
eventsFired
.
push
(
"
newListener
"
);
}
});
testEmitter
.
on
(
"
event
"
,
()
=>
{
eventsFired
.
push
(
"
event
"
);
});
assertEquals
(
eventsFired
,
[
"
newListener
"
]);
eventsFired
=
[];
testEmitter
.
emit
(
"
event
"
);
assertEquals
(
eventsFired
,
[
"
event
"
]);
}
});
test
({
name
:
'
When removing a listenert, "removeListener" event is fired after removal
'
,
fn
()
{
const
eventsFired
=
[];
const
testEmitter
=
new
EventEmitter
();
testEmitter
.
on
(
"
removeListener
"
,
()
=>
{
eventsFired
.
push
(
"
removeListener
"
);
});
const
eventFunction
=
function
():
void
{
eventsFired
.
push
(
"
event
"
);
};
testEmitter
.
on
(
"
event
"
,
eventFunction
);
assertEquals
(
eventsFired
,
[]);
testEmitter
.
removeListener
(
"
event
"
,
eventFunction
);
assertEquals
(
eventsFired
,
[
"
removeListener
"
]);
}
});
test
({
name
:
"
Default max listeners is 10, but can be changed by direct assignment only
"
,
fn
()
{
assertEquals
(
EventEmitter
.
defaultMaxListeners
,
10
);
new
EventEmitter
().
setMaxListeners
(
20
);
assertEquals
(
EventEmitter
.
defaultMaxListeners
,
10
);
EventEmitter
.
defaultMaxListeners
=
20
;
assertEquals
(
EventEmitter
.
defaultMaxListeners
,
20
);
EventEmitter
.
defaultMaxListeners
=
10
;
//reset back to original value
}
});
test
({
name
:
"
addListener adds a listener, and listener count is correct
"
,
fn
()
{
const
testEmitter
=
new
EventEmitter
();
testEmitter
.
on
(
"
event
"
,
shouldNeverBeEmitted
);
assertEquals
(
1
,
testEmitter
.
listenerCount
(
"
event
"
));
testEmitter
.
on
(
"
event
"
,
shouldNeverBeEmitted
);
assertEquals
(
2
,
testEmitter
.
listenerCount
(
"
event
"
));
}
});
test
({
name
:
"
Emitted events are called synchronously in the order they were added
"
,
fn
()
{
const
testEmitter
=
new
EventEmitter
();
const
eventsFired
=
[];
testEmitter
.
on
(
"
event
"
,
oneArg
=>
{
eventsFired
.
push
(
"
event(
"
+
oneArg
+
"
)
"
);
});
testEmitter
.
on
(
"
event
"
,
(
oneArg
,
twoArg
)
=>
{
eventsFired
.
push
(
"
event(
"
+
oneArg
+
"
,
"
+
twoArg
+
"
)
"
);
});
testEmitter
.
on
(
"
non-event
"
,
shouldNeverBeEmitted
);
testEmitter
.
on
(
"
event
"
,
(
oneArg
,
twoArg
,
threeArg
)
=>
{
eventsFired
.
push
(
"
event(
"
+
oneArg
+
"
,
"
+
twoArg
+
"
,
"
+
threeArg
+
"
)
"
);
});
testEmitter
.
emit
(
"
event
"
,
1
,
2
,
3
);
assertEquals
(
eventsFired
,
[
"
event(1)
"
,
"
event(1, 2)
"
,
"
event(1, 2, 3)
"
]);
}
});
test
({
name
:
"
Registered event names are returned as strings or Sybols
"
,
fn
()
{
const
testEmitter
=
new
EventEmitter
();
testEmitter
.
on
(
"
event
"
,
shouldNeverBeEmitted
);
testEmitter
.
on
(
"
event
"
,
shouldNeverBeEmitted
);
const
sym
=
Symbol
(
"
symbol
"
);
testEmitter
.
on
(
sym
,
shouldNeverBeEmitted
);
assertEquals
(
testEmitter
.
eventNames
(),
[
"
event
"
,
sym
]);
}
});
test
({
name
:
"
You can set and get max listeners
"
,
fn
()
{
const
testEmitter
=
new
EventEmitter
();
assertEquals
(
testEmitter
.
getMaxListeners
(),
10
);
testEmitter
.
setMaxListeners
(
20
);
assertEquals
(
testEmitter
.
getMaxListeners
(),
20
);
}
});
test
({
name
:
"
You can retrieve registered functions for an event
"
,
fn
()
{
const
testEmitter
=
new
EventEmitter
();
testEmitter
.
on
(
"
someOtherEvent
"
,
shouldNeverBeEmitted
);
testEmitter
.
on
(
"
event
"
,
shouldNeverBeEmitted
);
const
testFunction
=
():
void
=>
{};
testEmitter
.
on
(
"
event
"
,
testFunction
);
assertEquals
(
testEmitter
.
listeners
(
"
event
"
),
[
shouldNeverBeEmitted
,
testFunction
]);
}
});
test
({
name
:
"
Off is alias for removeListener
"
,
fn
()
{
const
testEmitter
=
new
EventEmitter
();
testEmitter
.
on
(
"
event
"
,
shouldNeverBeEmitted
);
assertEquals
(
testEmitter
.
listenerCount
(
"
event
"
),
1
);
testEmitter
.
off
(
"
event
"
,
shouldNeverBeEmitted
);
assertEquals
(
testEmitter
.
listenerCount
(
"
event
"
),
0
);
}
});
test
({
name
:
"
Event registration can be chained
"
,
fn
()
{
const
testEmitter
=
new
EventEmitter
();
testEmitter
.
on
(
"
event
"
,
shouldNeverBeEmitted
)
.
on
(
"
event
"
,
shouldNeverBeEmitted
);
assertEquals
(
testEmitter
.
listenerCount
(
"
event
"
),
2
);
}
});
test
({
name
:
"
Events can be registered to only fire once
"
,
fn
()
{
let
eventsFired
=
[];
const
testEmitter
=
new
EventEmitter
();
//prove multiple emits on same event first (when registered with 'on')
testEmitter
.
on
(
"
multiple event
"
,
()
=>
{
eventsFired
.
push
(
"
multiple event
"
);
});
testEmitter
.
emit
(
"
multiple event
"
);
testEmitter
.
emit
(
"
multiple event
"
);
assertEquals
(
eventsFired
,
[
"
multiple event
"
,
"
multiple event
"
]);
//now prove multiple events registered via 'once' only emit once
eventsFired
=
[];
testEmitter
.
once
(
"
single event
"
,
()
=>
{
eventsFired
.
push
(
"
single event
"
);
});
testEmitter
.
emit
(
"
single event
"
);
testEmitter
.
emit
(
"
single event
"
);
assertEquals
(
eventsFired
,
[
"
single event
"
]);
}
});
test
({
name
:
"
You can inject a listener into the start of the stack, rather than at the end
"
,
fn
()
{
const
eventsFired
=
[];
const
testEmitter
=
new
EventEmitter
();
testEmitter
.
on
(
"
event
"
,
()
=>
{
eventsFired
.
push
(
"
first
"
);
});
testEmitter
.
on
(
"
event
"
,
()
=>
{
eventsFired
.
push
(
"
second
"
);
});
testEmitter
.
prependListener
(
"
event
"
,
()
=>
{
eventsFired
.
push
(
"
third
"
);
});
testEmitter
.
emit
(
"
event
"
);
assertEquals
(
eventsFired
,
[
"
third
"
,
"
first
"
,
"
second
"
]);
}
});
test
({
name
:
'
You can prepend a "once" listener
'
,
fn
()
{
const
eventsFired
=
[];
const
testEmitter
=
new
EventEmitter
();
testEmitter
.
on
(
"
event
"
,
()
=>
{
eventsFired
.
push
(
"
first
"
);
});
testEmitter
.
on
(
"
event
"
,
()
=>
{
eventsFired
.
push
(
"
second
"
);
});
testEmitter
.
prependOnceListener
(
"
event
"
,
()
=>
{
eventsFired
.
push
(
"
third
"
);
});
testEmitter
.
emit
(
"
event
"
);
testEmitter
.
emit
(
"
event
"
);
assertEquals
(
eventsFired
,
[
"
third
"
,
"
first
"
,
"
second
"
,
"
first
"
,
"
second
"
]);
}
});
test
({
name
:
"
Remove all listeners, which can also be chained
"
,
fn
()
{
const
testEmitter
=
new
EventEmitter
();
testEmitter
.
on
(
"
event
"
,
shouldNeverBeEmitted
);
testEmitter
.
on
(
"
event
"
,
shouldNeverBeEmitted
);
testEmitter
.
on
(
"
other event
"
,
shouldNeverBeEmitted
);
testEmitter
.
on
(
"
other event
"
,
shouldNeverBeEmitted
);
testEmitter
.
once
(
"
other event
"
,
shouldNeverBeEmitted
);
assertEquals
(
testEmitter
.
listenerCount
(
"
event
"
),
2
);
assertEquals
(
testEmitter
.
listenerCount
(
"
other event
"
),
3
);
testEmitter
.
removeAllListeners
(
"
event
"
).
removeAllListeners
(
"
other event
"
);
assertEquals
(
testEmitter
.
listenerCount
(
"
event
"
),
0
);
assertEquals
(
testEmitter
.
listenerCount
(
"
other event
"
),
0
);
}
});
test
({
name
:
"
Remove individual listeners, which can also be chained
"
,
fn
()
{
const
testEmitter
=
new
EventEmitter
();
testEmitter
.
on
(
"
event
"
,
shouldNeverBeEmitted
);
testEmitter
.
on
(
"
event
"
,
shouldNeverBeEmitted
);
testEmitter
.
once
(
"
other event
"
,
shouldNeverBeEmitted
);
assertEquals
(
testEmitter
.
listenerCount
(
"
event
"
),
2
);
assertEquals
(
testEmitter
.
listenerCount
(
"
other event
"
),
1
);
testEmitter
.
removeListener
(
"
other event
"
,
shouldNeverBeEmitted
);
assertEquals
(
testEmitter
.
listenerCount
(
"
event
"
),
2
);
assertEquals
(
testEmitter
.
listenerCount
(
"
other event
"
),
0
);
testEmitter
.
removeListener
(
"
event
"
,
shouldNeverBeEmitted
)
.
removeListener
(
"
event
"
,
shouldNeverBeEmitted
);
assertEquals
(
testEmitter
.
listenerCount
(
"
event
"
),
0
);
assertEquals
(
testEmitter
.
listenerCount
(
"
other event
"
),
0
);
}
});
test
({
name
:
"
It is OK to try to remove non-existant listener
"
,
fn
()
{
const
testEmitter
=
new
EventEmitter
();
const
madeUpEvent
=
():
void
=>
{
fail
(
"
Should never be called
"
);
};
testEmitter
.
on
(
"
event
"
,
shouldNeverBeEmitted
);
assertEquals
(
testEmitter
.
listenerCount
(
"
event
"
),
1
);
testEmitter
.
removeListener
(
"
event
"
,
madeUpEvent
);
testEmitter
.
removeListener
(
"
non-existant event
"
,
madeUpEvent
);
assertEquals
(
testEmitter
.
listenerCount
(
"
event
"
),
1
);
}
});
test
({
name
:
"
all listeners complete execution even if removed before execution
"
,
fn
()
{
const
testEmitter
=
new
EventEmitter
();
let
eventsProcessed
=
[];
const
listenerB
=
():
number
=>
eventsProcessed
.
push
(
"
B
"
);
const
listenerA
=
():
void
=>
{
eventsProcessed
.
push
(
"
A
"
);
testEmitter
.
removeListener
(
"
event
"
,
listenerB
);
};
testEmitter
.
on
(
"
event
"
,
listenerA
);
testEmitter
.
on
(
"
event
"
,
listenerB
);
testEmitter
.
emit
(
"
event
"
);
assertEquals
(
eventsProcessed
,
[
"
A
"
,
"
B
"
]);
eventsProcessed
=
[];
testEmitter
.
emit
(
"
event
"
);
assertEquals
(
eventsProcessed
,
[
"
A
"
]);
}
});
test
({
name
:
'
Raw listener will return event listener or wrapped "once" function
'
,
fn
()
{
const
testEmitter
=
new
EventEmitter
();
const
eventsProcessed
=
[];
const
listenerA
=
():
number
=>
eventsProcessed
.
push
(
"
A
"
);
const
listenerB
=
():
number
=>
eventsProcessed
.
push
(
"
B
"
);
testEmitter
.
on
(
"
event
"
,
listenerA
);
testEmitter
.
once
(
"
once-event
"
,
listenerB
);
const
rawListenersForEvent
=
testEmitter
.
rawListeners
(
"
event
"
);
const
rawListenersForOnceEvent
=
testEmitter
.
rawListeners
(
"
once-event
"
);
assertEquals
(
rawListenersForEvent
.
length
,
1
);
assertEquals
(
rawListenersForOnceEvent
.
length
,
1
);
assertEquals
(
rawListenersForEvent
[
0
],
listenerA
);
assertEquals
(
(
rawListenersForOnceEvent
[
0
]
as
WrappedFunction
).
listener
,
listenerB
);
}
});
test
({
name
:
"
Once wrapped raw listeners may be executed multiple times, until the wrapper is executed
"
,
fn
()
{
const
testEmitter
=
new
EventEmitter
();
let
eventsProcessed
=
[];
const
listenerA
=
():
number
=>
eventsProcessed
.
push
(
"
A
"
);
testEmitter
.
once
(
"
once-event
"
,
listenerA
);
const
rawListenersForOnceEvent
=
testEmitter
.
rawListeners
(
"
once-event
"
);
const
wrappedFn
:
WrappedFunction
=
rawListenersForOnceEvent
[
0
]
as
WrappedFunction
;
wrappedFn
.
listener
();
wrappedFn
.
listener
();
wrappedFn
.
listener
();
assertEquals
(
eventsProcessed
,
[
"
A
"
,
"
A
"
,
"
A
"
]);
eventsProcessed
=
[];
wrappedFn
();
// executing the wrapped listener function will remove it from the event
assertEquals
(
eventsProcessed
,
[
"
A
"
]);
assertEquals
(
testEmitter
.
listeners
(
"
once-event
"
).
length
,
0
);
}
});
test
({
name
:
"
Can add once event listener to EventEmitter via standalone function
"
,
async
fn
()
{
const
ee
:
EventEmitter
=
new
EventEmitter
();
setTimeout
(()
=>
{
ee
.
emit
(
"
event
"
,
42
,
"
foo
"
);
},
0
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const
valueArr
:
any
[]
=
await
once
(
ee
,
"
event
"
);
assertEquals
(
valueArr
,
[
42
,
"
foo
"
]);
}
});
test
({
name
:
"
Can add once event listener to EventTarget via standalone function
"
,
async
fn
()
{
const
et
:
EventTarget
=
new
EventTarget
();
setTimeout
(()
=>
{
const
event
:
Event
=
new
Event
(
"
event
"
,
{
composed
:
true
});
et
.
dispatchEvent
(
event
);
},
0
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const
eventObj
:
any
[]
=
await
once
(
et
,
"
event
"
);
assert
(
!
eventObj
[
0
].
isTrusted
);
}
});
test
({
name
:
"
Only valid integers are allowed for max listeners
"
,
fn
()
{
const
ee
:
EventEmitter
=
new
EventEmitter
();
ee
.
setMaxListeners
(
0
);
assertThrows
(
()
=>
{
ee
.
setMaxListeners
(
-
1
);
},
Error
,
"
must be >= 0
"
);
assertThrows
(
()
=>
{
ee
.
setMaxListeners
(
3.45
);
},
Error
,
"
must be 'an integer'
"
);
}
});
std/node/module.ts
浏览文件 @
81905a86
...
...
@@ -26,6 +26,7 @@ import * as nodeUtil from "./util.ts";
import
*
as
nodePath
from
"
./path.ts
"
;
import
*
as
nodeTimers
from
"
./timers.ts
"
;
import
*
as
nodeOs
from
"
./os.ts
"
;
import
*
as
nodeEvents
from
"
./events.ts
"
;
import
*
as
path
from
"
../path/mod.ts
"
;
import
{
assert
}
from
"
../testing/asserts.ts
"
;
...
...
@@ -579,11 +580,14 @@ function createNativeModule(id: string, exports: any): Module {
mod
.
loaded
=
true
;
return
mod
;
}
nativeModulePolyfill
.
set
(
"
fs
"
,
createNativeModule
(
"
fs
"
,
nodeFS
));
nativeModulePolyfill
.
set
(
"
util
"
,
createNativeModule
(
"
util
"
,
nodeUtil
));
nativeModulePolyfill
.
set
(
"
events
"
,
createNativeModule
(
"
events
"
,
nodeEvents
));
nativeModulePolyfill
.
set
(
"
os
"
,
createNativeModule
(
"
os
"
,
nodeOs
));
nativeModulePolyfill
.
set
(
"
path
"
,
createNativeModule
(
"
path
"
,
nodePath
));
nativeModulePolyfill
.
set
(
"
timers
"
,
createNativeModule
(
"
timers
"
,
nodeTimers
));
nativeModulePolyfill
.
set
(
"
os
"
,
createNativeModule
(
"
os
"
,
nodeOs
));
nativeModulePolyfill
.
set
(
"
util
"
,
createNativeModule
(
"
util
"
,
nodeUtil
));
function
loadNativeModule
(
_filename
:
string
,
request
:
string
...
...
std/node/os.ts
浏览文件 @
81905a86
...
...
@@ -19,6 +19,7 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
import
{
notImplemented
}
from
"
./_utils.ts
"
;
import
{
validateIntegerRange
}
from
"
./util.ts
"
;
import
{
EOL
as
fsEOL
}
from
"
../fs/eol.ts
"
;
const
SEE_GITHUB_ISSUE
=
"
See https://github.com/denoland/deno/issues/3802
"
;
...
...
@@ -117,7 +118,7 @@ export function freemem(): number {
/** Not yet implemented */
export
function
getPriority
(
pid
=
0
):
number
{
validateInt
32
(
pid
,
"
pid
"
);
validateInt
egerRange
(
pid
,
"
pid
"
);
notImplemented
(
SEE_GITHUB_ISSUE
);
}
...
...
@@ -162,8 +163,8 @@ export function setPriority(pid: number, priority?: number): void {
priority
=
pid
;
pid
=
0
;
}
validateInt
32
(
pid
,
"
pid
"
);
validateInt
32
(
priority
,
"
priority
"
,
-
20
,
19
);
validateInt
egerRange
(
pid
,
"
pid
"
);
validateInt
egerRange
(
priority
,
"
priority
"
,
-
20
,
19
);
notImplemented
(
SEE_GITHUB_ISSUE
);
}
...
...
@@ -211,20 +212,3 @@ export const constants = {
};
export
const
EOL
=
Deno
.
build
.
os
==
"
win
"
?
fsEOL
.
CRLF
:
fsEOL
.
LF
;
const
validateInt32
=
(
value
:
number
,
name
:
string
,
min
=
-
2147483648
,
max
=
2147483647
):
void
=>
{
// The defaults for min and max correspond to the limits of 32-bit integers.
if
(
!
Number
.
isInteger
(
value
))
{
throw
new
Error
(
`
${
name
}
must be 'an integer' but was
${
value
}
`
);
}
if
(
value
<
min
||
value
>
max
)
{
throw
new
Error
(
`
${
name
}
must be >=
${
min
}
&& <=
${
max
}
. Value was
${
value
}
`
);
}
};
std/node/util.ts
浏览文件 @
81905a86
...
...
@@ -45,3 +45,20 @@ export function isFunction(value: unknown): boolean {
export
function
isRegExp
(
value
:
unknown
):
boolean
{
return
value
instanceof
RegExp
;
}
export
function
validateIntegerRange
(
value
:
number
,
name
:
string
,
min
=
-
2147483648
,
max
=
2147483647
):
void
{
// The defaults for min and max correspond to the limits of 32-bit integers.
if
(
!
Number
.
isInteger
(
value
))
{
throw
new
Error
(
`
${
name
}
must be 'an integer' but was
${
value
}
`
);
}
if
(
value
<
min
||
value
>
max
)
{
throw
new
Error
(
`
${
name
}
must be >=
${
min
}
&& <=
${
max
}
. Value was
${
value
}
`
);
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录