Ответ 1
Веб-сокеты, по-видимому, будут самым элегантным решением здесь. Таким образом, вам не нужно опросить сервер. Сервер может сообщить ваше приложение, когда данные или что-то изменилось.
Сейчас я просматриваю сервер для проверки новых данных, а затем обновляю модель в приложении AngularJS. Он примерно то, что я делаю:
setInterval(function () {
$http.get('data.json').then(function (result) {
if (result.data.length > 0) {
// if data, update model here
} else {
// nothing has changed, but AngularJS will still start the digest cycle
}
});
}, 5000);
Это отлично работает, но большинство запросов не приведут к новым изменениям данных или данных, но служба $http действительно не знает/не заботится и все равно вызовет цикл дайджеста. Я считаю, что это не нужно (поскольку цикл дайджеста является одной из самых тяжелых операций в приложении). Есть ли способ по-прежнему использовать $http, но каким-то образом пропускать дайджест, если ничего не изменилось?
Одним из решений было бы не использовать $http, а jQuery, а затем вызвать $apply, чтобы Angular знал, что модель изменилась:
setInterval(function () {
$.get('data.json', function (dataList) {
if (dataList.length > 0) {
// if data, update model
$scope.value = dataList[0].value + ' ' + new Date();
// notify angular manually that the model has changed.
$rootScope.$apply();
}
});
}, 5000);
Пока это работает, я не уверен, что это хорошая идея. Я по-прежнему хотел бы использовать чистый Angular, если это возможно.
У кого-нибудь есть предложения по улучшению вышеприведенного подхода или более элегантного решения?
P.S. Причина, по которой я использую setInterval вместо $timeout, состоит в том, что $timeout также запускает цикл дайджеста, который в этом случае был бы лишним и только добавлял бы к "проблеме".
Веб-сокеты, по-видимому, будут самым элегантным решением здесь. Таким образом, вам не нужно опросить сервер. Сервер может сообщить ваше приложение, когда данные или что-то изменилось.
AngularJS рекомендует использовать трюк PERF, который связывает несколько ответов $http в одном $digest через $httpProvider. Это опять же, не устраняет проблему, это просто успокаивающее:)
$httpProvider.useApplyAsync(true)
Во-первых, принятое решение не масштабируемо - вы не собираетесь делать этот трюк $watchers на 100K строках проекта JS-кода - это не может быть и речи.
Во-вторых, даже если проект мал, он довольно рискованно! Что происходит, например, если приходит еще один вызов ajax, который действительно нуждается в этих наблюдателях?
Единственная альтернатива для достижения этого без изменения кода AngularJS заключается в том, чтобы установить $rootScope. $$ phase в true или '$ digest', сделать $http-вызов и вернуть $rootScope. $$ phase to null.
$rootScope.$$phase = true;
$http({...})
.then(successcb, failurecb)
.finally(function () {
$rootScope.$$phase = null;
});
Риски
1) другие вызовы ajax могут попытаться сделать то же самое → они должны быть синхронизированы с помощью службы ajax для обертывания (более $http)
2) пользователь может инициировать действия пользовательского интерфейса между ними, действия, которые изменят фазу $$ до нуля, и когда вызов ajax вернется и все еще вызовет $digest
Решение появилось после сканирования исходного кода AngularJS - вот строка, которая сохраняет ситуацию: https://github.com/angular/angular.js/blob/e5e0884eaf2a37e4588d917e008e45f5b3ed4479/src/ng/http.js#L1272
Поскольку это проблема, с которой все сталкиваются с AngularJS, я думаю, что ее необходимо систематически решать. Ответы выше не, устраняющие проблему, только пытаются избежать этого. Итак, мы должны создать запрос на растяжение AngularJS, который позволит нам указать через $httpProvider конфигурацию, которая не инициирует дайджест для конкретного запроса $http. Надеюсь, они согласятся, что это нужно как-то решить.
Вы можете сделать это с помощью этого трюка:
var watchers;
scope.$on('suspend', function () {
watchers = scope.$$watchers;
scope.$$watchers = [];
});
scope.$on('resume', function () {
scope.$$watchers = watchers;
watchers = null;
});
С помощью этого вы удалите свой объем или верните его в цикл $digest.
Вы должны управлять событиями, чтобы сделать это, конечно.
Обратитесь к этому сообщению:
Надеюсь, это поможет!