Fixed a bug when onUndeliveredElement was invoked for normally-receive elements on JS (#2828)

Fixes #2826
diff --git a/kotlinx-coroutines-core/common/test/channels/ChannelUndeliveredElementTest.kt b/kotlinx-coroutines-core/common/test/channels/ChannelUndeliveredElementTest.kt
index 9915d38..f26361f 100644
--- a/kotlinx-coroutines-core/common/test/channels/ChannelUndeliveredElementTest.kt
+++ b/kotlinx-coroutines-core/common/test/channels/ChannelUndeliveredElementTest.kt
@@ -123,4 +123,19 @@
             check(!_cancelled.getAndSet(true)) { "Already cancelled" }
         }
     }
+
+    @Test
+    fun testHandlerIsNotInvoked() = runTest { // #2826
+        val channel = Channel<Unit> {
+            expectUnreached()
+        }
+
+        expect(1)
+        launch {
+            expect(2)
+            channel.receive()
+        }
+        channel.send(Unit)
+        finish(3)
+    }
 }
diff --git a/kotlinx-coroutines-core/js/src/internal/LinkedList.kt b/kotlinx-coroutines-core/js/src/internal/LinkedList.kt
index f2711f5..147b31d 100644
--- a/kotlinx-coroutines-core/js/src/internal/LinkedList.kt
+++ b/kotlinx-coroutines-core/js/src/internal/LinkedList.kt
@@ -32,7 +32,18 @@
         this._prev = node
     }
 
+    /*
+     * Remove that is invoked as a virtual function with a
+     * potentially augmented behaviour.
+     * I.g. `LockFreeLinkedListHead` throws, while `SendElementWithUndeliveredHandler`
+     * invokes handler on remove
+     */
     public open fun remove(): Boolean {
+        return removeImpl()
+    }
+
+    @PublishedApi
+    internal fun removeImpl(): Boolean {
         if (_removed) return false
         val prev = this._prev
         val next = this._next
@@ -76,7 +87,7 @@
     public fun removeFirstOrNull(): Node? {
         val next = _next
         if (next === this) return null
-        check(next.remove()) { "Should remove" }
+        check(next.removeImpl()) { "Should remove" }
         return next
     }
 
@@ -85,7 +96,7 @@
         if (next === this) return null
         if (next !is T) return null
         if (predicate(next)) return next
-        check(next.remove()) { "Should remove" }
+        check(next.removeImpl()) { "Should remove" }
         return next
     }
 }