2015-07-31 2 views
1

У меня есть свойство элемента, который впрыскивается в мою страницу, с 3-й партии:JavaScript: ждать, пока свойство элемента не готов продолжать

document.querySelector('#embed-container #mf2-events').jsMF2 

jsMF2, как говорят, впрыскиваемого свойство. Мне нужно подождать, пока не будет определено свойство jsMF2, чтобы работать с ним. Первоначально я просто установил тайм-аут, но это нежелательно по многим причинам. Есть ли способ, которым я могу вращаться до свойства или установить обратный вызов? Если бы это была программа C, я хотел бы написать что-то вроде этого:

while (document.querySelector('#embed-container #mf2-events').jsMF2 === undefined || 
      document.querySelector('#embed-container #mf2-events').jsMF2 === null) { } 

    // do work 
+0

Вы имеете в виду * многопоточную программу C, это то, что вы сделали бы. JavaScript в браузерах (кроме случаев, когда они используются в качестве веб-работников) действительно выполняется в одном потоке. –

+0

Вам нужно будет либо опросить с помощью 'setTimeout()', либо вы можете использовать ['MutationObserver'] (https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) в современном браузере , Спиннинг в цикле 'while' просто заблокирует браузер, и это никогда не будет успешным, потому что никакой другой код не может работать, чтобы фактически вызвать изменение. – jfriend00

+0

@ user3689167: Правильно, но если программа была действительно однопоточной, она была бы занята - ждать вечно - потому что никогда не появляется возможность установить jsMF2. Для этого * while * busy-waiting вам нужно как минимум два потока. –

ответ

3

Вы не хотите, занятой-ждать, потому что никаких других JavaScript не могут работать (не говоря уже о больших частях интерфейса браузера), и поэтому свойство не будет определено.

В идеале, независимо от того, что это свойство будет иметь событие, которое оно запускает, в которое вы можете подключиться. Я собираюсь предположить, что вы посмотрели и не нашли его. :-)

После того, как поддержка последней вещи в ECMAScript6 (ака «ES6») становится широко распространенным (не в настоящее время), вы может быть в состоянии использовать Proxy для этого (при условии вашей целевой браузеры позволили Proxy на их экземплярах HTML-элементов). Но достаточно широко распространенная поддержка Proxy займет пару лет, если не дольше (и Proxy не может быть прорежена/полифорирована). (В ES7, вы могли бы использовать Object.observe, но предположительно Proxy, который определяется током [по состоянию на июнь 2015] стандарт будет широко поддерживаемый до того, как технология ES7 есть.)

До /, если вы не можете использовать Proxy , таймер действительно является правильным способом справиться с этой ситуацией. При необходимости это может быть действительно агрессивный таймер.

Если элемент известно, существует, но вы ждете собственности:

check(function(element) { 
    // It's there now, use it 
    // x = element.jsMF2 
}); 

function check(callback) { 
    var element = document.querySelector('#embed-container #mf2-events'); 
    if (element && 'jsMF2' in element) { 
     setTimeout(callback.bind(null, element), 0); 
    } else { 
     setTimeout(check.bind(null, callback), 0); 
    } 
} 

Большинство браузеров будет срабатывать этот таймер сразу когда поток JavaScript доступен первый пару раз, затем выключите его, по крайней мере, на 4 мс для последующих вызовов. Все еще довольно быстро.

Вам не обязательно быть гиперагрессивным; люди медленны по сравнению с компьютерами, вы, вероятно, могли бы использовать 10, 20 или даже 50 мс.

Если есть любые шанса, что свойство не будет отображаться, вы хотите, чтобы остановить эту повторную серию setTimeout в конечном итоге (после секунды, после 10 секунд, через 30 секунд, после 60 секунд, независимо от Уместно к использованию дело). Вы можете сделать это, помня, когда вы начали, а потом просто отказаться, а не перепланирование, если это было слишком долго:

var started = Date.now(); 

check(function(element) { 
    // It's there now, use it 
    // x = element.jsMF2 
}); 

function check(callback) { 
    var element = document.querySelector('#embed-container #mf2-events'); 
    if (element && 'jsMF2' in element) { 
     setTimeout(callback.bind(null, element), 0); 
    } else { 
     if (Date.now() - started > 1000) { // 1000ms = one second 
      // Fail with message 
     } else { 
      setTimeout(check.bind(null, callback), 0); 
     } 
    } 
} 

Side Примечание: Запрос,

var document.querySelector('#embed-container #mf2-events'); 

... есть немного странно. В нем говорится: Дайте мне первый элемент с idmf2-events, найденным внутри элемента с idembed-container.Но id значения должно быть быть уникальным на странице. Итак, все, что на самом деле говорит, это «Получить tme элемент #mfs-events, но только если он находится внутри элемента #embed-container».

Если что нет действительно то, что вы имели в виду, то значительно быстрее

var document.getElementById('mf2-events'); 

... был бы в путь.

+0

, пожалуйста, не устанавливайтеTimeout с 0. Это сжигает батарею, если нет CPU –

+0

@DennisCheung: Нет, это не так. Очевидно, вы не хотите делать это навсегда, но это всего лишь код запуска, как и любая другая программа, запускающая код. Примеры использования корректно закодированных 'setTimeout (..., 0)' являются ** чрезвычайно ** распространенными. –

+0

Он делает. https://plus.google.com/+PeterKasting/posts/GpL63A1K2TF Сон больше процессора, меньше батареи вы впустую –

0

Единственный реальный выход здесь - использовать обратный вызов. Как устанавливается свойство? Если он задан, скажем, ajax-запросом, вам нужно добавить функцию в качестве параметра запроса, который будет выполняться, когда запрос будет выполнен. Темы, которые вам, вероятно, понадобятся, это обратные вызовы, асинхронный JavaScript и, возможно, обещания, которые представляют собой современный подход к асинхронной калло.

+0

Я не совсем уверен, как свойство будет установлено, оно вводится через третью сторону, у меня нет доступа к – user3689167

-1

Был DOMEvents, который не очень популярен, а затем заменит его новым стандартом MutationObserver.

Но вы должны check if your target browser support it или реализовать оба варианта.


EDIT: Вы также можете использовать Object.observe() если свойство не является атрибут дома.

+0

'jsMF2', это не что-то, что наблюдатель мутации может наблюдать. Это свойство expando. Наблюдатели за мутацией могут наблюдать только изменения DOM. –

+0

он возвращается из документа.querySelector. это DOMElement. Это можно наблюдать. –

+0

Просто попробуйте. Да, элемент * является элементом DOM. Это не делает свойство expando свойством DOM, которое можно наблюдать. Подумайте об этом, что бы вы сказали наблюдателю наблюдать? 'ChildList'? Это не дочерний узел. 'атрибуты'? 'AttributeOldValue'? 'AttributeFilter'? Это не атрибут. 'characterData'? 'CharacterDataOldValue'? Это не характерные данные. 'поддерева'? Опять же, это не узел. –

Смежные вопросы