ETA 24 Apr 17
Saya ingin menyederhanakan ini sedikit dengan beberapa async
/await
magic, karena membuatnya jauh lebih ringkas:
Menggunakan promisified-observable yang sama:
const startObservable = (domNode) => {
var targetNode = domNode;
var observerConfig = {
attributes: true,
childList: true,
characterData: true
};
return new Promise((resolve) => {
var observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
console.log(mutation.type);
});
resolve(mutations)
});
observer.observe(targetNode, observerConfig);
})
}
Fungsi panggilan Anda bisa sesederhana:
const waitForMutation = async () => {
const button = document.querySelector('.some-button')
if (button !== null) button.click()
try {
const results = await startObservable(someDomNode)
return results
} catch (err) {
console.error(err)
}
}
Jika Anda ingin menambahkan batas waktu, Anda dapat menggunakan Promise.race
pola sederhana seperti yang ditunjukkan di sini :
const waitForMutation = async (timeout = 5000 ) => {
const button = document.querySelector('.some-button')
if (button !== null) button.click()
try {
const results = await Promise.race([
startObservable(someDomNode),
new Promise((resolve, reject) => setTimeout(
reject,
timeout,
new Error('timed out waiting for mutation')
)
])
return results
} catch (err) {
console.error(err)
}
}
Asli
Anda dapat melakukan ini tanpa perpustakaan, tetapi Anda harus menggunakan beberapa barang ES6, jadi waspadalah terhadap masalah kompatibilitas (yaitu, jika audiens Anda sebagian besar adalah Amish, luddite atau, lebih buruk, pengguna IE8)
Pertama, kita akan menggunakan API MutationObserver untuk membuat objek pengamat. Kami akan membungkus objek ini dalam sebuah promise, dan resolve()
saat callback diaktifkan (h / t davidwalshblog) artikel blog david walsh tentang mutasi :
const startObservable = (domNode) => {
var targetNode = domNode;
var observerConfig = {
attributes: true,
childList: true,
characterData: true
};
return new Promise((resolve) => {
var observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
console.log(mutation.type);
});
resolve(mutations)
});
observer.observe(targetNode, observerConfig);
})
}
Kemudian, kami akan membuat file generator function
. Jika Anda belum menggunakan ini, maka Anda ketinggalan - tetapi sinopsis singkatnya adalah: ini berjalan seperti fungsi sinkronisasi, dan ketika menemukan yield <Promise>
ekspresi, itu menunggu dengan cara yang tidak menghalangi janji itu akan terjadi. terpenuhi ( Generator melakukan lebih dari ini, tetapi inilah yang kami minati di sini ).
let targ = document.querySelector('#domNodeToWatch')
function* getMutation() {
console.log("Starting")
var mutations = yield startObservable(targ)
console.log("done")
}
Bagian rumit tentang generator adalah mereka tidak 'mengembalikan' seperti fungsi normal. Jadi, kita akan menggunakan fungsi pembantu agar bisa menggunakan generator seperti fungsi biasa. (sekali lagi, h / t ke dwb )
function runGenerator(g) {
var it = g(), ret;
(function iterate(val){
ret = it.next( val );
if (!ret.done) {
if ("then" in ret.value) {
ret.value.then( iterate );
}
else {
setTimeout( function(){
iterate( ret.value );
}, 0 );
}
}
})();
}
Kemudian, pada titik mana pun sebelum mutasi DOM yang diharapkan mungkin terjadi, jalankan saja runGenerator(getMutation)
.
Sekarang Anda dapat mengintegrasikan mutasi DOM ke dalam aliran kontrol gaya sinkron. Bagaimana kalau itu.