উপাদান বিদ্যমান না হওয়া পর্যন্ত ফাংশন অপেক্ষা করুন


158

আমি অন্য ক্যানভাসের উপরে একটি ক্যানভাস যুক্ত করার চেষ্টা করছি - প্রথম ক্যানভাসটি তৈরি না হওয়া পর্যন্ত আমি এই ফাংশনটি কীভাবে শুরু হওয়ার অপেক্ষা করতে পারি?

function PaintObject(brush) {

    this.started = false;

    // get handle of the main canvas, as a DOM object, not as a jQuery Object. Context is unfortunately not yet
    // available in jquery canvas wrapper object.
    var mainCanvas = $("#" + brush).get(0);

    // Check if everything is ok
    if (!mainCanvas) {alert("canvas undefined, does not seem to be supported by your browser");}
    if (!mainCanvas.getContext) {alert('Error: canvas.getContext() undefined !');}

    // Get the context for drawing in the canvas
    var mainContext = mainCanvas.getContext('2d');
    if (!mainContext) {alert("could not get the context for the main canvas");}

    this.getMainCanvas = function () {
        return mainCanvas;
    }
    this.getMainContext = function () {
        return mainContext;
    }

    // Prepare a second canvas on top of the previous one, kind of second "layer" that we will use
    // in order to draw elastic objects like a line, a rectangle or an ellipse we adjust using the mouse
    // and that follows mouse movements
    var frontCanvas = document.createElement('canvas');
    frontCanvas.id = 'canvasFront';
    // Add the temporary canvas as a second child of the mainCanvas parent.
    mainCanvas.parentNode.appendChild(frontCanvas);

    if (!frontCanvas) {
        alert("frontCanvas null");
    }
    if (!frontCanvas.getContext) {
        alert('Error: no frontCanvas.getContext!');
    }
    var frontContext = frontCanvas.getContext('2d');
    if (!frontContext) {
        alert("no TempContext null");
    }

    this.getFrontCanvas = function () {
        return frontCanvas;
    }
    this.getFrontContext = function () {
        return frontContext;
    }

4
আপনি যখন ক্লিকে ক্যানভাস তৈরি করেন, তখন ফাংশনটি চালান বা কোনও ইভেন্টটি ট্রিগার করুন যা কোনও হ্যান্ডলার চালায় যা ফাংশনটি চালায়। কোনও বিল্ট-ইন ক্রস-ব্রাউজার ইভেন্ট নেই যা ঘটে যখন কোনও উপাদান উপলব্ধ থাকে happens
কেভিন বি

উত্তর:


303

আপনার যদি ক্যানভাস তৈরি করা কোডটিতে অ্যাক্সেস থাকে - ক্যানভাস তৈরি হওয়ার পরে কেবল সেখানে ফাংশনটি কল করুন।

যদি আপনার সেই কোডটিতে অ্যাক্সেস না থাকে (উদাঃ এটি যদি গুগল ম্যাপের মতো কোনও তৃতীয় পক্ষের কোড হয়) তবে আপনি যা করতে পারেন তা হ'ল একটি বিরতিতে অস্তিত্বের জন্য পরীক্ষা:

var checkExist = setInterval(function() {
   if ($('#the-canvas').length) {
      console.log("Exists!");
      clearInterval(checkExist);
   }
}, 100); // check every 100ms

তবে দ্রষ্টব্য - অনেক সময় তৃতীয় পক্ষের কোডটিতে আপনার কোডটি সক্রিয় করার বিকল্প থাকে (কলব্যাক বা ইভেন্ট ট্রিগার দ্বারা) যখন এটি লোড শেষ হয়। আপনি যেখানে আপনার ফাংশন রাখতে পারেন তা সেটাই হতে পারে। বিরতি সমাধান সত্যিই একটি খারাপ সমাধান এবং অন্য কিছু কাজ না করে তবেই ব্যবহার করা উচিত।


Angularjs টাইপহেডে ব্যবহারের জন্য নিখুঁত সমাধান। আমাকে সঠিক দিকনির্দেশনা দেওয়ার জন্য ধন্যবাদ!
জুয়ানট্রেভ

1
সেখানে অন্য কিছু জিনিস রাখার আগে অ্যাজাক্স দ্বারা তৈরি করা কোনও কিছুর জন্য অপেক্ষা করার দুর্দান্ত সমাধান। অনেক ধন্যবাদ.
কাউন্টজারো

@ লিঃ নির্বাচক পরিবর্তনশীল হলে আমি কীভাবে এটি কাজ করব? এছাড়াও, এটি কোনও আইডি বা শ্রেণি নির্বাচক থাকলেও পরিবর্তন হয়। কখনও কখনও আমি যখন ক্লাসের সাথে নির্বাচন করি তখন একাধিক উপাদান ফিরে আসে এবং কোনটি নির্ধারণের জন্য আমাকে নির্বাচককে একটি সূচক পাস করার উপায় খুঁজে বের করতে হবে। আমি এই কিভাবে করব? ধন্যবাদ
ক্রেগালন

@ ক্রাগলন এটি সম্পূর্ণ আলাদা প্রশ্ন এবং এই উত্তরের মন্তব্যের জন্য উপযুক্ত নয়। আমি আপনাকে একটি নতুন প্রশ্ন জিজ্ঞাসা করার পরামর্শ দিচ্ছি, আপনি কী চেষ্টা করেছেন, সমস্যাটি কী তা ব্যাখ্যা করুন ...
ইফতাঃ

8
প্রদত্ত সমাধানটি ব্যবহার করার সময় আরও একটি বিষয় উল্লেখ করা গুরুত্বপূর্ণ, আপনার লুপের জন্য কোডের একটি অংশটি থাকা উচিত এবং সর্বাধিক পুনরায় চেষ্টা করা কাউন্টার সেট করা উচিত, যদি কিছু ভুল হয়ে যায় তবে আপনি অনন্ত লুপটি শেষ করবেন না :)
বিজে

