Js - однопоточная.
Браузер можно разделить на три части:
1) Event Loop
2 ) Web API
3) Очередь событий
Событие Loop запускается вечно, т. Е. Тип бесконечного цикла. Очередь ожидания - это то, где вся ваша функция нажимается на какое-либо событие (пример: нажмите) this один за другим выполняется в очереди и помещается в цикл «Событие», который выполняет эту функцию и подготавливает ее для следующего после первого запуска. Это означает, что выполнение одной функции не начинается до тех пор, пока функция, перед которой она в очереди не будет выполнена цикл событий.
Теперь давайте подумаем, что мы поставили две функции в очереди, чтобы получить данные с сервера, а другой использует эти данные. Мы сначала нажали функцию serverRequest () в очереди, а затем применили функцию Data () , Функция serverRequest переходит в цикл событий и делает вызов на сервер, так как мы никогда не знаем, сколько времени потребуется для получения данных с сервера, поэтому ожидается, что этот процесс займет много времени, и поэтому мы заняли наш цикл событий, тем самым повесив нашу страницу, вот где Web API входит в эту роль, он принимает эту функцию из цикла событий и обращается к серверу, создающему цикл событий, так что мы можем выполнить следующую функцию из очереди. Следующая функция в очереди - useData (), которая идет в цикле, но из-за отсутствия данных отходы и выполнение следующей функции продолжаются до конца очереди (это называется Async-вызовом, то есть мы можем сделать что-то еще, пока не получим данные)
Предположим, что наша функция serverRequest () имела оператор возврата в код, когда мы возвращаем данные с сервера Web API, будет выталкивать его в очередь в конце очереди. По мере того, как он заканчивается в очереди, мы не можем использовать его данные, поскольку в нашей очереди нет функции, чтобы использовать эти данные. Таким образом, невозможно вернуть что-то из Async Call.
Таким образом, решение этой проблемы callback или обещают .
A Изображение из одного из ответов здесь, правильно объясняет использование обратного вызова ... Мы (функция, использующая данные, возвращаемые с сервера), чтобы вызвать вызывающий сервер.
function doAjax(callbackFunc, method, url) { var xmlHttpReq = new XMLHttpRequest(); xmlHttpReq.open(method, url); xmlHttpReq.onreadystatechange = function() { if (xmlHttpReq.readyState == 4 && xmlHttpReq.status == 200) { callbackFunc(xmlHttpReq.responseText); } } xmlHttpReq.send(null); }
В моем коде он называется
function loadMyJson(categoryValue){ if(categoryValue==="veg") doAjax(print,"GET","http://localhost:3004/vegetables"); else if(categoryValue==="fruits") doAjax(print,"GET","http://localhost:3004/fruits"); else console.log("Data not found"); }
Прочитайте здесь новые методы в ECMA (2016/17) для создания асинхронного вызова (@Felix Kling Answer сверху) https://stackoverflow.com/a/14220323/7579856
Это в основном (преднамеренное) следствие того, как проектируется API. Каждый Node
имеет набор свойств, включая свойство parent
(один и только один - родительский узел узла в графе сцены), а также такие свойства, как layoutX
и layoutY
, которые являются координатами узла относительно его родителя. Следовательно, узел может принадлежать только одному родителю и может быть добавлен только одному родителю один раз (поскольку он может иметь только одно местоположение в родительском элементе). Организация этого способа позволяет очень эффективный процесс компоновки.
Еще один способ подумать об этом: предположим, что ваш первый блок кода сделал то, что вы хотели; поэтому текстовое поле tf
появилось дважды в области потока. Какой результат вы ожидаете получить от tf.getBoundsInParent()
? Поскольку tf
появляется дважды в родительском, API не сможет дать разумного значения для этого вызова.
В заявлениях, которые вы делаете в своем вопросе, есть несколько неточностей:
Например, почему это приводит к ошибке компиляции? Не создается ли новое текстовое поле внутри панели, поскольку это композиция?
blockquote>Во-первых, технически это агрегирование, а не состав; хотя я не уверен, что различие поможет вам понять, что происходит на данный момент.
Во-вторых, здесь нет ошибки компиляции; вы получаете ошибку во время выполнения (
pane
обнаруживает, что один и тот жеnode
был добавлен дважды, у компилятора нет возможности проверить это).В-третьих, родители не создают копии узлов вы добавляете к ним. Если это так, вы не сможете изменить свойства отображаемых узлов. Например, если
FlowPane
в вашем примере создавал новыйTextField
, когда вы вызывалиpane.getChildren().add(tf);
, а затем отображал это новое текстовое поле, то, если вы впоследствии назоветеtf.setText("new text")
, это не повлияет, так как это будет не изменяйте текст текстового поля, отображаемогоpane
.Когда вы вызываете
pane.getChildren().add(...)
, вы передаете ссылку на узел, который хотите добавить; это тот узел, который затем отображается как дочерний элемент панели. Любая другая реализация создавала бы довольно противоречивое поведение.В вашем втором кодовом блоке:
pane.getChildren().add(tf); pane2.getChildren().add(tf);
второй вызов неявно устанавливает свойство
parent
вtf
наpane2
; следовательно,tf
уже не является дочерним элементомpane
. Таким образом, этот код имеет эффект удаленияtf
от первого родителя,pane
. Насколько мне известно, этот побочный эффект не документирован, поэтому вам, вероятно, следует избегать написания такого кода.
Попробуйте следующее:
TextField tf = new TextField();
TextField tf2 = new TextField();
pane.getChildren().add(tf);
pane.getChildren().add(tf2);
Причина, по которой вы не можете добавить один и тот же узел дважды, состоит в том, что в gui можно просматривать только один узел с теми же спецификациями и размерами. Это было бы похоже на копирование идентичного синего круга на оригинальный синий круг. Для пользователя он выглядит одинаково, но он занимает больше памяти.