Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
4.3k views
in Technique[技术] by (71.8m points)

dom - JavaScript, MutationObserver misses mutations

I'm trying to create a user script for the Chess.com website. I need to detect changes in the class attribute on certain elements on the page.

There is a small problem: certain mutations of the class attribute are missed by the observer.

My question in short: does anyone have any idea, from the general, conceptual point of the MutationObserver (at least), what might be the reason of this?


A more detailed question:

I'll post the script below, in case anyone wants to try, but the behavior is this:

  • I attached an observer to a black knight (I play for black), whichever appears first in the DOM, when I pointerdown on it, it is added a 'dragging' class. One change is observed, which is OK.

chess-board

  • Then I release the pointer, no changes seem to occur to the class attribute, no observer call.

  • Then I pointerdown again on the knight tile, to remove 'selection' fro it (not to make a move) and this is what I see (this step is marked with red):

mutations-log

An array of 3 MutationRecords is passed to the observer callback:

  • in the first record we see the the old value is the same as the current value from step 1 (not marked with red) (which is normal and expected);
  • in the second record (change 2) we see that the old value was piece bn dragging while the current value from the previous record (change 1 in the marked block) was piece bn square-28. This means that somewhere in between the 'square-28' class had been removed and the 'dragging' one added and no mutation record for this has been reported. The same problem is with step 3.

Some additional thoughts:

  • I tried to reproduce such a situation on another dummy page, but I failed, the changes are always reported (even if they don't occur actually, like when removing a class which wasn't present elem.classList.remove('unexisting-class')).

  • Firefox and Chrome both have the same behavior, so it looks like not a bug

  • It can't be a call to observer.takeRecords() elsewhere, since in that case the queue would be completely empty, and change 1 wouldn't be present. So apparently the queue of changes is not empty, yet some changes, which must be there, are abscent.

  • It can't be an overridden MutationObserver, since one seem to contain [native Code], no definition of it was present in the scripts.

The script is:

// ==UserScript==
// @name         so-question-chess.com
// @version      0.0.0-0
// @include      https://www.chess.com/play/*
// @run-at       document-end
// @grant        none
// ==/UserScript==

(function() {
  'use strict';
  const chessBoard = document.querySelector('chess-board');
  const observerBoard = new MutationObserver((changes) => {
    // attach the observer to the first black knight, when one appears
    for (const change of changes) {
      if (change.type === 'childList') {
        const addedNode = change.addedNodes.item(0);
        if (!addedNode) {
          continue;
        }
        const classList = addedNode.classList;
        //detect a black knight
        if (classList && classList.contains('bn') && classList.contains('piece')) {

          //The relevant part, the observer which observes changes on the class
          //attribute on the black knight piece
          const observerPiece = new MutationObserver((changes) => {
            console.group('single change array');
            for (const change of changes) {
              console.group('single change item');
              console.count('change');
              console.log('current value: ' + change.target.attributes.class.value);
              console.log('old value: ' + change.oldValue);
              console.groupEnd();
            }
            console.countReset('change');
            console.groupEnd();
          });
          observerPiece.observe(addedNode, {
            attributeFilter: ['class'],
            attributeOldValue: true,
            subtree: false,
          });
          //End of the relevant part


          observedBoard.disconnect();
          break;
        }
      }
    }
  });
  observerBoard.observe(chessBoard, {subtree: false, childList: true});

})();

I have no idea of why this is happening, and would be very grateful, if someone pointed to the reason of this.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
等待大神解答

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...