Detener la ejecución de la función Javascript (lado del cliente) o modificarla

Resuelto Yousuf asked hace 13 años • 0 respuestas

Quiero detener la ejecución de una sola línea de un sitio, para que el navegador lea toda la página excepto esa única línea. O el navegador puede simplemente omitir la ejecución de esa función de JavaScript.

O

¿Hay alguna manera de modificar JavaScript de alguna manera para que la función de generación de números aleatorios en JavaScript no genere números aleatorios, sino los números que quiero...

No tengo acceso al sitio en el que está alojado el script, por lo que todo esto debe hacerse desde el lado del cliente.

Yousuf avatar Oct 20 '10 02:10 Yousuf
Aceptado

Firefox actualmente admite el evento beforescriptexecute (a partir de la versión 4, lanzada el 22 de marzo de 2011 ) .

Con ese evento y la // @run-at document-startdirectiva , Firefox y Greasemonkey ahora parecen hacer un buen trabajo interceptando <script>etiquetas específicas.

Esto todavía no es posible para Chrome+Tampermonkey . Para cualquier cosa que no sea Firefox+Greasemonkey, necesitarás usar técnicas como se muestran en las otras respuestas, a continuación, para escribir una extensión de navegador completa.

La checkForBadJavascriptsfunción resume esto. Por ejemplo, supongamos que la página tuviera una <script>etiqueta como esta:

<script>
    alert ("Sorry, Sucka!  You've got no money left.");
</script>

Podrías usar checkForBadJavascriptsasí:

checkForBadJavascripts ( [
    [   false, 
        /Sorry, Sucka/, 
        function () {
            addJS_Node ('alert ("Hooray, you\'re a millionaire.");');
        } 
    ]
] );

para recibir un mensaje mucho más agradable. (^_^)
Consulte la documentación en línea, en checkForBadJavascripts , para obtener más información.


Para ver una demostración en un script completo, primero visite esta página en jsBin . Verás 3 líneas de texto, dos de ellas agregadas por JS.

Ahora, instale este script ( Ver código fuente ; también se encuentra a continuación) y vuelva a visitar la página. Verá que el script GM eliminó una etiqueta incorrecta y reemplazó otra con nuestro JS "bueno".


Tenga en cuenta que solo Firefox admite el beforescriptexecuteevento. Y se eliminó de la especificación HTML5 sin especificar una capacidad equivalente.



Ejemplo completo de script GM (el mismo que el de GitHub y jsBin):

Dado este HTML:

<body onload="init()">
<script type="text/javascript" src="http://jsbin.com/evilExternalJS/js"></script>
<script type="text/javascript" language="javascript">
    function init () {
        var newParagraph            = document.createElement ('p');
        newParagraph.textContent    = "I was added by the old, evil init() function!";
        document.body.appendChild (newParagraph);
    }
</script>
<p>I'm some initial text.</p>
</body>


Utilice este script de Greasemonkey:

// ==UserScript==
// @name        _Replace evil Javascript
// @include     http://jsbin.com/ogudon*
// @run-at      document-start
// ==/UserScript==

/****** New "init" function that we will use
    instead of the old, bad "init" function.
*/
function init () {
    var newParagraph            = document.createElement ('p');
    newParagraph.textContent    = "I was added by the new, good init() function!";
    document.body.appendChild (newParagraph);
}

/*--- Check for bad scripts to intercept and specify any actions to take.
*/
checkForBadJavascripts ( [
    [false, /old, evil init()/, function () {addJS_Node (init);} ],
    [true,  /evilExternalJS/i,  null ]
] );

