Cara menggunakan INVICATION pada JavaScript

Fungsi pada JavascriptFungsi adalah salah satu bagian yang paling indah dari Javascript. Sebagai bahasa fungsionalJavascript mengimplementasikan fungsi kelas pertama (first class function). Fungsi dapatdisimpan dalam variabel, dikembalikan oleh fungsi lain, dan dikirimkan sebagai argumen untukfungsi lainnya. Implementasi fungsi yang sangat fleksibel seperti ini membuka banyakkesempatan kepada pengembang untuk menuliskan kode yang bukan hanya berjalan denganbaik, tetapi juga sangat elegan dan indah.Sebuah fungsi membungkus satu atau banyak perintah. Setiap kali kita memanggil fungsi, makaperintah-perintah yang ada di dalam fungsi tersebut dijalankan. Secara umum fungsi digunakanuntuk penggunaan kembali kode (code reuse) dan penyimpanan informasi (information hiding).Implementasi fungsi kelas pertama juga memungkinkan kita menggunakan fungsi sebagai unit-unit yang dapat dikombinasikan, seperti layaknya sebuah lego. Dukungan terhadappemrograman berorientasi objek juga berarti fungsi dapat kita gunakan untuk memberikanperilaku tertentu dari sebuah objek.Dalam sudut pandang tertentu, kita bahkan dapat mengatakan bahwa intisari dari pemrogramanadalah mengubah atau menguraikan kebutuhan pengguna menjadi fungsi dan struktur data.Oke, cukup untuk berbicara tentang cinta penulis terhadap fungsi. Sekarang mari kita lihatlangsungkenapadan apakah fungsi benar-benar seperti yang diceritakan oleh penulis.Pembuatan Fungsi pada JavascriptSebuah fungsi pada Javascript dibuat dengan cara seperti berikut:1234functiontambah(a, b) {hasil=a+b;returnhasil;}Cara penulisan fungsi seperti ini dikenal dengan namafunction declaration, atau deklarasi fungsi.Terdapat empat komponen yang membangun fungsi yang baru kita definisikan di atas, yaitu:1.Kata kuncifunction, yang memberitahu Javascript bahwa kita akan membuat fungsi.2.Nama fungsi, dalam contoh di atas adalahtambah. Dengan memberikan sebuah fungsinama maka kita dapat merujuk ke fungsi tersebut dengan nama yang diberikan. Harusdiingat bawa nama fungsi bersifatopsional, yang berartifungsi pada Javascript tidakharus diberi nama. Kita akan membahas tentang hal ini lebih dalam nanti.3.Daftar parameter fungsi, yaitua,bpada contoh di atas. Daftar parameter ini selaludikelilingi oleh tanda kurung (()). Parameter boleh kosong, tetapi tanda kurung wajibtetap dituliskan. Parameter fungsi akan secara otomatis didefinisikan menjadi variabel

I am developing a chrome extension (my fourth question or so...) for facebook, which adds a custom button beside the "like" button. Since posts are added automatically to the news feed without a page refresh, I have to add the script every time new posts are added.

And I use DOMNodeInserted event.

The problem is that when the event is called I insert a new element (the button) to the page and it makes a loop!

My script:

$(document).bind('DOMNodeInserted', function(event) {
    $(".like_link").after('<span class="dot"> · </span><button class="taheles_link stat_elem as_link" title="תגיד תכל&acute;ס" type="submit" name="taheles" onclick="apply_taheles()" data-ft="{&quot;tn&quot;:&quot;&gt;&quot;,&quot;type&quot;:22}"><span class="taheles_default_message">תכל&acute;ס</span><span class="taheles_saving_message">לא תכלס</span></button>');
    $(".taheles_saving_message").hide();
});

You can see my previous question here

I'm tired of asking questions so I'll really appreciate any answer/comment!

Saya sedang mengerjakan Ekstensi di Chrome, dan saya bertanya-tanya: apa cara terbaik untuk mengetahui kapan suatu elemen muncul? Menggunakan javascript biasa, dengan interval yang memeriksa hingga elemen ada, atau apakah jQuery punya cara mudah untuk melakukan ini?

DOMNodeInserted sedang ditinggalkan, bersama dengan peristiwa mutasi DOM lainnya, karena masalah kinerja - pendekatan yang disarankan adalah menggunakan MutationObserver untuk menonton DOM. Ini hanya didukung di browser yang lebih baru, jadi Anda harus kembali ke DOMNodeInserted ketika MutationObserver tidak tersedia.

