Как запустить код в JavaScript, только когда определена переменная?

Я пишу простую функцию в JavaScript:

function waitThenRun(objectToWaitFor, callback) {
   // logic to periodically check for objectToWaitFor to become something
   // then call the callback
}

И я намерен использовать его как:

waitThenRun(someObjectThatWillBeDefinedLater, function() {
    // Doing something with someObjectThatWillBeDefinedLater
});

Тем не менее, я получаю эту ошибку:

Uncaught ReferenceError: someObjectThatWillBeDefinedLater is not defined

Как вы справляетесь с этим?

Проще говоря, я хочу запускать фрагмент кода только тогда, когда определена глобальная переменная JSON, и я не могу определить, когда и где она определяется. Иногда он определяется после моего кода, иногда перед моим кодом, иногда на секунду позже, иногда на 5 секунд позже. Это недетерминировано.

Что ты имеешь в виду and I can't determine when it gets defined? Разве это не определено где-то в вашем коде?

Mark 09.03.2019 21:02

Я имею в виду, что мой код может выполняться до его определения или после его определения. Это недетерминировано.

Truth Pursuer 09.03.2019 21:05

Переменные передаются по значению, а не по ссылке. Функция не может проверить, определена ли переменная в области действия вызывающего объекта.

Barmar 09.03.2019 21:05

@Barmar, тогда как убедиться, что он определен? Это чем-то похоже на jQuery $(document).ready(), но для глобального объекта JSON.

Truth Pursuer 09.03.2019 21:08

Вы боретесь против того, как все делается в javascript. Обычно можно использовать обратный вызов или прослушиватель событий, чтобы узнать, когда что-то произошло. У вас есть код, который определяет переменную — вы должны вызвать свою функцию или обратный вызов там (так работает $(document).ready() — он принимает обратный вызов). Все остальное с таймерами и опросом будет халтурой.

Mark 09.03.2019 21:20
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
5
1 646
5

Ответы 5

Если это глобальная переменная, вы можете передать имя переменной в виде строки. Поскольку глобальные переменные становятся свойствами объекта window, функция может проверить, определен ли window[objectToWaitFor].

function waitThenRun(objectToWaitFor, callback) {
    var interval = setInterval(function() {
        if (window[objectToWaitFor] !== undefined) {
            clearInterval(interval);
            callback();
        }
    }            
}

waitThenRun("someObjectThatWillBeDefinedLater", function() {
    // do something with someObjectThatWillBeDefinedLater
});

вы можете сделать это, используя

   var checkExist = setInterval(function() {
   if (JsonObject) {
//execute your method here
      console.info("Exists!");
      clearInterval(checkExist);
   }
}, 100); // check every 100ms

Вы сами пробовали? Это if (JsonObject) именно там, где я получаю ошибку. Вот почему я задал этот вопрос.

Truth Pursuer 09.03.2019 21:58

Все глобальные переменные присоединены к объекту window, поэтому вы можете передать имя переменной вашей функции в виде строки и проверить, существует ли она в window, а затем запустить обратный вызов, если он есть. Фрагмент:

setTimeout(function() {
  window.someObjectThatWillBeDefinedLater = {hello: 'world'};
}, 1000);

function waitThenRun(globalObj, callback) {
  let intervalId = setInterval(function() {
    if (window[globalObj] !== undefined) {
      callback(window[globalObj]);
      clearInterval(intervalId);
    }
  }, 200);
}

waitThenRun('someObjectThatWillBeDefinedLater', console.info.bind(console));

Вы можете попробовать использовать метапрограммирование, такое как прокси-серверы JS, для перехвата метода set свойства объектов. Что-то вроде этого:

function tracePropAccess(obj, propKeys) {
    const propKeySet = new Set(propKeys);
    return new Proxy(obj, {
        get(target, propKey, receiver) {
            if (propKeySet.has(propKey)) {
                console.info('GET '+propKey);
            }
            return Reflect.get(target, propKey, receiver);
        },
        set(target, propKey, value, receiver) {
            if (propKeySet.has(propKey)) {
                console.info('SET '+propKey+'='+value);
            }
            return Reflect.set(target, propKey, value, receiver);
        },
    });
}

фрагмент был взят из здесь

В вашем примере, когда вызывается свойство set, вы можете проверить, соответствует ли значение ожидаемому значению, и сделать с ним все, что хотите.

Вы можете отправить событие в window, когда вы определяете свой объект JSON и добавляете прослушиватель событий для этого события в окно. Таким образом, вам не нужно будет использовать setInterval, чтобы постоянно проверять, определена ли глобальная переменная.

function defineJSON(){
  window.JSONObj = {x: "something"};
  triggerEvent("JSONDefined", window, {JSONObjName: "JSONObj"});//fire a custom event on the window when you define the JSON Object
}
function triggerEvent(type, obj, data){
  var ev;
  if (document.createEvent) {
    ev = document.createEvent("HTMLEvents");
    ev.initEvent(type, true, true);
  } else {
    ev = document.createEventObject();
    ev.eventType = type;
  }
  ev.eventName = type;
  if (data){
   for(var key in data){
     if (data.hasOwnProperty(key)){
        ev[key] = data[key];
     }
   }
  }
  if (document.createEvent) {
    obj.dispatchEvent(ev);
  } else {
    obj.fireEvent("on" + ev.eventType, ev);//for < IE8
  }
}
window.addEventListener("JSONDefined", function(ev){
  //this event handler will be called when the JSON Object is defined
  console.info("JSON defined:", window[ev.JSONObjName]);
});
setTimeout(function(){
   defineJSON();
}, 2000);//define JSON Object after 2 seconds (just for this example)

Другие вопросы по теме