ETA 24 tháng 4 17
Tôi muốn đơn giản hóa điều này một chút với một số async
/ await
phép thuật, vì nó làm cho nó ngắn gọn hơn rất nhiều:
Sử dụng cùng có thể quan sát được:
const startObservable = (domNode) => {
var targetNode = domNode;
var observerConfig = {
attributes: true,
childList: true,
characterData: true
};
return new Promise((resolve) => {
var observer = new MutationObserver(function (mutations) {
// For the sake of...observation...let's output the mutation to console to see how this all works
mutations.forEach(function (mutation) {
console.log(mutation.type);
});
resolve(mutations)
});
observer.observe(targetNode, observerConfig);
})
}
Chức năng gọi điện của bạn có thể đơn giản như:
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)
}
}
Nếu bạn muốn thêm thời gian chờ, bạn có thể sử dụng một Promise.race
mẫu đơn giản như được trình bày ở đây :
const waitForMutation = async (timeout = 5000 /*in ms*/) => {
const button = document.querySelector('.some-button')
if (button !== null) button.click()
try {
const results = await Promise.race([
startObservable(someDomNode),
// this will throw after the timeout, skipping
// the return & going to the catch block
new Promise((resolve, reject) => setTimeout(
reject,
timeout,
new Error('timed out waiting for mutation')
)
])
return results
} catch (err) {
console.error(err)
}
}
Nguyên
Bạn có thể làm điều này mà không cần thư viện, nhưng bạn phải sử dụng một số nội dung ES6, vì vậy hãy nhận thức rõ các vấn đề tương thích (ví dụ: nếu đối tượng của bạn chủ yếu là người dùng Amish, luddite hoặc tệ hơn là người dùng IE8)
Trước tiên, chúng tôi sẽ sử dụng API MutingObserver để xây dựng một đối tượng quan sát viên. Chúng tôi sẽ bao bọc đối tượng này trong một lời hứa và resolve()
khi cuộc gọi lại được thực hiện (h / t davidwalshblog) bài viết trên blog của david walsh về các đột biến :
const startObservable = (domNode) => {
var targetNode = domNode;
var observerConfig = {
attributes: true,
childList: true,
characterData: true
};
return new Promise((resolve) => {
var observer = new MutationObserver(function (mutations) {
// For the sake of...observation...let's output the mutation to console to see how this all works
mutations.forEach(function (mutation) {
console.log(mutation.type);
});
resolve(mutations)
});
observer.observe(targetNode, observerConfig);
})
}
Sau đó, chúng tôi sẽ tạo ra một generator function
. Nếu bạn chưa sử dụng những thứ này, thì bạn đã bỏ lỡ - nhưng tóm tắt ngắn gọn là: nó chạy như một chức năng đồng bộ hóa và khi tìm thấy một yield <Promise>
biểu thức, nó sẽ chờ đợi theo cách không bị chặn hoàn thành ( Máy phát điện làm nhiều hơn thế, nhưng đây là điều chúng tôi quan tâm ở đây ).
// we'll declare our DOM node here, too
let targ = document.querySelector('#domNodeToWatch')
function* getMutation() {
console.log("Starting")
var mutations = yield startObservable(targ)
console.log("done")
}
Một phần khó khăn về máy phát điện là chúng không 'trở lại' như một chức năng bình thường. Vì vậy, chúng tôi sẽ sử dụng chức năng trợ giúp để có thể sử dụng trình tạo như một chức năng thông thường. (một lần nữa, h / t để lùn )
function runGenerator(g) {
var it = g(), ret;
// asynchronously iterate over generator
(function iterate(val){
ret = it.next( val );
if (!ret.done) {
// poor man's "is it a promise?" test
if ("then" in ret.value) {
// wait on the promise
ret.value.then( iterate );
}
// immediate value: just send right back in
else {
// avoid synchronous recursion
setTimeout( function(){
iterate( ret.value );
}, 0 );
}
}
})();
}
Sau đó, tại bất kỳ thời điểm nào trước khi đột biến DOM dự kiến có thể xảy ra, chỉ cần chạy runGenerator(getMutation)
.
Bây giờ bạn có thể tích hợp các đột biến DOM vào luồng điều khiển kiểu đồng bộ. Làm thế nào mà ra.