48

আপনাকে কোন ব্রাউজারটি সমর্থন করতে হবে তার উপর নির্ভর করে মিউটেশনঅবার্সারের বিকল্প রয়েছে ।

সম্পাদনা: সমস্ত বড় ব্রাউজার এখন মিউটেশনঅবার্সারকে সমর্থন করে

এর লাইন ধরে কিছু করা কৌশলটি করা উচিত:

// callback executed when canvas was found
function handleCanvas(canvas) { ... }

// set up the mutation observer
var observer = new MutationObserver(function (mutations, me) {
  // `mutations` is an array of mutations that occurred
  // `me` is the MutationObserver instance
  var canvas = document.getElementById('my-canvas');
  if (canvas) {
    handleCanvas(canvas);
    me.disconnect(); // stop observing
    return;
  }
});

// start observing
observer.observe(document, {
  childList: true,
  subtree: true
});

এনবি আমি নিজে এই কোডটি পরীক্ষা করিনি, তবে এটি সাধারণ ধারণা।

আপনি সহজেই এটি পরিবর্তিত DOM এর অংশটি অনুসন্ধান করতে প্রসারিত করতে পারেন। তার জন্য, mutationsযুক্তিটি ব্যবহার করুন , এটি MutationRecordবস্তুর একটি অ্যারে ।


2
এই এক ভাল লাগল। ধন্যবাদ.
২৩

1
এই নিদর্শনটি অনেক ক্ষেত্রে সত্যিই সহায়ক, আপনি যদি কোনও পৃষ্ঠাতে জেএস টানছেন এবং অন্যান্য আইটেমগুলি লোড হয়েছে কিনা তা জানেন না।
নামের জন্য

1
সেরা উত্তর! ধন্যবাদ!
অ্যান্টনি হ্যাচকিন্স

1
আমি একটি পুরানো ব্রাউজারের সাথে আটকে আছি (ff38) এবং এটি আমাকে বাঁচিয়েছে।
জাং রাউহে

1
এটা চমৎকার! আমি আশা করি এটি আগে উপস্থিত থাকলে আমি জানতাম।
রব

39

এটি কেবল আধুনিক ব্রাউজারগুলির সাথেই কাজ করবে তবে আমি কেবল এটির জন্য আরও সহজ মনে করি thenদয়া করে প্রথমে পরীক্ষা করুন তবে:

