'Unable to remove an arrow function event listener

EDIT-01: Here is a jsfiddle of an earlier answer attempt I altered to show the behavior I expect to happen: https://jsfiddle.net/avwon/mjagkvo8/

EDIT-02: Codepen demonstrating how addEventListener() and removeEventListener() should behave: https://codepen.io/avwon/pen/RwjXNPv?editors=1111 - this probably means that Youtube API is broken or doesn't behave as expected. I hate my life This means there is no definitive solution to my question. Now knowing the root issue I was able to find other reports of this issue dating back 7.5 years. As suggested on that thread, the best option is to wrap the onStateChange event with a custom EventTarget object because I think an AbortController wouldn't work either with Youtube's custom add/rmvEventListener.

I am trying to interact with a Youtube Embed API via a YoutubeHandler I am making. Since the API is only an interface to the player in an iframe with processing/buffering between calls I need to listen to state change events to be sure. Everything works fine except I am not sure why the state listeners are not being removed, it seems that I am using the same reference when adding and removing the listener. The Promise resolves just fine but the listener stays attached. Is there anything else I am missing? I am sure I am probably not accounting for something regarding scope. What is the next best way to solve this? I need to be able to reach the resolve() reject() of the Promise. I would like to figure this out but before trying to use an AbortController to remove the listener. Using Typescript with ES6.

Within my YoutubeHandler class (in a ts file), my play() is very similar to this pause() so it has the same issue:

    async pause(onTime?: Time): Promise<boolean> {
        console.log("YOUTUBE-handler: Pausing video", this.player);
        this.pauseIgnore ++; // Increase pause ignore
        return new Promise(((resolve,reject) => {
            // Event handler that awaits and resolves the pause promise when it occurs
            let pauseAwait = (event: any)=>{
                // Remove this event handler from future events
                console.log("DELETED PAUSE AWAIT",this.player,pauseAwait);
                this.player.removeEventListener(YTEvent.STATE_CHANGE,pauseAwait);
                // Resolve or reject
                if(event.data != undefined){
                    if (event.data == YTPlayerState.PAUSED) {
                        resolve(true);
                    } else { // TODO timeout reject
                        reject("Did not receive a pause state. Received: "+ event.data);
                    }
                } else {
                    throw new Error("onStateChange event did not provide a data")
                }
            }
            console.log("STARTED PAUSE AWAIT",this.player)
            this.player.addEventListener(YTEvent.STATE_CHANGE, pauseAwait);
            this.player.pauseVideo();
        }));
    }

The compiled ES6 JS code looks practically identical.

This is what my browser console log looks like after several play (event.data = 1) and pause (event.data = 1) events:

Image of chrome console log

