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
Какое правильное использование области сеанса
blockquote>Используйте его только для данных с областью сеанса, и ничего больше. Например, вошедший в систему пользователь, его настройки, выбранный язык и т. Д.
См. Также:
И каждый раз, когда я посещаю страницу, список продуктов будет создан из последних записей в базе данных. Как я могу справиться с этим?
blockquote>Обычно для этого используется область запроса или представления. Загрузка списка должна выполняться по методу
@PostConstruct
. Если страница не содержит<h:form>
, то область запроса будет прекрасной. Объект, обработанный представлением, будет вести себя как область запроса, если в любом случае нет<h:form>
.Все ссылки «Просмотреть продукт» и «редактировать товар», которые только извлекают информацию (т.е. идемпотент), должны быть просто GET
<h:link>
/<h:button>
, в которые вы проходите идентификатор объекта как параметр запроса по<f:param>
.Все ссылки «delete product» и «save product» / кнопки, которые будут обрабатывать информацию (т.е. не-идемпотент), должны выполнять POST с помощью
<h:commandLink>
/<h:commandButton>
(вы не хотите, чтобы они были заклассифицированы / searchbot-indexable!). Это, в свою очередь, требует<h:form>
. Чтобы сохранить данные для валидаций и ajax-запросов (так что вам не нужно перезагружать / preinitialize сущность при каждом запросе), компонент должен быть предпочтительно областью видимости.Обратите внимание, что в каждом представлении вы должны иметь отдельный компонент, а также обратите внимание, что эти beans необязательно должны ссылаться друг на друга.
Итак, с учетом этого объекта «продукта» :
@Entity public class Product { @Id private Long id; private String name; private String description; // ... }
И этот «сервисный сервис» EJB:
@Stateless public class ProductService { @PersistenceContext private EntityManager em; public Product find(Long id) { return em.find(Product.class, id); } public List<Product> list() { return em.createQuery("SELECT p FROM Product p", Product.class).getResultList(); } public void create(Product product) { em.persist(product); } public void update(Product product) { em.merge(product); } public void delete(Product product) { em.remove(em.contains(product) ? product : em.merge(product)); } // ... }
Вы можете использовать этот «просмотр продуктов» на
/products.xhtml
:<h:dataTable value="#{viewProducts.products}" var="product"> <h:column>#{product.id}</h:column> <h:column>#{product.name}</h:column> <h:column>#{product.description}</h:column> <h:column> <h:link value="Edit" outcome="/products/edit"> <f:param name="id" value="#{product.id}" /> </h:link> </h:column> </h:dataTable>
@Named @RequestScoped public class ViewProducts { private List<Product> products; // +getter @EJB private ProductService productService; @PostConstruct public void init() { products = productService.list(); } // ... }
И вы можете получить этот «продукт редактирования» на
/products/edit.xhtml
:<f:metadata> <f:viewParam name="id" value="#{editProduct.product}" converter="#{productConverter}" converterMessage="Unknown product, please use a link from within the system." required="true" requiredMessage="Bad request, please use a link from within the system." /> </f:metadata> <h:messages /> <h:form rendered="#{not empty editProduct.product}> <h:inputText value="#{editProduct.product.name}" /> <h:inputTextarea value="#{editProduct.product.description}" /> ... <h:commandButton value="save" action="#{editProduct.save}" /> </h:form>
@Named @ViewScoped public class EditProduct { private Product product; // +getter +setter @EJB private ProductService productService; public String save() { productService.save(product); return "/products?faces-redirect=true"; } // ... }
И этот преобразователь для
<f:viewParam>
для «edit product»:@Named @RequestScoped public class ProductConverter implements Converter { @EJB private ProductService productService; @Override public Object getAsObject(FacesContext context, UIComponent component, String value) { if (value == null || value.isEmpty()) { return null; } try { Long id = Long.valueOf(value); return productService.find(id); } catch (NumberFormatException e) { throw new ConverterException("The value is not a valid Product ID: " + value, e); } } @Override public String getAsString(FacesContext context, UIComponent component, Object value) { if (value == null) { return ""; } if (value instanceof Product) { Long id = ((Product) value).getId(); return (id != null) ? String.valueOf(id) : null; } else { throw new ConverterException("The value is not a valid Product instance: " + value); } } }
См. также:
В качестве небольшого улучшения, рекомендуемого BalusC, иногда вы можете удалить часть required
/ requiredMessage
из <f:viewParam>
вашего экрана «details» и вместо этого использовать условную визуализацию формы редактирования (поскольку BalusC сделал ) с обратным условием для рекомендации конкретной ссылки для экрана «список / мастер» или даже использовать viewAction, который будет проверять параметр и принудительно перенаправлять его в этот список.