Самый простой способ - создать функцию и вручную перебрать все объекты в массиве после каждого обещания.
var delayedFORLoop = function (array) {
var defer = $q.defer();
var loop = function (count) {
var item = array[count];
// Example of a promise to wait for
myService.DoCalculation(item).then(function (response) {
}).finally(function () {
// Resolve or continue with loop
if (count === array.length) {
defer.resolve();
} else {
loop(++count);
}
});
}
loop(0); // Start loop
return defer.promise;
}
// To use:
delayedFORLoop(array).then(function(response) {
// Do something
});
Пример также доступен на моем GitHub: https: //github.com/pietervw/Deferred-Angular-FOR-Loop-Example
Несколько ключевых «отличий» в «Стиле» внутри более широкого баннера ООП.
Во всех случаях утверждение о статической или динамической системе типа означает преимущественно одну или другую, проблема далеко не ясна или четко определена. Также многие языки предпочитают стирать грань между вариантами, так что это ни в коем случае не список двоичных вариантов.
или «что означает foo.Bar(x)
?»
1 часто используется в статически типизированных средах, где это ошибка, проверяется во время компиляции на отсутствие такой реализации. Кроме того, языки часто различают Bar (x) и Bar (y), если x и y - разные типы. Это перегрузка методов, и результирующие методы с одинаковыми именами рассматриваются как совершенно разные.
2 часто используется в динамических языках (которые имеют тенденцию избегать перегрузки методов), так как возможно, что во время выполнения тип foo не имеет «обработчика» для сообщения с именем «Bar», разные языки обрабатывают это по-разному пути.
Оба могут быть реализованы за кулисами одним и тем же способом, если это необходимо (часто по умолчанию для второго стиля Smalltalk является вызов функции, но это не является определенным поведением во всех случаях). Поскольку первый метод часто может быть легко реализован как простые вызовы функции смещения указателя, его можно легче сделать относительно быстро. Это не означает, что другие стили также не могут быть сделаны быстро, но может потребоваться больше работы, чтобы гарантировать, что при этом не будет нарушена большая гибкость.
или «Откуда берутся дети?»
Снова 1 имеет тенденцию происходить в статических языках, 2 в динамике, хотя это ни в коем случае не является требованием, они просто поддаются стилю.
или «что или как?»
Это очень не бинарный выбор. Большинство языков на основе классов допускают концепцию абстрактных методов (еще не реализованных). Если у вас есть класс, в котором все методы являются абстрактными (называемыми в C ++ чисто виртуальными), то этот класс в значительной степени представляет собой интерфейс, хотя и тот, который, возможно, также определил некоторое состояние (поля). Настоящий Интерфейс не должен иметь состояния (поскольку он определяет только , что возможно, а не как это происходит.
Только более старые языки ООП склонны полагаться исключительно на один или другой.
VB6 имеет только интерфейсы и не имеет наследования реализации.
Simula позволяет вам объявлять чисто виртуальные классы, но вы можете создавать их экземпляры (с использованием ошибок времени выполнения)
или «Кто такой папа?»
Этот вопрос вызывает серьезные споры, тем более что он является ключевым отличием между реализацией ООП в C ++ и многими современными статически типизированными языками, которые воспринимаются как возможные преемники, такие как c # и java.
или «что вы хотите со мной сделать?»
Зачастую это не все или ничего, это просто значение по умолчанию (наиболее часто используемые языки ООП по умолчанию изменяются по умолчанию). Это может оказать большое влияние на структуру языка. Многие в основном функциональные языки, включающие функции ООП, по умолчанию устанавливают неизменное состояние объектов.
или «Является ли все объектом?»
Это довольно сложно, так как такие приемы, как автобокс примитивов, создают впечатление, что все есть, но вы обнаружите, что существует несколько граничных случаев, где эта «магия компилятора» обнаружен, и пресловутый волшебник Оз находится за занавесом, в результате чего возникают проблемы или ошибки. В языках с неизменяемостью по умолчанию это менее вероятно, поскольку ключевой аспект объектов (то, что они содержат оба метода и состояние ) означает, что вещи, которые похожи на объекты, но не совсем, имеют меньше возможностей для осложнения.
или «Кем вы себя считаете?»
Гораздо более распространенный аспект языкового дизайна, и здесь не один, но присущий выбор на это решение влияют многие аспекты ООП, как упоминалось ранее.
Только аспекты полиморфного позднего связывания могут зависеть от:
Чем динамичнее язык, тем более сложными становятся эти решения, но наоборот тем больше вводит пользователь языка, а не разработчик языка в решении. Давать примеры здесь было бы несколько глупо, поскольку статически типизированные языки могут быть модифицированы для включения динамических аспектов (например, c # 4.0).
Eiffel - это статически типизированный, скомпилированный, с множественным наследованием чистый ООП язык.
Я бы сказал, что ООП со статической и динамической типизацией - это две отдельные дисциплины в одной и той же школе ООП.
Я поместил бы Java и C # в лагерь Simula:
Smalltalk, будучи динамически типизированным, довольно сильно отличается от четырех других языков, которые вы цитируете.
Smalltalk структурно типизирован (псевдоним утиной типизации), в то время как остальные четыре номинально типизированы.
(Что общего у Java и C # с Smalltalk, в основном основано на ВМ, но мало влияет на стиль программирования).
Из современных (и я использую термин слегка) ОО-языков программирования Objective C является наиболее похожим на smalltalk.
В C ++, C # и Java: сообщения связаны во время компиляции.
Вы можете представить вызов метода как сообщение, отправляемое объекту.
В Цели C, Smalltalk: сообщения связаны во время выполнения.
Я бы сказал, что концептуально существует также довольно большое различие между ООП на основе классов (примерами которых являются Smalltalk, Simula, C # и Java) и ООП на основе прототипов (которая началась с Self и является наиболее распространенной). в JavaScript).
Java и C # определенно не принадлежат к семейству Smalltalk. Алан Кей даже сказал, что когда он создавал ООП, он не имел в виду ничего подобного Java или C ++. Java, C # и C ++ интерпретируют ООП практически одинаково.
Такие языки, как Smalltalk и Ruby, имеют радикально отличную модель, основанную на передаче сообщений. В C ++ классы по сути являются пространствами имен для методов и состояний. Вызовы методов связаны во время компиляции. Smalltalk не связывает «вызов метода» до времени выполнения. Результатом этого является то, что в C ++
foo->bar
компилируется, чтобы означать «вызов метода bar для объекта foo». Если bar не является виртуальным, я бы предположил, что адрес метода bar специально указан.
В Smalltalk
foo bar
означает «отправить панель сообщений объекту foo». foo
может делать с этим сообщением все, что захочет, когда оно придет. Поведение по умолчанию - вызывать метод с именем bar
, но это не обязательно. Это свойство используется в Ruby для средств доступа к столбцам ActiveRecord. Когда у вас есть объект ActiveRecord, и вы отправляете ему имя столбца в его таблице базы данных в качестве сообщения, если нет метода с таким именем, он проверяет, есть ли столбец с этим именем в таблице, и если есть возвращает значение.
Передача сообщений может показаться крошечной, не относящейся к делу деталью, но из нее легко вытекает остальная часть ООП.
«Для меня ООП означает только обмен сообщениями, локальное хранение и защиту, а также скрытие процесса состояния и крайнюю позднюю привязку всех вещей. Это может быть сделано в Smalltalk и в LISP. Возможно, существуют другие системы, в которых это происходит. возможно, но я не знаю о них ". - Алан Кей, создатель Smalltalk
Java, C # и C ++ следуют схожей стратегии ООП. Он основан на вызовах функций, которые связаны во время компиляции. В зависимости от его вызова, прямой вызов функции или смещение в vtable фиксируется, когда происходит компиляция. В отличие от ООП Smalltalk основан на передаче сообщений. Концептуально каждый вызов метода - это сообщение для принимающего объекта, спрашивающее, есть ли у него метод с именем «Foo».
Smalltalk не имеет понятия интерфейсов. У него есть только похожие методы. В группе языков C ++ все связано с интерфейсами. Нельзя реализовать AddRef и Release без реализации QueryInterface (даже если это просто заглушка), потому что все они являются частью интерфейса IUnknown. В Smalltalk нет IUnknown. Существует только набор из 3 функций, любая из которых может быть реализована или нет.
Помимо вышеперечисленных пунктов, существует также концептуальная разбивка Smalltalk против Simula.
Концептуально «Smalltalk-style» обычно указывает, что метод, запускаемый при вызове сообщения, определяется во время выполнения, помогая полиморфизму.
С другой стороны, «стиль Симулы», как правило, указывает на то, что все вызовы методов на самом деле являются просто удобным способом записи перегруженных вызовов функций - без полиморфизма во время выполнения. (Пожалуйста, исправьте меня, если я ошибаюсь.)
В середине у нас есть Java: все методы виртуальные по умолчанию, но статически типизированы и имеют диспетчеризацию типа во время компиляции.
Пример:
// C++
class Base {
void doSomething() {
cout << "Base::doSomething() called!\n";
}
}
class Derived : Base {
void doSomething() {
cout << "Derived::doSomething() called!\n";
}
}
int main() {
Base* b = new Base();
Derived* d = new Derived();
b->doSomething(); // prints "Base::doSomething() called!"
d->doSomething(); // prints "Derived::doSomething() called!"
Base* d2 = d; // OK; Liskov substitution principle.
d2->doSomething(); // prints "Base::doSomething called!" (!)
delete b;
delete d;
return 0;
}
VS:
// Objective-C
//Base.h
@interface Base
{
}
-(void)doSomething
@end
//Base.m
#import "Base.h"
@implementation Base
-(void) doSomething {
printf("doSomething sent to Base!");
}
@end
//Derived.h
#import "Base.h"
#import "Base.m"
@interface Derived : Base
{
}
@end
//Derived.m
#import "Derived.h"
@implementation Derived
-(void) doSomething {
printf("doSomething sent to Derived!")
}
@end
//Main.m
#import "Base.h"
#import "Base.m"
#import "Derived.h"
#import "Derived.m"
int main() {
Base* b = [[Base alloc] init];
Derived* d = [[Derived alloc] init];
[b doSomething]; // prints "doSomething sent to Base!"
[d doSomething]; // prints "doSomething sent to Derived!"
Base* d2 = d;
[d2 doSomething]; // prints "doSomething sent to Derived!"
[b release];
[d release];
return 0;
}