var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    if (!mutation.addedNodes) return

    for (var i = 0; i < mutation.addedNodes.length; i++) {
      // do things to your newly added nodes here
      var node = mutation.addedNodes[i]
    }
  })
})

observer.observe(document.body, {
    childList: true
  , subtree: true
  , attributes: false
  , characterData: false
})

// stop watching using:
observer.disconnect()

Saya mengalami masalah yang sama, jadi saya melanjutkan dan menulis plugin untuk itu.

$(selector).waitUntilExists(function);

Kode:

;(function ($, window) {

var intervals = {};
var removeListener = function(selector) {

    if (intervals[selector]) {

        window.clearInterval(intervals[selector]);
        intervals[selector] = null;
    }
};
var found = 'waitUntilExists.found';

/**
 * @function
 * @property {object} jQuery plugin which runs handler function once specified
 *           element is inserted into the DOM
 * @param {function|string} handler 
 *            A function to execute at the time when the element is inserted or 
 *            string "remove" to remove the listener from the given selector
 * @param {bool} shouldRunHandlerOnce 
 *            Optional: if true, handler is unbound after its first invocation
 * @example jQuery(selector).waitUntilExists(function);
 */

$.fn.waitUntilExists = function(handler, shouldRunHandlerOnce, isChild) {

    var selector = this.selector;
    var $this = $(selector);
    var $elements = $this.not(function() { return $(this).data(found); });

    if (handler === 'remove') {

        // Hijack and remove interval immediately if the code requests
        removeListener(selector);
    }
    else {

        // Run the handler on all found elements and mark as found
        $elements.each(handler).data(found, true);

        if (shouldRunHandlerOnce && $this.length) {

            // Element was found, implying the handler already ran for all 
            // matched elements
            removeListener(selector);
        }
        else if (!isChild) {

            // If this is a recurring search or if the target has not yet been 
            // found, create an interval to continue searching for the target
            intervals[selector] = window.setInterval(function () {

                $this.waitUntilExists(handler, shouldRunHandlerOnce, true);
            }, 500);
        }
    }

    return $this;
};

}(jQuery, window));

Berikut ini adalah fungsi inti JavaScript untuk menunggu tampilan elemen.

Parameter: 

  1. selector: Fungsi ini mencari elemen $ {selector}
  2. time: Fungsi ini memeriksa apakah elemen ini ada setiap $ {waktu} milidetik.

    function waitForElementToDisplay(selector, time) {
            if(document.querySelector(selector)!=null) {
                alert("The element is displayed, you can put your code instead of this alert.")
                return;
            }
            else {
                setTimeout(function() {
                    waitForElementToDisplay(selector, time);
                }, time);
            }
        }
    

Sebagai contoh, pengaturan selector="#div1" dan time=5000 akan mencari tag HTML yang id="div1" setiap 5000 milidetik.

Anda dapat mendengarkan acara DOMNodeInserted atau DOMSubtreeModified yang menyala setiap kali elemen baru ditambahkan ke DOM. 

Ada juga plugin LiveQuery jQuery yang akan mendeteksi kapan elemen baru dibuat:

$("#future_element").livequery(function(){
    //element created
});

Anda dapat melakukan

$('#yourelement').ready(function() {

});

Harap dicatat bahwa ini hanya akan berfungsi jika elemen ada di DOM ketika diminta dari server. Jika elemen ditambahkan secara dinamis melalui JavaScript, elemen itu tidak akan berfungsi dan Anda mungkin perlu melihat jawaban lainnya.

Saya menggunakan pendekatan ini untuk menunggu elemen muncul sehingga saya dapat menjalankan fungsi lain setelah itu.

Katakanlah fungsi doTheRestOfTheStuff(parameters) hanya boleh dipanggil setelah elemen dengan ID the_Element_ID muncul atau selesai memuat, kita dapat menggunakan,

var existCondition = setInterval(function() {
 if ($('#the_Element_ID').length) {
    console.log("Exists!");
    clearInterval(existCondition);
    doTheRestOfTheStuff(parameters);
 }
}, 100); // check every 100ms

Untuk pendekatan sederhana menggunakan jQuery, saya menemukan ini berfungsi dengan baik:

  // Wait for element to exist.
  function elementLoaded(el, cb) {
    if ($(el).length) {
      // Element is now loaded.
      cb($(el));
    } else {
      // Repeat every 500ms.
      setTimeout(function() {
        elementLoaded(el, cb)
      }, 500);
    }
  };

  elementLoaded('.element-selector', function(el) {
    // Element is ready to use.
    el.click(function() {
      alert("You just clicked a dynamically inserted element");
    });
  });