function checkForBadJavascripts (controlArray) {
    /*--- Note that this is a self-initializing function.  The controlArray
        parameter is only active for the FIRST call.  After that, it is an
        event listener.

        The control array row is  defines like so:
        [bSearchSrcAttr, identifyingRegex, callbackFunction]
        Where:
            bSearchSrcAttr      True to search the SRC attribute of a script tag
                                false to search the TEXT content of a script tag.
            identifyingRegex    A valid regular expression that should be unique
                                to that particular script tag.
            callbackFunction    An optional function to execute when the script is
                                found.  Use null if not needed.
    */
    if ( ! controlArray.length) return null;

    checkForBadJavascripts      = function (zEvent) {

        for (var J = controlArray.length - 1;  J >= 0;  --J) {
            var bSearchSrcAttr      = controlArray[J][0];
            var identifyingRegex    = controlArray[J][1];

            if (bSearchSrcAttr) {
                if (identifyingRegex.test (zEvent.target.src) ) {
                    stopBadJavascript (J);
                    return false;
                }
            }
            else {
                if (identifyingRegex.test (zEvent.target.textContent) ) {
                    stopBadJavascript (J);
                    return false;
                }
            }
        }

        function stopBadJavascript (controlIndex) {
            zEvent.stopPropagation ();
            zEvent.preventDefault ();

            var callbackFunction    = controlArray[J][2];
            if (typeof callbackFunction == "function")
                callbackFunction ();

            //--- Remove the node just to clear clutter from Firebug inspection.
            zEvent.target.parentNode.removeChild (zEvent.target);

            //--- Script is intercepted, remove it from the list.
            controlArray.splice (J, 1);
            if ( ! controlArray.length) {
                //--- All done, remove the listener.
                window.removeEventListener (
                    'beforescriptexecute', checkForBadJavascripts, true
                );
            }
        }
    }

    /*--- Use the "beforescriptexecute" event to monitor scipts as they are loaded.
        See https://developer.mozilla.org/en/DOM/element.onbeforescriptexecute
        Note that it does not work on acripts that are dynamically created.
    */
    window.addEventListener ('beforescriptexecute', checkForBadJavascripts, true);

    return checkForBadJavascripts;
}

function addJS_Node (text, s_URL, funcToRun) {
    var D                                   = document;
    var scriptNode                          = D.createElement ('script');
    scriptNode.type                         = "text/javascript";
    if (text)       scriptNode.textContent  = text;
    if (s_URL)      scriptNode.src          = s_URL;
    if (funcToRun)  scriptNode.textContent  = '(' + funcToRun.toString() + ')()';

    var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
    //--- Don't error check here. if DOM not available, should throw error.
    targ.appendChild (scriptNode);
}
Brock Adams avatar May 06 '2012 07:05 Brock Adams

Método 1: usar MutationObserver

beforescriptexecuteYa no funciona en Firefox, ni tampoco en Chrome. Afortunadamente, existe una alternativa, usar MutationObserver, que cuenta con un soporte bastante amplio. La idea general es agregar un MutationObserver al comienzo de la carga de la página, que ejecutará una devolución de llamada cada vez que se agregue un nuevo nodo al DOM. Dentro de la devolución de llamada, verifique la existencia de la <script>etiqueta que desea modificar o eliminar. Si existe, puede alterarlo (como cambiarlo textContento tener su srcpunto en otro lugar). Solo después de que finalice la devolución de llamada se ejecutará la etiqueta de script recién agregada, por lo que esta es una forma efectiva de interceptar y cambiar Javascript en una página. Aquí hay un ejemplo de fragmento en vivo:

Mostrar fragmento de código

Aquí hay un script de usuario de ejemplo que bloquea la carga de jQuery aquí <head>en Stack Overflow:

// ==UserScript==
// @name             Example jQuery removal
// @include          https://stackoverflow.com*
// @run-at           document-start
// @grant            none
// ==/UserScript==

if (document.head) {
  throw new Error('Head already exists - make sure to enable instant script injection');
}
new MutationObserver((_, observer) => {
  const jqueryScriptTag = document.querySelector('script[src*="jquery"]');
  if (jqueryScriptTag) {
    jqueryScriptTag.remove();
    observer.disconnect();
  }
})
  .observe(document.documentElement, { childList: true, subtree: true });

Si instala esto, verá que la carga de jQuery falla, lo que genera muchos errores generados por el JS de Stack Overflow.

Asegúrese de adjuntar el MutationObserver lo antes posible; debe @run-at document-startadjuntarlo antes de que la página cargue algo dentro del archivo <head>. (Si usa Tampermonkey/Chrome, es posible que necesite habilitar la inyección de script instantánea experimental para lograr esto de manera confiable; vaya a Configuración de Tampermonkey, Modo de configuración: Avanzado, desplácese hasta la parte inferior, configure el Modo de inyección experimental en Instantáneo).