কোড

function rafAsync() {
    return new Promise(resolve => {
        requestAnimationFrame(resolve); //faster than set time out
    });
}

function checkElement(selector) {
    if (document.querySelector(selector) === null) {
        return rafAsync().then(() => checkElement(selector));
    } else {
        return Promise.resolve(true);
    }
}

বা জেনারেটর ফাংশন ব্যবহার করে

async function checkElement(selector) {
    const querySelector = document.querySelector(selector);
    while (querySelector === null) {
        await rafAsync()
    }
    return querySelector;
}  

ব্যবহার

checkElement('body') //use whichever selector you want
.then((element) => {
     console.info(element);
     //Do whatever you want now the element is there
});

সেখানে ভুল আছে. জেনারেটর ফাংশনগুলি ব্যবহার করার সময়, ক্যোয়ারী নির্বাচনকারী প্রতিটি লুপে আপডেট করা উচিত:while (document.querySelector(selector) === null) {await rafAsync()}
হাফলি

31

উপাদানগুলির জন্য অপেক্ষা করার জন্য আরও আধুনিক পদ্ধতি:

while(!document.querySelector(".my-selector")) {
  await new Promise(r => setTimeout(r, 500));
}
// now the element is loaded

নোট করুন যে এই কোডটি একটি অ্যাসিঙ্ক ফাংশনে আবৃত করা দরকার ।


4
এটা বেশ ঝরঝরে!
ডেক্সটার বেনগিল

rসেখানে কি আছে?
ড্যানিয়েল মুলার

ঠিক আছে, তবে কোথা থেকে এসেছে? এটার কাজ কি? আপনি কি পাঠাচ্ছেন setTimeout?
ড্যানিয়েল মুলার

@ ড্যানিয়েলমেলার এই কোডটির আরও ভাল বোঝার জন্য আপনার প্রতিশ্রুতি একবার দেখে নেওয়া দরকার । মূলত কোডটি এখানে যা করে তা 500ms এর টাইমআউট সেট আপ করে এবং লুপটির একটি নতুন পুনরাবৃত্তি শুরু করার আগে এটি শেষ হওয়ার জন্য অপেক্ষা করে। চতুর সমাধান!
ক্লিমেটপ্যারিস016

8

জেমি হাবারের উত্তরের চেয়ে এখানে একটি সামান্য উন্নতি

const checkElement = async selector => {

while ( document.querySelector(selector) === null) {
    await new Promise( resolve =>  requestAnimationFrame(resolve) )
}

return document.querySelector(selector); };

8

requestAnimationFrameএকটি চেয়ে রিলে ভাল setTimeout। এটি এসআই 6 মডিউল এবং ব্যবহারে আমার সমাধান Promises

এস 6, মডিউল এবং প্রতিশ্রুতি:

// onElementReady.js
const onElementReady = $element => (
  new Promise((resolve) => {
    const waitForElement = () => {
      if ($element) {
        resolve($element);
      } else {
        window.requestAnimationFrame(waitForElement);
      }
    };
    waitForElement();
  })
);

export default onElementReady;

// in your app
import onElementReady from './onElementReady';