Di sini kita cukup memeriksa setiap 500 ms untuk melihat apakah elemen tersebut dimuat, ketika itu, kita dapat menggunakannya.

Ini sangat berguna untuk menambahkan penangan klik ke elemen yang telah ditambahkan secara dinamis ke dokumen.

Bagaimana dengan insertionQuery library? 

insertionQuery menggunakan callback Animasi CSS yang dilampirkan pada pemilih yang ditentukan untuk menjalankan callback ketika sebuah elemen dibuat. Metode ini memungkinkan panggilan balik dijalankan setiap kali elemen dibuat, bukan hanya pertama kali.

Dari github:

Cara non-dom-event untuk menangkap node yang muncul. Dan itu menggunakan penyeleksi.

Ini bukan hanya untuk dukungan browser yang lebih luas, Ini bisa lebih baik daripada DOMMutationObserver untuk hal-hal tertentu.

Mengapa?

  • Karena Acara DOM memperlambat browser dan insertionQuery tidak
  • Karena DOM Mutation Observer memiliki lebih sedikit dukungan browser daripada insertionQuery
  • Karena dengan insertionQuery Anda dapat memfilter perubahan DOM menggunakan penyeleksi tanpa overhead kinerja!

Dukungan luas!

IE10 + dan sebagian besar hal lain (termasuk seluler)

Inilah fungsi yang bertindak sebagai pembungkus tipis di sekitar MutationObserver. Satu-satunya persyaratan adalah bahwa browser mendukung MutationObserver; tidak ada ketergantungan pada JQuery. Jalankan cuplikan di bawah untuk melihat contoh yang berfungsi.

function waitForMutation(parentNode, isMatchFunc, handlerFunc, observeSubtree, disconnectAfterMatch) {
  var defaultIfUndefined = function(val, defaultVal) {
    return (typeof val === "undefined") ? defaultVal : val;
  };

  observeSubtree = defaultIfUndefined(observeSubtree, false);
  disconnectAfterMatch = defaultIfUndefined(disconnectAfterMatch, false);

  var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
      if (mutation.addedNodes) {
        for (var i = 0; i < mutation.addedNodes.length; i++) {
          var node = mutation.addedNodes[i];
          if (isMatchFunc(node)) {
            handlerFunc(node);
            if (disconnectAfterMatch) observer.disconnect();
          };
        }
      }
    });
  });

  observer.observe(parentNode, {
    childList: true,
    attributes: false,
    characterData: false,
    subtree: observeSubtree
  });
}

// Example
waitForMutation(
  // parentNode: Root node to observe. If the mutation you're looking for
  // might not occur directly below parentNode, pass 'true' to the
  // observeSubtree parameter.
  document.getElementById("outerContent"),
  // isMatchFunc: Function to identify a match. If it returns true,
  // handlerFunc will run.
  // MutationObserver only fires once per mutation, not once for every node
  // inside the mutation. If the element we're looking for is a child of
  // the newly-added element, we need to use something like
  // node.querySelector() to find it.
  function(node) {
    return node.querySelector(".foo") !== null;
  },
  // handlerFunc: Handler.
  function(node) {
    var elem = document.createElement("div");
    elem.appendChild(document.createTextNode("Added node (" + node.innerText + ")"));
    document.getElementById("log").appendChild(elem);
  },
  // observeSubtree
  true,
  // disconnectAfterMatch: If this is true the hanlerFunc will only run on
  // the first time that isMatchFunc returns true. If it's false, the handler
  // will continue to fire on matches.
  false);

// Set up UI. Using JQuery here for convenience.

$outerContent = $("#outerContent");
$innerContent = $("#innerContent");

$("#addOuter").on("click", function() {
  var newNode = $("<div><span class='foo'>Outer</span></div>");
  $outerContent.append(newNode);
});
$("#addInner").on("click", function() {
  var newNode = $("<div><span class='foo'>Inner</span></div>");
  $innerContent.append(newNode);
});
.content {
  padding: 1em;
  border: solid 1px black;
  overflow-y: auto;
}
#innerContent {
  height: 100px;
}
#outerContent {
  height: 200px;
}
#log {
  font-family: Courier;
  font-size: 10pt;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>Create some mutations</h2>