youtube-handler.ts:117 YOUTUBE-handler: Playing video An {i: nn, h: iframe#player, m: null, j: 2, u: true, …}
youtube-handler.ts:150 STARTED PLAY AWAIT An {i: nn, h: iframe#player, m: null, j: 2, u: true, …}
youtube-handler.ts:101 YT Handler  -1 {video_id: '<vid>', author: '', title: '<title>'}
youtube-handler.ts:101 YT Handler  3 {video_id: '<vid>', author: '', title: '<title>'}
youtube-handler.ts:101 YT Handler  -1 {video_id: '<vid>', author: '<author>', title: '<title>', video_quality: 'hd720', video_quality_features: Array(0)}
youtube-handler.ts:101 YT Handler  3 {video_id: '<vid>', author: '<author>', title: '<title>', video_quality: 'hd720', video_quality_features: Array(0)}
youtube-handler.ts:101 YT Handler  1 {video_id: '<vid>', author: '<author>', title: '<title>', video_quality: 'hd720', video_quality_features: Array(0)}
youtube-handler.ts:126 DELETED PLAY AWAIT An {i: nn, h: iframe#player, m: null, j: 2, u: true, …} (event) => {
                    // Remove this event handler from future events
                    const rmvListener = () => {
                        console.log("DELETED PLAY AWAIT", this.play…

<...>

youtube-handler.ts:160 YOUTUBE-handler: Pausing video An {i: nn, h: iframe#player, m: null, j: 2, u: true, …}
youtube-handler.ts:181 STARTED PAUSE AWAIT An {i: nn, h: iframe#player, m: null, j: 2, u: true, …}
youtube-handler.ts:101 YT Handler  2 {video_id: '<vid>', author: '<author>', title: '<title>', video_quality: 'hd720', video_quality_features: Array(0)}
youtube-handler.ts:126 DELETED PLAY AWAIT An {i: nn, h: iframe#player, m: null, j: 2, u: true, …} (event) => {
                    // Remove this event handler from future events
                    const rmvListener = () => {
                        console.log("DELETED PLAY AWAIT", this.play…
youtube-handler.ts:168 DELETED PAUSE AWAIT An {i: nn, h: iframe#player, m: null, j: 2, u: true, …} (event) => {
                    // Remove this event handler from future events
                    console.log("DELETED PAUSE AWAIT", this.player, pauseAwait);
                    this.player.re…

<...>

youtube-handler.ts:117 YOUTUBE-handler: Playing video An {i: nn, h: iframe#player, m: null, j: 2, u: true, …}
youtube-handler.ts:150 STARTED PLAY AWAIT An {i: nn, h: iframe#player, m: null, j: 2, u: true, …}
youtube-handler.ts:101 YT Handler  1 {video_id: '<vid>', author: '<author>', title: '<title>', video_quality: 'hd720', video_quality_features: Array(0)}
youtube-handler.ts:126 DELETED PLAY AWAIT An {i: nn, h: iframe#player, m: null, j: 2, u: true, …} (event) => {
                    // Remove this event handler from future events
                    const rmvListener = () => {
                        console.log("DELETED PLAY AWAIT", this.play…
youtube-handler.ts:168 DELETED PAUSE AWAIT An {i: nn, h: iframe#player, m: null, j: 2, u: true, …} (event) => {
                    // Remove this event handler from future events
                    console.log("DELETED PAUSE AWAIT", this.player, pauseAwait);
                    this.player.re…
youtube-handler.ts:126 DELETED PLAY AWAIT An {i: nn, h: iframe#player, m: null, j: 2, u: true, …} (event) => {
                    // Remove this event handler from future events
                    const rmvListener = () => {
                        console.log("DELETED PLAY AWAIT", this.play…

<...>

youtube-handler.ts:160 YOUTUBE-handler: Pausing video An {i: nn, h: iframe#player, m: null, j: 2, u: true, …}
youtube-handler.ts:181 STARTED PAUSE AWAIT An {i: nn, h: iframe#player, m: null, j: 2, u: true, …}
youtube-handler.ts:101 YT Handler  2 {video_id: '<vid>', author: '<author>', title: '<title>', video_quality: 'hd720', video_quality_features: Array(0)}
youtube-handler.ts:126 DELETED PLAY AWAIT An {i: nn, h: iframe#player, m: null, j: 2, u: true, …} (event) => {
                    // Remove this event handler from future events
                    const rmvListener = () => {
                        console.log("DELETED PLAY AWAIT", this.play…
youtube-handler.ts:168 DELETED PAUSE AWAIT An {i: nn, h: iframe#player, m: null, j: 2, u: true, …} (event) => {
                    // Remove this event handler from future events
                    console.log("DELETED PAUSE AWAIT", this.player, pauseAwait);
                    this.player.re…
youtube-handler.ts:126 DELETED PLAY AWAIT An {i: nn, h: iframe#player, m: null, j: 2, u: true, …} (event) => {
                    // Remove this event handler from future events
                    const rmvListener = () => {
                        console.log("DELETED PLAY AWAIT", this.play…
youtube-handler.ts:168 DELETED PAUSE AWAIT An {i: nn, h: iframe#player, m: null, j: 2, u: true, …} (event) => {
                    // Remove this event handler from future events
                    console.log("DELETED PAUSE AWAIT", this.player, pauseAwait);
                    this.player.re…

You can see that the play listener stayed attached and the pause listener will stay attached aswell resulting in continuously stacking "DELETED PLAY AWAIT, DELETED PAUSE AWAIT, DELETED PLAY AWAIT..." messages with each play and pause.

Thanks!



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source