ईटीए 24 अप्रैल 17
मैं कुछ async
/ await
जादू के साथ इसे थोड़ा सरल करना चाहता था , क्योंकि यह इसे बहुत अधिक सफल बनाता है:
उसी प्रॉमिसिफाइड-ऑब्जर्वेबल का उपयोग करना:
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);
})
}
आपका कॉलिंग फ़ंक्शन उतना ही सरल हो सकता है:
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)
}
}
यदि आप एक टाइमआउट जोड़ना चाहते हैं, तो आप यहां प्रदर्शित एक सरल Promise.race
पैटर्न का उपयोग कर सकते हैं :
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)
}
}
मूल
आप पुस्तकालयों के बिना भी ऐसा कर सकते हैं, लेकिन आपको कुछ ES6 सामानों का उपयोग करना होगा, इसलिए संगतता के मुद्दों से सावधान रहें (यानी, यदि आपके दर्शक ज्यादातर अमीश, लुडाइट या बदतर, IE8 उपयोगकर्ता हैं)
सबसे पहले, हम ऑब्जर्वर ऑब्जेक्ट बनाने के लिए MutationObserver API का उपयोग करेंगे । हम इस ऑब्जेक्ट को एक वादा में resolve()
लपेटेंगे , और जब कॉलबैक निकाल दिया जाएगा (h / t davidwalshblog) म्यूटेशन पर walsh ब्लॉग लेख :
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);
})
}
फिर, हम एक बनाएंगे generator function
। यदि आपने अभी तक इनका उपयोग नहीं किया है, तो आप गायब हो रहे हैं - लेकिन एक संक्षिप्त सारांश है: यह सिंक फ़ंक्शन की तरह चलता है, और जब यह एक yield <Promise>
अभिव्यक्ति पाता है , तो यह वादे के लिए गैर-अवरुद्ध फैशन में इंतजार करता है पूरा ( जेनरेटर इससे अधिक करते हैं, लेकिन यह वही है जो हम यहां रुचि रखते हैं )।
// 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")
}
जनरेटर के बारे में एक मुश्किल हिस्सा यह है कि वे एक सामान्य कार्य की तरह 'वापसी' नहीं करते हैं। तो, हम एक हेल्पर फंक्शन का उपयोग करेंगे जो एक नियमित फंक्शन की तरह जनरेटर का उपयोग करने में सक्षम होगा। (फिर से, h / t से dwb )
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 );
}
}
})();
}
फिर, अपेक्षित DOM उत्परिवर्तन से पहले किसी भी बिंदु पर, बस चला सकते हैं runGenerator(getMutation)
।
अब आप DOM म्यूटेशन को सिंक्रोनस-स्टाइल कंट्रोल फ्लो में एकीकृत कर सकते हैं। कैसे डटकर।