<div id="main">
  <button id="addOuter">Add outer node</button>
  <button id="addInner">Add inner node</button>
  <div class="content" id="outerContent">
    <div class="content" id="innerContent"></div>
  </div>
</div>
<h2>Log</h2>
<div id="log"></div>

Inilah fungsi Javascript murni yang memungkinkan Anda menunggu apa pun. Atur interval lebih lama untuk mengurangi sumber daya CPU.

/**
 * @brief Wait for something to be ready before triggering a timeout
 * @param {callback} isready Function which returns true when the thing we're waiting for has happened
 * @param {callback} success Function to call when the thing is ready
 * @param {callback} error Function to call if we time out before the event becomes ready
 * @param {int} count Number of times to retry the timeout (default 300 or 6s)
 * @param {int} interval Number of milliseconds to wait between attempts (default 20ms)
 */
function waitUntil(isready, success, error, count, interval){
    if (count === undefined) {
        count = 300;
    }
    if (interval === undefined) {
        interval = 20;
    }
    if (isready()) {
        success();
        return;
    }
    // The call back isn't ready. We need to wait for it
    setTimeout(function(){
        if (!count) {
            // We have run out of retries
            if (error !== undefined) {
                error();
            }
        } else {
            // Try again
            waitUntil(isready, success, error, count -1, interval);
        }
    }, interval);
}

Untuk memanggil ini, misalnya di jQuery, gunakan sesuatu seperti:

waitUntil(function(){
    return $('#myelement').length > 0;
}, function(){
    alert("myelement now exists");
}, function(){
    alert("I'm bored. I give up.");
});

Inilah solusi Pengembalian Janji di Vanilla Javascript (tanpa panggilan balik yang berantakan) Secara default ia memeriksa setiap 200 ms.

function waitFor(selector) {
    return new Promise(function (res, rej) {
        waitForElementToDisplay(selector, 200);
        function waitForElementToDisplay(selector, time) {
            if (document.querySelector(selector) != null) {
                res(document.querySelector(selector));
            }
            else {
                setTimeout(function () {
                    waitForElementToDisplay(selector, time);
                }, time);
            }
        }
    });
}

Contoh yang lebih bersih menggunakan MutationObserver:

new MutationObserver( mutation => {
    if (!mutation.addedNodes) return
    mutation.addedNodes.forEach( node => {
        // do stuff with node
    })
})

Cukup tambahkan pemilih yang Anda inginkan. Setelah elemen ditemukan, Anda dapat memiliki akses ke dalam fungsi panggilan balik.

const waitUntilElementExists = (selector, callback) => {
const el = document.querySelector(selector);

if (el){
    return callback(el);
}

setTimeout(() => waitUntilElementExists(selector, callback), 500);
}

waitUntilElementExists('.wait-for-me', (el) => console.log(el));

Solusi yang mengembalikan Promise dan memungkinkan untuk menggunakan batas waktu (kompatibel IE 11+):

"use strict";

function waitUntilElementLoaded(selector) {
    var timeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;

    var start = performance.now();
    var now = 0;

    return new Promise(function (resolve, reject) {
        var interval = setInterval(function () {
            var element = document.querySelector(selector);

            if (element instanceof HTMLElement) {
                clearInterval(interval);

                resolve();
            }

            now = performance.now();

            if (now - start >= timeout) {
                reject("Could not find the element " + selector + " within " + timeout + " ms");
            }
        }, 100);
    });
}

"use strict";

function waitUntilElementsLoaded(selector) {
    var timeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;

    var start = performance.now();
    var now = 0;

    return new Promise(function (resolve, reject) {
        var interval = setInterval(function () {
            var elements = document.querySelectorAll(selector);

            if (elements instanceof NodeList) {
                clearInterval(interval);

                resolve(elements);
            }

            now = performance.now();

            if (now - start >= timeout) {
                reject("Could not find elements " + selector + " within " + timeout + " ms");
            }
        }, 100);
    });
}

Contoh:

waitUntilElementLoaded('#message', 800).then(function(element) {
    // element found and available

    element.innerHTML = '...';
}).catch(function() {
    // element not found within 800 milliseconds
});

waitUntilElementsLoaded('.message', 10000).then(function(elements) {
    for(const element of elements) {
        // ....
    }
}).catch(function(error) {
    // elements not found withing 10 seconds
});

Berfungsi untuk daftar elemen dan elemen tunggal.