Простой AngularJS
В Lift всегда использовалась лучшая технология серверного проталкивания. Зачем? Он безопасен, хорошо работает с нестабильными соединениями, учитывает ограниченное количество HTTP-соединений между клиентом и сервером и многое другое.
Angular JS — это очень интересный пакет пользовательского интерфейса, который упрощает создание динамических одностраничных приложений, поскольку существует двусторонняя привязка между моделью и пользовательским интерфейсом, чтобы изменения в модели правильно отражались в пользовательском интерфейсе. И вся привязка является декларативной, поэтому, когда вы используете элемент модели в пользовательском интерфейсе, эта часть пользовательского интерфейса всегда обновляется при изменении модели.
Круглые поездки
Стандартный способ создания приложений Angular JS — связать определенные события в клиенте с вызовами REST к серверу, а когда вызовы REST удовлетворены, модель обновляется и пользовательский интерфейс перерисовывается. Звучит разумно.
Но есть проблемы:
- Существует HTTP-соединение, открытое во время вызова REST, и, учитывая ограниченное количество доступных HTTP-соединений от браузера к данному хосту, одновременное открытие нескольких вызовов REST не является оптимальным.
- REST хорошо работает для простых быстрых циклов запросов / ответов, но если вычисления занимают много времени, HTTP-соединение открыто в течение долгого времени, и это иногда портит прокси-серверы, которые часто задерживают HTTP-запросы через 90 секунд — 3 минуты.
- REST не делает потоковую передачу хорошо
- Разработчик должен защищать каждый вызов REST, потому что конечные точки REST всегда открыты, поэтому в каждый вызов должна быть встроена логика управления доступом
В Lift 3 мы представляем идею циклических поездок: запрос на стороне клиента, отправляемый на сервер, где клиент получает обещание потоковой передачи, сервер выполняет свои вычисления, а когда результаты готовы, они передаются клиенту… и если есть несколько результатов, несколько результатов передаются клиенту по мере того, как результаты становятся доступными.
Поездки Лифта туда и обратно имеют следующие преимущества перед простым ОТДЫХОМ:
- Они потребляют гораздо меньше HTTP-соединений
- Они используют технологию Lift Comet Server-Push, чтобы результаты передавались клиенту, даже если результаты вычисляются, пока клиент временно отключен и передается в порядке
- В запросах используются средства Lift Ajax, которые включают в себя усовершенствованные механизмы повтора и дедупликации
- Lift-json выполняет большую часть сериализации JSON — Scala-land автоматически
- Результаты передаются в потоковом режиме, поэтому результаты передаются с сервера на клиент по завершении вычислений на сервере.
Простое путешествие туда и обратно
Давайте посмотрим на реализацию простой циклической загрузки для загрузки и сохранения некоторых данных String. На стороне сервера у нас есть код, который выглядит следующим образом:
// Save the text… we get a JSON blog and manually decode it // If an exception is thrown during the save, the client automatically // gets a Failure def doSave(info: JValue): JValue = { for { JString(path) <- info \ "path" JString(text) <- info \ "text" } { // save the text } JNull // a no-op } // Load the file def doLoad(fileName: String): String = { // load the named file, turn it into a String and return it } // Associate the server functions with client-side functions JScript( JsCrVar("serverFuncs", sess.buildRoundtrip(List[RoundTripInfo]( "save" -> doSave _, "load" -> doLoad _)))
И чтобы вызвать код от клиента:
// Save the file $scope.save = function() { serverFuncs.save({path: $scope.curFile, text: $scope.curText}); } // load the named file and update the model // when the file arrives $scope.load = function(fn) { serverFuncs.load(fn).then(function(v) { $scope.$apply(function() { $scope.curFile = fn; $scope.curText = v; }); }); }
Икс
Таким образом, строки кода здесь очень похожи на строки кода для реализации REST.
Но у нас есть контроль доступа, потому что функции на стороне клиента на самом деле связаны с помощью GUID с функциями на стороне сервера, поэтому не нужно беспокоиться о CSRF или защите ресурса REST на основе разрешений пользователя, потому что единственные функции, которые клиент может вызвать, — это функции которые представлены ему.
Нам также не нужно явно настраивать обработку ошибок, потому что исключение на стороне сервера превратится в сбой на клиенте.
Но это потоки
Что происходит, когда вы хотите передавать данные с сервера на клиент?
У Lift’s Round Trips есть простой ответ, используйте Streams. Лифт автоматически определит, является ли возвращаемый тип buildRoundTrip
функции Stream[T]
«правильно». Итак, если наша функция на стороне сервера:
def thing(s: String): Stream[String] = { var x = 0 (s + x) #:: { Thread.sleep(1000); x += 1; s + x } #:: { Thread.sleep(1000); x += 1; s + x } #:: Stream.empty[String] }
И наш клиент выглядит так:
$scope.doThing = function(fn) { $scope.data = []; $scope.done = false; serverFuncs.thing(fn).then(function(v) { $scope.$apply(function() { $scope.data.push(v); }).done(function() { $scope.$apply(function() {$scope.done = true;}) }); }); }
Таким образом, даже если данные поступают с промежутками в 1 секунду, данные передаются клиенту по мере их появления на сервере.
Это бесконечно гибкий
Иногда поток с исключениями для обозначения сбоя не является правильным ответом. Например, если у вас есть библиотека Iteratee, и вы хотели бы обернуть Round-Rate вокруг Iteratee, вам необходимо сообщить о новых данных, выполненных и сбое. RoundTripHandlerFunc
является ответом для вас.
Вот необработанный код:
private def thing(q: String, onChange: RoundTripHandlerFunc) { if (q.trim.length < 3) { onChange.failure("request too short!") } else { def doIt() { if (ran.nextFloat() < 0.05f) { onChange.done() } else if (ran.nextFloat() < 0.02f) { onChange.failure("Hey, I'm a failure") } else { onChange.send(/* some data */) // delay without consuming a thread Schedule(doIt _, /* some timeout */) } } doIt() } }
Итак, приведенный выше код функционирует подобно Stream
примеру выше, но дает нам явный контроль над отправкой данных, выполнением и ошибкой.
Вы можете сделать неявное преобразование из любой формы потоковой библиотеки в RoundTripHandlerFunc
вызов стиля и получить что-то вроде def myFunc(in: MyData): Iteratee[T]
обслуживания через Round Trips.
Также обратите внимание, что типы ввода наших функций были String
и JValue
, но они могут быть любыми, если есть способ конвертировать JValue
в этот тип через Lift-json.
Заворачивать
Здесь описывается, как функция Lift 3 Round Trip позволяет вам создавать действительно превосходные приложения AngularJS, поскольку вы можете легко передавать данные с клиента на сервер, вам не нужно беспокоиться о преобразовании типов данных, вам не нужно беспокоиться об управлении доступом и вам не нужно беспокоиться о разрыве соединения. На самом деле, вы не беспокоитесь о сантехнике, вы беспокоитесь о бизнес-логике вашего приложения.