Si está escribiendo scripts de usuario para otras personas o está utilizando esta técnica, asegúrese de incluir instrucciones para la inyección instantánea de scripts, ya que la inyección no es instantánea de forma predeterminada en Chrome.

Tenga en cuenta que el observador se adjunta utilizando

.observe(document.documentElement, { childList: true, subtree: true });

Esto vincula al observador al <html>elemento, vigila si hay hijos inmediatos agregados y eliminados con childList: truey vigila si hay nodos agregados y eliminados en cualquier lugar dentro de sus descendientes con subtree: true. Un oyente recursivo de este tipo es útil, pero también es costoso desde el punto de vista computacional en páginas dinámicas grandes, así que asegúrese de eliminarlo una vez que haya logrado su propósito.

En una página enorme, invocar querySelectorcada mutación podría ser costoso, por lo que es posible que desees iterar a través de mutations(el primer parámetro de la devolución de llamada del observador) y las mutaciones addedNodesen su lugar:

Mostrar fragmento de código

También puede modificar los scripts en línea asignándolos textContentdentro de la devolución de llamada del observador. El siguiente fragmento muestra cómo se puede cambiar una función de generación de números aleatorios para que siempre devuelva 10, en lugar de 1-6:

Mostrar fragmento de código


Método 2: usar anulaciones locales de DevTools

El método 1 es la técnica que puede utilizar al escribir scripts de usuario para otros . Pero si el script de usuario es solo para usted , existe un método más sencillo que puede funcionar en algunas situaciones. Vea esta respuesta a la pregunta Herramientas de desarrollo de Chrome: modifique JavaScript y vuelva a cargar : al ir a la pestaña Fuentes -> Anulaciones en Chrome Devtools y habilitar las anulaciones locales, puede indicarle al navegador que cargue una copia local de un .jsen lugar de descargar el sitio. versión. Luego puede editar la copia local como desee y se ejecutará en lugar del script integrado. Esto es especialmente útil cuando se modifican archivos Javascript grandes: es mucho más manejable que el enfoque MutationObserver.

Pero hay algunas desventajas:

  • Para modificar <script>// code here</script>etiquetas en línea, deberá descargar una copia local de la página. (Entonces, si la página ofrece contenido dinámico a través de la respuesta HTML, tendrá que volver a guardar y modificar las .htmlanulaciones para usar el nuevo contenido, o tendrá que volver al método MutationObserver).
  • Esta es una técnica que los desarrolladores pueden entender (después de experimentar un poco), pero no es tan fácil de usar. Puede que no sea el tipo de cosas por las que le gustaría guiar a un consumidor casual de scripts de usuario.
CertainPerformance avatar Dec 29 '2019 08:12 CertainPerformance

La respuesta depende de los detalles que no se proporcionaron (la página y la línea de código exactas serían las mejores), pero así es como se hace en general:

  1. Si el código JS infractor no se activa de inmediato (se activa después DOMContentLoaded), puede usar Greasemonkey para reemplazar el código infractor. P.EJ:

    var scriptNode          = document.createElement ("script");
    scriptNode.textContent  = "Your JS code here";
    document.head.appendChild (scriptNode);
    

    Hecho.

  2. Si el código JS se activa inmediatamente , entonces se vuelve más complicado.
    Primero, tome una copia del script y realice los cambios deseados. Guarde esto localmente.

  3. ¿El script infractor está en un archivo o en la página principal HTML ( <script src="Some File>versus <script>Mess O' Code</script>)?

  4. Si el script está en un archivo, instale Adblock Plus y utilícelo para bloquear la carga de ese script. Luego use Greasemonkey para agregar su código modificado a la página. P.EJ:

    var scriptNode          = document.createElement ("script");
    scriptNode.setAttribute ("src", "Point to your modified JS file here.");
    document.head.appendChild (scriptNode);
    
  5. Si el script está en la página HTML principal, instale NoScript (mejor) o YesScript y utilícelo para bloquear JavaScript de ese sitio.
    Esto significa que necesitarás usar Greasemonkey para reemplazar todos los scripts de ese sitio que quieras ejecutar.

Brock Adams avatar Oct 20 '2010 04:10 Brock Adams