question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[BUG] GM_addValueChangeListener ignores the first change from 3rd+ instance of script

See original GitHub issue
  • I have searched for existing issues that already reported this problem and found none

Describe the bug When running a script in multiple tabs, GM_addValueChangeListener in the first tab will ignore the first change made by the 3rd+ instance of the same script.

To Reproduce I’ve made an example script using the concept of having a “host”, which is the first instance of the script, with subsequent instances of the script attempting to change a value to check if this “host” is already present. You can read the code comments to fully understand what is going on. In short, though, what is going on is the following:

  1. “present” is set to false
  2. if it is not set to true within 500ms, the script will become a “host”
  3. new script is loaded, and also sets present to true
  4. the original “host” sets present back to false. This causes the script to know that it is already loaded because another “host” is already present.
// ==UserScript==
// @name        Test GM_addValueChangeListener 
// @namespace   Violentmonkey Scripts
// @match       *://example.com/*
// @grant       GM_setValue
// @grant       GM_getValue
// @grant       GM_addValueChangeListener
// @version     1.0
// @author      Levi_OP
// @description 4/8/2022, 2:03:57 PM
// ==/UserScript==

// This code (in the if statement) only runs on the first time the script is executed. If the "present" value is undefined, it will be set to true and the script will assume the role of "host".
if (GM_getValue("present") === undefined) {
    console.log('first time setup and becoming "host"')
    GM_setValue("present", true);
    GM_addValueChangeListener("present", (_name, oldValue, newValue, _remote) => {
        console.log("present changed from %o to %o", oldValue, newValue)
        if (!newValue) GM_setValue("present", true)
    })
} else { // This code will run every time after the first run ("present" is defined)
    GM_setValue("present", false); // First, "present" is set to false.
    // Then, a timeout is set for half a second. If not cleared by the code below the timeout, it will assume the role of "host".
    const timeout = setTimeout(() => { 
        console.log('response timeout. becoming "host"')
        GM_setValue("present", true) // Setting present back to true (default, as the host is "preset")
        // Event listener is added which ensures that if "present" is changed, it will be changed back immediately.
        GM_addValueChangeListener("present", (_name, oldValue, newValue, _remote) => {
            console.log("present changed from %o to %o", oldValue, newValue) // This also logs every time "present" is being changed. This shows that the 3rd+ instance is skipped.
            if (newValue === false) GM_setValue("present", true)
        })
    }, 500)

    // This event listener is added at the same time as the timeout. If "present" is changed back to true after we set it to false above, then we know that the host is present. We then clear the timeout so that our script does not try to become the new "host". 
    GM_addValueChangeListener("present", (_name, _oldValue, newValue, remote) => {
        if (!remote) return;
        if (newValue) {
            clearTimeout(timeout)
            console.log("response")
        }
    })
}

Steps to reproduce the behavior:

  1. Run the script above in three or more tabs
  2. Observe the console. (read “Actual behavior” for interpretation)

Expected behavior Every instance after the first of the script will log “response”, and all changes will be logged in the host’s console.

Actual behavior

  • First instance of script will log “becoming ‘host’”
  • Second instance of script will log “response”
  • Third (and subsequent instances) will log “becoming ‘host’”.

Taking a look at the original host’s console, we can see that the event listener only sees when the script is set back to true by these new instances. For example:

response timeout. becoming "host"
present changed from true to false
present changed from false to true
present changed from false to true

As you probably know, GM_addValueChangeListener should only fire when the new value is different than the old value. The logs above would make it appear as though this isn’t the case, which doesn’t make sense.

I was writing code that used a concept similar to the example above, and rewrote it multiple times thinking there was some issue with my code. What convinced me otherwise was that running the same script as above in tampermonkey runs exactly how I would expect it to. The GM_addValueChangeListener catches every change from every instance of the script.

What is the result in the upcoming release? I thought that this might have something to do with #1214, but using the latest beta of violentmonkey changed nothing (probably a different issue).

Environment:

  • OS: macOS Version 11.6 (Build 20G165)
  • Browser: Chrome
  • Browser Version: 100.0.4896.75 (Official Build) (x86_64)
  • Violentmonkey Version: 2.13.0

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:5 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
tophfcommented, Apr 11, 2022

Test build: zip.

1reaction
tophfcommented, Apr 11, 2022

Fixed in a5ab9bb7.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Multiple Value Listeners Firing Simultaneously — oracle-tech
The idea is to model the Mac OS "Finder" interface, wherein a top level directory is displayed in the first column, and then...
Read more >
Replace nth occurrence of substring in string - python
You can use a while loop with str.find to find the nth occurrence if it exists and use that position to create the...
Read more >
Jakarta Server Faces
In order to generate a Faces Response, the application must first ... Renderers will typically ignore the value property of this instance, ...
Read more >
Index (Flow Server 2.7.6 API) - javadoc.io
Adds a property change listener and configures the property to be synchronized to the server when a given DOM event is fired.
Read more >
Substitution: how to ignore the Nth first occurrences of a pattern?
I would like to (preferably using one command) change occurrences of a , by a : from the 5th , until the last...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found