request(options)
Opis
Wykonuje żądania XHR (znane również jako AJAX) i zwraca obietnicę.
m.request({
method: 'PUT',
url: '/api/v1/users/:id',
params: { id: 1 },
body: { name: 'test' },
}).then(function (result) {
console.log(result);
});
Sygnatura
promise = m.request(options)
Argument | Typ | Wymagany | Opis |
---|---|---|---|
options | Object | Tak | Konfiguracja żądania. |
options.method | String | Nie | Metoda HTTP. Dopuszczalne wartości: GET , POST , PUT , PATCH , DELETE , HEAD lub OPTIONS . Domyślnie GET . |
options.url | String | Tak | Nazwa ścieżki, do której ma zostać wysłane żądanie. Może zawierać parametry, które zostaną zastąpione wartościami z options.params . |
options.params | Object | Nie | Dane do interpolacji w adresie URL lub serializacji do ciągu zapytania (query string). |
options.body | Object | Nie | Dane do serializacji i umieszczenia w treści żądania (dla metod takich jak POST, PUT, PATCH). |
options.async | Boolean | Nie | Określa, czy żądanie ma być asynchroniczne. Domyślnie true . |
options.user | String | Nie | Nazwa użytkownika do autoryzacji HTTP. Domyślnie undefined . |
options.password | String | Nie | Hasło do autoryzacji HTTP. Domyślnie undefined . Opcja ta jest dostępna ze względu na kompatybilność z XMLHttpRequest , ale należy unikać jej używania, ponieważ hasło jest przesyłane przez sieć w postaci jawnego tekstu. |
options.withCredentials | Boolean | Nie | Określa, czy wysyłać pliki cookie do domen stron trzecich. Domyślnie false . |
options.timeout | Number | Nie | Maksymalny czas trwania żądania w milisekundach. Po przekroczeniu tego czasu żądanie zostanie automatycznie przerwane. Domyślnie undefined . |
options.responseType | String | Nie | Oczekiwany typ odpowiedzi. Domyślnie "" jeśli zdefiniowano extract , "json" jeśli brak. Jeśli responseType: "json" , wewnętrznie wykonywane jest JSON.parse(responseText) . |
options.config | xhr = Function(xhr) | Nie | Funkcja, która otrzymuje bazowy obiekt XMLHttpRequest jako argument i pozwala na jego konfigurację niskiego poziomu lub wymianę (przez zwrócenie nowego obiektu XHR). |
options.headers | Object | Nie | Nagłówki HTTP do dołączenia do żądania przed jego wysłaniem (stosowane tuż przed wywołaniem options.config ). |
options.type | any = Function(any) | Nie | Konstruktor, który ma być użyty do utworzenia instancji dla każdego obiektu w odpowiedzi. Domyślnie funkcja tożsamości. |
options.serialize | string = Function(any) | Nie | Funkcja serializująca dane z body do formatu tekstowego. Domyślnie JSON.stringify , lub funkcja tożsamości (tj. function(value) {return value} ) jeśli options.body jest instancją FormData lub URLSearchParams . |
options.deserialize | any = Function(any) | Nie | Funkcja deserializująca odpowiedź z xhr.response lub znormalizowanego xhr.responseText . Domyślnie funkcja tożsamości. Jeśli zdefiniowano extract , deserialize zostanie pominięte. |
options.extract | any = Function(xhr, options) | Nie | Funkcja pozwalająca na niestandardowe przetwarzanie odpowiedzi XMLHttpRequest. Przydatna do przetwarzania danych odpowiedzi, odczytywania nagłówków i plików cookie. Domyślnie jest to funkcja, która zwraca options.deserialize(parsedResponse) , zgłaszając wyjątek, gdy kod statusu odpowiedzi serwera wskazuje na błąd lub gdy odpowiedź jest syntaktycznie niepoprawna. Jeśli zdefiniowano niestandardową funkcję extract , parametr xhr reprezentuje instancję XMLHttpRequest użytą w żądaniu, a options to obiekt przekazany do wywołania m.request . Ponadto, deserialize zostanie pominięte, a wartość zwrócona przez funkcję extract zostanie użyta bezpośrednio po rozwiązaniu obietnicy. |
options.background | Boolean | Nie | Jeśli false , ponownie rysuje zamontowane komponenty po zakończeniu żądania. Jeśli true , nie robi tego. Domyślnie false . |
returns | Promise | Obietnica, która rozwiązuje się do danych odpowiedzi po przetworzeniu ich przez funkcje extract , deserialize i type . Jeśli kod statusu odpowiedzi wskazuje na błąd, obietnica jest odrzucana, ale można temu zapobiec, ustawiając opcję extract . |
promise = m.request(url, options)
Argument | Typ | Wymagany | Opis |
---|---|---|---|
url | String | Tak | Nazwa ścieżki, do której ma zostać wysłane żądanie. options.url zastępuje to, gdy jest obecne. |
options | Object | Nie | Konfiguracja żądania. |
returns | Promise | Obietnica, która rozwiązuje się do danych odpowiedzi po przetworzeniu ich przez funkcje extract , deserialize i type |
Ta druga forma jest w większości równoważna m.request(Object.assign({url: url}, options))
, po prostu wewnętrznie nie zależy od globalnego ES6 Object.assign
.
Jak to działa
Narzędzie m.request
jest cienką warstwą abstrakcji nad XMLHttpRequest
i umożliwia wykonywanie żądań HTTP do zdalnych serwerów w celu zapisywania i/lub pobierania danych z bazy danych.
m.request({
method: 'GET',
url: '/api/v1/users',
}).then(function (users) {
console.log(users);
});
Wywołanie m.request
zwraca obietnicę i powoduje ponowne renderowanie (redraw) po zakończeniu łańcucha obietnic.
Domyślnie m.request
zakłada, że odpowiedź jest w formacie JSON i parsuje ją do obiektu JavaScript (lub tablicy).
Zdefiniowanie funkcji extract
zapobiega odrzuceniu obietnicy w przypadku błędów HTTP.
Typowe użycie
Oto przykładowy komponent, który używa m.request
do pobrania danych z serwera.
var Data = {
todos: {
list: [],
fetch: function () {
m.request({
method: 'GET',
url: '/api/v1/todos',
}).then(function (items) {
Data.todos.list = items;
});
},
},
};
var Todos = {
oninit: Data.todos.fetch,
view: function (vnode) {
return Data.todos.list.map(function (item) {
return m('div', item.title);
});
},
};
m.route(document.body, '/', {
'/': Todos,
});
Załóżmy, że żądanie do adresu URL serwera /api/items
zwraca tablicę obiektów w formacie JSON.
Gdy m.route
jest wywoływane na dole, komponent Todos
jest inicjalizowany. Wywoływana jest funkcja oninit
, która wywołuje m.request
. Pobiera to asynchronicznie tablicę obiektów z serwera. "Asynchronicznie" oznacza, że JavaScript kontynuuje wykonywanie innego kodu, czekając na odpowiedź z serwera. W tym przypadku oznacza to, że fetch
zwraca i komponent jest renderowany przy użyciu oryginalnej pustej tablicy jako Data.todos.list
. Po zakończeniu żądania do serwera tablica obiektów items
jest przypisywana do Data.todos.list
i komponent jest ponownie renderowany, wyświetlając listę elementów <div>
zawierających tytuły każdego zadania todo
.
Obsługa błędów
Gdy żądanie inne niż file:
zwraca status inny niż 2xx lub 304, zwraca odrzuconą obietnicę z błędem. Ten błąd jest instancją klasy Error, ale z kilkoma dodatkowymi właściwościami.
error.message
zawiera surowy tekst odpowiedzi.error.code
zawiera kod statusu HTTP.error.response
zawiera sparsowaną odpowiedź, przetworzoną przy użyciuoptions.extract
ioptions.deserialize
, tak jak w przypadku normalnych odpowiedzi.
Jest to przydatne w wielu przypadkach, w których same błędy zawierają użyteczne informacje. Aby sprawdzić, czy sesja wygasła, możesz użyć kodu: if (error.code === 401) return promptForAuth().then(retry)
. Jeśli trafisz na mechanizm ograniczania przepustowości API i zwrócił on błąd z "timeout": 1000
, możesz zrobić setTimeout(retry, error.response.timeout)
.
Wskaźniki ładowania i komunikaty o błędach
Oto rozszerzona wersja powyższego przykładu, która implementuje wskaźnik ładowania i komunikat o błędzie:
var Data = {
todos: {
list: null,
error: '',
fetch: function () {
m.request({
method: 'GET',
url: '/api/v1/todos',
})
.then(function (items) {
Data.todos.list = items;
})
.catch(function (e) {
Data.todos.error = e.message;
});
},
},
};
var Todos = {
oninit: Data.todos.fetch,
view: function (vnode) {
return Data.todos.error
? [m('.error', Data.todos.error)]
: Data.todos.list
? [
Data.todos.list.map(function (item) {
return m('div', item.title);
}),
]
: m('.loading-icon');
},
};
m.route(document.body, '/', {
'/': Todos,
});
Istnieje kilka różnic między tym przykładem a poprzednim. Tutaj Data.todos.list
jest null
na początku. Ponadto istnieje dodatkowe pole error
do przechowywania komunikatu o błędzie, a widok komponentu Todos
został zmodyfikowany, aby wyświetlał komunikat o błędzie, jeśli taki istnieje, lub wyświetlał ikonę ładowania, jeśli Data.todos.list
nie jest tablicą.
Dynamiczne adresy URL
Adresy URL żądań mogą zawierać zmienne:
m.request({
method: 'GET',
url: '/api/v1/users/:id',
params: { id: 123 },
}).then(function (user) {
console.log(user.id); // wyświetla 123
});
W powyższym kodzie :id
jest zastępowane danymi z obiektu params
, a żądanie staje się GET /api/v1/users/123
.
Interpolacje są ignorowane, jeśli w obiekcie params
nie istnieją pasujące dane.
m.request({
method: 'GET',
url: '/api/v1/users/foo:bar',
params: { id: 123 },
});
W powyższym kodzie żądanie staje się GET /api/v1/users/foo:bar?id=123
Przerywanie żądań HTTP
Czasami pożądane jest przerwanie żądania. Na przykład, w widżecie autouzupełniania/podpowiedzi, chcesz mieć pewność, że tylko ostatnie żądanie zostanie zakończone, ponieważ zazwyczaj autouzupełnianie/podpowiedzi wysyła kilka żądań podczas pisania przez użytkownika, a żądania HTTP mogą kończyć się w innej kolejności ze względu na nieprzewidywalny charakter sieci. Jeśli inne żądanie zakończy się po ostatnim wysłanym żądaniu, widżet wyświetli mniej istotne (lub potencjalnie błędne) dane niż gdyby ostatnie wysłane żądanie zakończyło się jako ostatnie.
m.request()
udostępnia bazowy obiekt XMLHttpRequest
za pośrednictwem parametru options.config
, co pozwala na zapisanie referencji do tego obiektu i wywołanie jego metody abort
w razie potrzeby:
var searchXHR = null;
function search() {
abortPreviousSearch();
m.request({
method: 'GET',
url: '/api/v1/users',
params: { search: query },
config: function (xhr) {
searchXHR = xhr;
},
});
}
function abortPreviousSearch() {
if (searchXHR !== null) searchXHR.abort();
searchXHR = null;
}
Przesyłanie plików
Aby przesłać pliki, najpierw musisz uzyskać referencję do obiektu File
. Najłatwiejszym sposobem na to jest użycie <input type="file">
.
m.render(document.body, [m('input[type=file]', { onchange: upload })]);
function upload(e) {
var file = e.target.files[0];
}
Powyższy fragment kodu renderuje pole wyboru pliku. Jeśli użytkownik wybierze plik, wyzwalane jest zdarzenie onchange
, które wywołuje funkcję upload
. e.target.files
to lista obiektów File
.
Następnie musisz utworzyć obiekt FormData
, aby utworzyć żądanie wieloczęściowe, które jest specjalnie sformatowanym żądaniem HTTP, które jest w stanie wysyłać dane pliku w treści żądania.
function upload(e) {
var file = e.target.files[0];
var body = new FormData();
body.append('myfile', file);
}
Następnie musisz wywołać m.request
i ustawić options.method
na metodę HTTP, która używa treści (np. POST
, PUT
, PATCH
) i użyć obiektu FormData
jako options.body
.
function upload(e) {
var file = e.target.files[0];
var body = new FormData();
body.append('myfile', file);
m.request({
method: 'POST',
url: '/api/v1/upload',
body: body,
});
}
Zakładając, że serwer jest skonfigurowany do akceptowania żądań wieloczęściowych, informacje o pliku zostaną powiązane z kluczem myfile
.
Przesyłanie wielu plików
Możliwe jest przesłanie wielu plików w jednym żądaniu. Zapewni to atomowość przesyłania wsadowego, co oznacza, że w przypadku wystąpienia błędu podczas przesyłania, żadne pliki nie zostaną przetworzone. W konsekwencji, nie można zapisać tylko części plików. Jeśli chcesz zapisać jak najwięcej plików w przypadku awarii sieci, powinieneś rozważyć przesłanie każdego pliku w osobnym żądaniu.
Aby przesłać wiele plików, po prostu dołącz je wszystkie do obiektu FormData
. Podczas korzystania z pola wyboru pliku możesz uzyskać listę plików, dodając atrybut multiple
do pola wyboru:
m.render(document.body, [
m('input[type=file][multiple]', { onchange: upload }),
]);
function upload(e) {
var files = e.target.files;
var body = new FormData();
for (var i = 0; i < files.length; i++) {
body.append('file' + i, files[i]);
}
m.request({
method: 'POST',
url: '/api/v1/upload',
body: body,
});
}
Monitorowanie postępu
Czasami, jeśli żądanie jest z natury powolne (np. przesyłanie dużego pliku), pożądane jest wyświetlenie wskaźnika postępu użytkownikowi, aby zasygnalizować, że aplikacja nadal działa.
m.request()
udostępnia bazowy obiekt XMLHttpRequest
za pośrednictwem parametru options.config
, co pozwala na dołączenie detektorów zdarzeń do obiektu XMLHttpRequest:
var progress = 0;
m.mount(document.body, {
view: function () {
return [
m('input[type=file]', { onchange: upload }),
progress + '% ukończone',
];
},
});
function upload(e) {
var file = e.target.files[0];
var body = new FormData();
body.append('myfile', file);
m.request({
method: 'POST',
url: '/api/v1/upload',
body: body,
config: function (xhr) {
xhr.upload.addEventListener('progress', function (e) {
progress = e.loaded / e.total;
m.redraw(); // powiedz Mithril.js, że dane się zmieniły i potrzebne jest ponowne renderowanie
});
},
});
}
W powyższym przykładzie renderowane jest pole wyboru pliku. Jeśli użytkownik wybierze plik, inicjowane jest przesyłanie, a w callbacku config
rejestrowany jest handler zdarzenia progress
. Ten program obsługi zdarzeń jest wywoływany przy każdej aktualizacji postępu w obiekcie XMLHttpRequest. Ponieważ zdarzenie postępu XMLHttpRequest nie jest bezpośrednio obsługiwane przez silnik wirtualnego DOM Mithril.js, konieczne jest wywołanie m.redraw()
, aby poinformować Mithril.js o zmianie danych i konieczności ponownego renderowania.
Rzutowanie odpowiedzi na typ
W zależności od architektury aplikacji, może być wskazane przekształcenie danych odpowiedzi na konkretną klasę lub typ (na przykład w celu jednolitej analizy pól daty lub udostępnienia metod pomocniczych).
Możesz przekazać konstruktor jako parametr options.type
, a Mithril.js utworzy instancję tej klasy dla każdego obiektu w odpowiedzi HTTP.
function User(data) {
this.name = data.firstName + ' ' + data.lastName;
}
m.request({
method: 'GET',
url: '/api/v1/users',
type: User,
}).then(function (users) {
console.log(users[0].name); // wyświetla imię
});
W powyższym przykładzie, zakładając, że /api/v1/users
zwraca tablicę obiektów, konstruktor User
zostanie utworzony (tj. wywołany jako new User(data)
) dla każdego obiektu w tablicy. Jeśli odpowiedź zwróciła pojedynczy obiekt, ten obiekt zostałby użyty jako argument body
.
Odpowiedzi inne niż JSON
Czasami punkt końcowy serwera nie zwraca odpowiedzi JSON: na przykład możesz żądać pliku HTML, pliku SVG lub pliku CSV. Domyślnie Mithril.js próbuje zinterpretować xhr.responseText
jako JSON i zwraca wynikową wartość. Aby zastąpić to zachowanie, zdefiniuj niestandardową funkcję options.deserialize
:
m.request({
method: 'GET',
url: '/files/icon.svg',
deserialize: function (value) {
return value;
},
}).then(function (svg) {
m.render(document.body, m.trust(svg));
});
W powyższym przykładzie żądanie pobiera plik SVG, nie robi nic, aby go przeanalizować (ponieważ deserialize
po prostu zwraca wartość w takiej postaci, w jakiej jest), a następnie renderuje ciąg SVG jako zaufany HTML.
Oczywiście funkcja deserialize
może być bardziej złożona:
m.request({
method: 'GET',
url: '/files/data.csv',
deserialize: parseCSV,
}).then(function (data) {
console.log(data);
});
function parseCSV(data) {
// naiwna implementacja dla uproszczenia przykładu
return data.split('\n').map(function (row) {
return row.split(',');
});
}
Ignorując fakt, że powyższa funkcja parseCSV nie obsługuje wielu przypadków, które obsługiwałby odpowiedni parser CSV, powyższy kod wyświetla tablicę tablic.
Niestandardowe nagłówki mogą być również pomocne w tym względzie. Na przykład, jeśli żądasz pliku SVG, prawdopodobnie chcesz odpowiednio ustawić typ zawartości. Aby zastąpić domyślny typ żądania JSON, ustaw options.headers
na obiekt par klucz-wartość odpowiadających nazwom i wartościom nagłówków żądania.
m.request({
method: 'GET',
url: '/files/image.svg',
headers: {
'Content-Type': 'image/svg+xml; charset=utf-8',
Accept: 'image/svg, text/*',
},
deserialize: function (value) {
return value;
},
});
Pobieranie szczegółów odpowiedzi
Domyślnie Mithril.js próbuje zinterpretować xhr.responseText
jako JSON i zwraca wynikową wartość. Może być przydatna bardziej szczegółowa analiza odpowiedzi serwera i jej ręczne przetworzenie. Można to osiągnąć, przekazując niestandardową funkcję options.extract
:
m.request({
method: 'GET',
url: '/api/v1/users',
extract: function (xhr) {
return { status: xhr.status, body: xhr.responseText };
},
}).then(function (response) {
console.log(response.status, response.body);
});
Parametrem options.extract
jest obiekt XMLHttpRequest po zakończeniu jego działania, ale przed przekazaniem go do zwróconego łańcucha obietnic, więc obietnica może nadal zakończyć się stanem odrzucenia, jeśli przetwarzanie zgłosi wyjątek.
Wysyłanie żądań do adresów IP
Ze względu na uproszczony sposób wykrywania parametrów w adresach URL, segmenty adresów IPv6 mogą być błędnie interpretowane jako interpolacje parametrów ścieżki. Ponieważ parametry ścieżki wymagają separatora, aby interpolacja przebiegła poprawnie, próba interpolacji adresu IPv6 spowoduje błąd.
// To nie działa
m.request('http://[2001:db8::990a:cd27:4d9e:79]:8080/some/path', {
// ...
});
Aby obejść ten problem, należy przekazać parę adres IPv6 + port jako parametr.
m.request('http://:host/some/path', {
params: { host: '[2001:db8::990a:cd27:4d9e:79]:8080' },
// ...
});
Nie jest to problem z adresami IPv4 i możesz ich używać normalnie.
// To zadziała zgodnie z oczekiwaniami
m.request('http://192.0.2.15:8080/some/path', {
// ...
});
Dlaczego używać JSON zamiast HTML
Wiele frameworków po stronie serwera udostępnia silnik widoków, który interpoluje dane z bazy danych do szablonu przed udostępnieniem HTML (przy załadowaniu strony lub przez AJAX), a następnie wykorzystuje jQuery do obsługi interakcji użytkownika.
Z kolei Mithril.js to framework przeznaczony dla aplikacji typu thick client, które zazwyczaj pobierają szablony i dane oddzielnie, a następnie łączą je w przeglądarce za pomocą JavaScript. Przeniesienie logiki szablonów do przeglądarki może przynieść korzyści, takie jak obniżenie kosztów operacyjnych poprzez odciążenie zasobów serwera. Oddzielenie szablonów od danych pozwala na efektywniejsze buforowanie kodu szablonów oraz ułatwia ponowne wykorzystanie kodu w różnych typach klientów (np. na komputerach stacjonarnych i urządzeniach mobilnych). Inną korzyścią jest to, że Mithril.js umożliwia paradygmat tworzenia interfejsu użytkownika w trybie zachowawczym, co znacznie upraszcza tworzenie i utrzymanie złożonych interakcji użytkownika.
Domyślnie m.request
oczekuje, że dane odpowiedzi będą w formacie JSON. W typowej aplikacji Mithril.js te dane JSON są następnie zwykle wykorzystywane przez widok.
Należy unikać próby renderowania dynamicznego kodu HTML generowanego przez serwer za pomocą Mithril. Jeśli masz istniejącą aplikację, która korzysta z systemu szablonów po stronie serwera i chcesz ją ponownie zarchitekturyzować, najpierw zdecyduj, czy wysiłek jest w ogóle wykonalny. Migracja z architektury thick server do architektury thick client jest zazwyczaj złożonym procesem, który wymaga refaktoryzacji logiki z szablonów do logicznych usług danych (wraz z odpowiednimi testami).
Usługi danych mogą być zorganizowane na wiele różnych sposobów, w zależności od charakteru aplikacji. Architektury RESTful są popularne wśród dostawców API, a architektury zorientowane na usługi są często wymagane, gdy istnieje wiele wysoce transakcyjnych przepływów pracy.
Dlaczego używać XHR zamiast fetch
fetch()
to nowsze Web API do pobierania zasobów z serwerów, podobne do XMLHttpRequest
.
m.request
Mithril.js używa XMLHttpRequest
zamiast fetch()
z kilku powodów:
fetch
nie jest jeszcze w pełni ustandaryzowany i może podlegać zmianom specyfikacji.- Wywołania
XMLHttpRequest
można anulować przed ich zakończeniem (np. aby uniknąć konfliktów w interfejsach użytkownika z natychmiastowym wyszukiwaniem). XMLHttpRequest
udostępnia punkty zaczepienia dla nasłuchiwaczy postępu dla długotrwałych żądań (np. przesyłanie plików).XMLHttpRequest
jest obsługiwany przez wszystkie przeglądarki, podczas gdyfetch()
nie jest obsługiwany przez Internet Explorer i starsze wersje Androida (sprzed 5.0 Lollipop).
Obecnie, ze względu na brak obsługi przeglądarek, fetch()
zazwyczaj wymaga polyfill, który ma ponad 11 kb nieskompresowany - prawie trzy razy więcej niż moduł XHR Mithril.js.
Pomimo niewielkich rozmiarów, moduł XHR Mithril.js obsługuje wiele istotnych i nietrywialnych funkcji, takich jak interpolacja adresów URL i serializacja ciągów zapytań, a także bezproblemową integrację z systemem automatycznego odświeżania Mithril.js. Polyfill fetch
nie obsługuje żadnej z tych funkcji i wymaga dodatkowych bibliotek i boilerplate, aby osiągnąć ten sam poziom funkcjonalności.
Ponadto moduł XHR Mithril.js jest zoptymalizowany pod kątem punktów końcowych opartych na JSON i sprawia, że ten najczęstszy przypadek jest odpowiednio zwięzły - tj. m.request(url)
- podczas gdy fetch
wymaga dodatkowego, wyraźnego kroku, aby przeanalizować dane odpowiedzi jako JSON: fetch(url).then(function(response) {return response.json()})
W kilku specyficznych przypadkach API fetch()
oferuje pewne zalety techniczne w porównaniu z XMLHttpRequest
:
- oferuje API strumieniowe (rozumiane jako "strumieniowanie wideo", a nie programowanie reaktywne), co pozwala na zmniejszenie opóźnień i zużycia pamięci w przypadku bardzo dużych odpowiedzi (kosztem zwiększonej złożoności kodu).
- integruje się z Service Worker API, które zapewnia dodatkową warstwę kontroli nad tym, jak i kiedy następują żądania sieciowe. To API umożliwia również dostęp do powiadomień push i funkcji synchronizacji w tle.
W typowych scenariuszach strumieniowanie nie przyniesie znaczących korzyści wydajnościowych, ponieważ pobieranie megabajtów danych nie jest zalecane. Ponadto, potencjalne oszczędności pamięci wynikające z wielokrotnego wykorzystywania małych buforów mogą zostać zniwelowane lub wręcz pogorszone przez nadmierne odświeżanie przeglądarki. Z tych powodów wybór strumieniowania fetch()
zamiast m.request
jest zalecany tylko w przypadku aplikacji o ekstremalnych wymaganiach zasobowych.
Unikaj niewłaściwych praktyk
Obietnice nie są danymi odpowiedzi
Metoda m.request
zwraca obiekt Promise
, a nie bezpośrednio dane odpowiedzi. Nie może zwrócić tych danych bezpośrednio, ponieważ żądanie HTTP może zająć dużo czasu (ze względu na opóźnienia sieci), a jeśli JavaScript czekałby na nie, zamroziłoby to aplikację, dopóki dane nie byłyby dostępne.
// UNIKAJ
var users = m.request('/api/v1/users');
console.log('lista użytkowników:', users);
// `users` NIE jest listą użytkowników, to obietnica
// PREFERUJ
m.request('/api/v1/users').then(function (users) {
console.log('lista użytkowników:', users);
});