const $someElement = document.querySelector('.some-className');
onElementReady($someElement)
  .then(() => {
    // your element is ready
  }

plain js and promises:

var onElementReady = function($element) {
  return new Promise((resolve) => {
    var waitForElement = function() {
      if ($element) {
        resolve($element);
      } else {
        window.requestAnimationFrame(waitForElement);
      }
    };
    waitForElement();
  })
};

var $someElement = document.querySelector('.some-className');
onElementReady($someElement)
  .then(() => {
    // your element is ready
  });

Uncaught TypeError: Cannot read property 'then' of undefined
জেফ

আমি মনে করি নতুন প্রতিশ্রুতি দেওয়ার আগে আমি ফিরে আসি ...
ncubica

1
এটি যথাযথ সমাধান, সমস্ত পর্যায়ক্রমিক টাইমার-ভিত্তিক চেকিংয়ের চেয়ে অনেক ভাল।
আন্দ্রেস জেপেশেজি

4
আসলে, এটি তার বর্তমান আকারে কাজ করে না। যদি $ কিছু এলিমেন্ট প্রাথমিকভাবে শূন্য হয় (অর্থাত্ ডিওমে উপস্থিত নেই) তবে আপনি এই নাল মানটি (সিএসএস নির্বাচকের পরিবর্তে) আপনার অনিলিটারি ফাংশনে পাস করুন এবং উপাদানটি কখনই সমাধান হবে না। পরিবর্তে, সিএসএস নির্বাচনকারীকে পাঠ্য হিসাবে পাস করুন এবং প্রতিটি পাসে .querySelector এর মাধ্যমে উপাদানটির রেফারেন্স পাওয়ার চেষ্টা করুন।
আন্দ্রেস জেপেশেজি

1
এটি আমার ব্যবহারের ক্ষেত্রে দুর্দান্ত কাজ করেছে এবং এটি আমার কাছে সঠিক সমাধান বলে মনে হচ্ছে। ধন্যবাদ
rdhaese

5

পর্যবেক্ষকগুলি ব্যবহার করে একটি সমাধান এখানে দেওয়া হল।

waitForElementToAppear(elementId) {                                          

    return Observable.create(function(observer) {                            
            var el_ref;                                                      
            var f = () => {                                                  
                el_ref = document.getElementById(elementId);                 
                if (el_ref) {                                                
                    observer.next(el_ref);                                   
                    observer.complete();                                     
                    return;                                                  
                }                                                            
                window.requestAnimationFrame(f);                             
            };                                                               
            f();                                                             
        });                                                                  
}                                                                            

এখন আপনি লিখতে পারেন

waitForElementToAppear(elementId).subscribe(el_ref => doSomethingWith(el_ref);

4

ডোমটিতে ইতিমধ্যে রেন্ডার না হওয়া পর্যন্ত টাইমআউট সেট করে ডোমটি ইতিমধ্যে উপস্থিত কিনা তা আপনি পরীক্ষা করতে পারেন।

var panelMainWrapper = document.getElementById('panelMainWrapper');
setTimeout(function waitPanelMainWrapper() {
    if (document.body.contains(panelMainWrapper)) {
        $("#panelMainWrapper").html(data).fadeIn("fast");
    } else {
        setTimeout(waitPanelMainWrapper, 10);
    }
}, 10);

3

আপনি যদি মিউটেশনঅবার্সার ব্যবহার করে জেনেরিক সমাধান চান তবে আপনি এই ফাংশনটি ব্যবহার করতে পারেন

// MIT Licensed
// Author: jwilson8767

/**
 * Waits for an element satisfying selector to exist, then resolves promise with the element.
 * Useful for resolving race conditions.
 *
 * @param selector
 * @returns {Promise}
 */
export function elementReady(selector) {
  return new Promise((resolve, reject) => {
    const el = document.querySelector(selector);
    if (el) {resolve(el);}
    new MutationObserver((mutationRecords, observer) => {
      // Query for elements matching the specified selector
      Array.from(document.querySelectorAll(selector)).forEach((element) => {
        resolve(element);
        //Once we have resolved we don't need the observer anymore.
        observer.disconnect();
      });
    })
      .observe(document.documentElement, {
        childList: true,
        subtree: true
      });
  });
}

সূত্র: https://gist.github.com/jwilson8767/db379026efcbd932f64382db4b02853e
এটি কীভাবে ব্যবহার করবেন উদাহরণ

elementReady('#someWidget').then((someWidget)=>{someWidget.remove();});

দ্রষ্টব্য: মিউটেশনঅবার্সারের একটি দুর্দান্ত ব্রাউজার সমর্থন রয়েছে; https://caniuse.com/#feat=mutationobserver

এট ভয়েইল! :)


2

ইফতার আরেকটি প্রকরণ

var counter = 10;
var checkExist = setInterval(function() {
  console.log(counter);
  counter--
  if ($('#the-canvas').length || counter === 0) {
    console.log("by bye!");
    clearInterval(checkExist);
  }
}, 200);

কেবলমাত্র যদি উপাদানটি কখনই প্রদর্শিত না হয়, তাই আমরা অনন্তভাবে চেক করি না।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.