परीक्षण पृष्ठ: https://jsfiddle.net/y25rk55w/
इस परीक्षण पृष्ठ पर आप 3 <iframe>
को एक दूसरे में एम्बेड होते हुए देख सकते हैं। प्रत्येक <iframe>
में इसके <head>
टैग में एक <script>
टैग होता है।
समस्या यह है: ब्राउज़र द्वारा पहले <iframe>
में केवल <script>
को ही लोड किया जाएगा। अन्य दो <script>
टैग डोम में मौजूद होंगे लेकिन ब्राउज़र उन्हें लोड करने की कोशिश भी नहीं करेगा। समस्या ब्राउज़र विशिष्ट नहीं है, इसे क्रोम, फ़ायरफ़ॉक्स, यानी में पुन: उत्पन्न किया जा सकता है। टाइमआउट जोड़कर या स्क्रिप्ट जोड़ने से पहले प्रतीक्षा करके समस्या को ठीक नहीं किया जा सकता है। यह महत्वपूर्ण प्रतीत होता है कि सभी iframes में प्रोग्रामिक रूप से उत्पन्न सामग्री है; यदि आप इस आईफ्रेम को वास्तविक स्रोत लिंक के साथ आईफ्रेम के साथ बदलते हैं, तो समस्या गायब हो जाएगी।
सवाल यह है: मैं वास्तव में iframes 2 और 3 में किसी स्क्रिप्ट को कैसे लोड कर सकता हूं?
पूर्ण परीक्षण कोड:
// It doesn't matter if the scripts exist or not
// Browser won't try to load them either way
var scripts = [
'//testdomain.test/script1.js',
'//testdomain.test/script2.js',
'//testdomain.test/script3.js'
];
function createIFrame(win, onCreated) {
var iframe = win.document.createElement('iframe');
iframe.onload = function () {
onCreated(iframe);
};
win.document.body.appendChild(iframe);
}
function loadScript(win, url) {
var script = win.document.createElement('script');
script.src = url;
script.onload = function() {
console.log("Script " + url + " is loaded.");
};
win.document.getElementsByTagName('head')[0].appendChild(script);
}
createIFrame(window, function(iframe1) {
loadScript(iframe1.contentWindow, scripts[0]);
createIFrame(iframe1.contentWindow, function (iframe2) {
loadScript(iframe2.contentWindow, scripts[1]);
createIFrame(iframe2.contentWindow, function (iframe3) {
loadScript(iframe3.contentWindow, scripts[2]);
});
});
});
3 जवाब
प्रश्न में आप देख सकते हैं कि मैं प्रोटोकॉल को छोड़ रहा था:
/* This is valid to omit the http:/https: protocol.
In that case, browser should automatically append
protocol used by the parent page */
var scripts = [
'//testdomain.test/script1.js',
'//testdomain.test/script2.js',
'//testdomain.test/script3.js'
];
बात यह है कि प्रोग्रामिक रूप से बनाए गए iframes में प्रोटोकॉल about:
(या javascript:
होता है, जो इस पर निर्भर करता है कि आप उन्हें कैसे बनाते हैं)। मैं अभी भी यह नहीं समझा सकता कि पहली स्क्रिप्ट क्यों लोड हो रही थी या अन्य दो स्क्रिप्ट नेटवर्क टैब में बिल्कुल क्यों नहीं दिख रही थीं, लेकिन मुझे लगता है कि यह बहुत महत्वपूर्ण नहीं है।
समाधान: या तो स्पष्ट रूप से https://
का उपयोग करें या निम्न कोड की तरह कुछ का उपयोग करके प्रोग्रामेटिक रूप से प्रोटोकॉल संलग्न करें:
function appendSchema(win, url) {
if (url.startsWith('//')) {
var protocol = 'https:';
try {
var wPrev = undefined;
var wCur = win;
while (wPrev != wCur) {
console.log(wCur.location.protocol);
if (wCur.location.protocol.startsWith("http")) {
protocol = wCur.location.protocol;
break;
}
wPrev = wCur;
wCur = wCur.parent;
}
} catch (e) {
/* We cannot get protocol of a cross-site iframe.
* So in case we are inside cross-site iframe, and
* there are no http/https iframes before it,
* we will just use https: */
}
return protocol + url;
}
return url;
}
आपका कोड ठीक काम कर रहा है --> http://plnkr.co/edit/vQGsyD7JxZiDlg6EZvK4?p= पूर्वावलोकन
सुनिश्चित करें कि आपने createIFrame को window.onload पर निष्पादित किया है या DOMContentLoaded।
var scripts = [
'https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.js',
'https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.2/jquery.js',
'https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js'
];
function createIFrame(win, onCreated) {
var iframe = win.document.createElement('iframe');
iframe.onload = function () {
onCreated(iframe);
};
win.document.body.appendChild(iframe);
}
function loadScript(win, url) {
var script = win.document.createElement('script');
script.src = url;
script.onload = function() {
console.log("Script " + url + " is loaded.");
};
win.document.getElementsByTagName('head')[0].appendChild(script);
}
window.onload = function(){
createIFrame(window, function(iframe1) {
loadScript(iframe1.contentWindow, scripts[0]);
createIFrame(iframe1.contentWindow, function (iframe2) {
loadScript(iframe2.contentWindow, scripts[1]);
createIFrame(iframe2.contentWindow, function (iframe3) {
loadScript(iframe3.contentWindow, scripts[2]);
});
});
});
};
मैं self-answer में ओपी द्वारा प्रस्तावित की तुलना में एक सरल विधि का उपयोग करने में सफल रहा हूं। मैं यूआरएल का उपयोग कर उत्पादन करता हूं:
new URL(scriptURL, window.location.href).toString();
जहां scriptURL
वह URL है जिसे उचित प्रोटोकॉल प्राप्त करने के लिए ठीक करने की आवश्यकता है और window
स्क्रिप्ट रखने वाले iframe
तत्व का पैरेंट है। यह उन परिदृश्यों का ध्यान रख सकता है जो OPs उदाहरण URL से भिन्न होते हैं: जैसे सापेक्ष URL (../foo.js
) या निरपेक्ष URL जो किसी होस्ट (/foo.js
) से शुरू नहीं होते हैं। उपरोक्त कोड मेरे मामले में पर्याप्त है।
अगर मैं ओपी द्वारा उपयोग किए जाने वाले विंडो पदानुक्रम के माध्यम से खोज को दोहराना चाहता था, तो शायद मैं निम्न की तरह कुछ करूँगा। यह टाइपस्क्रिप्ट कोड है। सादा जावास्क्रिप्ट प्राप्त करने के लिए टाइप एनोटेशन को अलग करें।
function url(win: Window, path: string): string {
// We search up the window hierarchy for the first window which uses
// a protocol that starts with "http".
while (true) {
if (win.location.protocol.startsWith("http")) {
// Interpret the path relative to that window's href. So the path
// will acquire the protocol used by the window. And the less we
// specify in `path`, the more it gets from the window. For
// instance, if path is "/foo.js", then the host name will also be
// acquired from the window's location.
return new URL(path, win.location.href).toString();
}
// We searched all the way to the top and found nothing useful.
if (win === win.parent) {
break;
}
win = win.parent;
}
// I've got a big problem on my hands if there's nothing that works.
throw new Error("cannot normalize the URL");
}
मेरे पास डिफ़ॉल्ट वापसी मूल्य नहीं है यदि विंडो श्रृंखला कुछ भी उपयोगी नहीं देती है क्योंकि यह URL बनाने के मुद्दे की तुलना में बहुत बड़ी समस्या का संकेत देगा। मेरे सेटअप में कहीं और कुछ गड़बड़ होगी।