Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 0 additions & 36 deletions 5-network/01-fetch/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,7 @@ let promise = fetch(url, [options])
- **`url`** -- 접근하고자 하는 URL
- **`options`** -- 선택 매개변수, method나 header 등을 지정할 수 있음

<<<<<<< HEAD
`options`에 아무것도 넘기지 않으면 요청은 `GET` 메서드로 진행되어 `url`로부터 콘텐츠가 다운로드 됩니다.
=======
Without `options`, this is a simple GET request, downloading the contents of the `url`.
>>>>>>> upstream/master

`fetch()`를 호출하면 브라우저는 네트워크 요청을 보내고 프라미스가 반환됩니다. 반환되는 프라미스는 `fetch()`를 호출하는 코드에서 사용됩니다.

Expand Down Expand Up @@ -65,21 +61,12 @@ if (response.ok) { // HTTP 상태 코드가 200~299일 경우

`response` 에는 프라미스를 기반으로 하는 다양한 메서드가 있습니다. 이 메서드들을 사용하면 다양한 형태의 응답 본문을 처리할 수 있습니다.

<<<<<<< HEAD
- **`response.text()`** -- 응답을 읽고 텍스트를 반환합니다,
- **`response.json()`** -- 응답을 JSON 형태로 파싱합니다,
- **`response.formData()`** -- 응답을 `FormData` 객체 형태로 반환합니다. `FormData`에 대한 자세한 내용은 [다음 챕터](info:formdata)에서 다루겠습니다.
- **`response.blob()`** -- 응답을 [Blob](info:blob)(타입이 있는 바이너리 데이터) 형태로 반환합니다.
- **`response.arrayBuffer()`** -- 응답을 [ArrayBuffer](info:arraybuffer-binary-arrays)(바이너리 데이터를 로우 레벨 형식으로 표현한 것) 형태로 반환합니다.
- 이 외에도 `response.body`가 있는데, [ReadableStream](https://streams.spec.whatwg.org/#rs-class) 객체인 `response.body`를 사용하면 응답 본문을 청크 단위로 읽을 수 있습니다. 자세한 용례는 곧 살펴보겠습니다.
=======
- **`response.text()`** -- read the response and return as text,
- **`response.json()`** -- parse the response as JSON,
- **`response.formData()`** -- return the response as `FormData` object (explained in the [next chapter](info:formdata)),
- **`response.blob()`** -- return the response as [Blob](info:blob) (binary data with type),
- **`response.arrayBuffer()`** -- return the response as [ArrayBuffer](info:arraybuffer-binary-arrays) (low-level representation of binary data),
- additionally, `response.body` is a [ReadableStream](https://streams.spec.whatwg.org/#rs-class) object, it allows you to read the body chunk-by-chunk, we'll see an example later.
>>>>>>> upstream/master

지금까지 배운 내용을 토대로 GitHub에서 마지막 커밋을 JSON 객체 형태로 받아봅시다.

Expand Down Expand Up @@ -205,21 +192,12 @@ let response = fetch(protectedUrl, {

`GET` 이외의 요청을 보내려면 추가 옵션을 사용해야 합니다.

<<<<<<< HEAD
- **`method`** -- HTTP 메서드(예: `POST`)
- **`body`** -- 요청 본문으로 다음 항목 중 하나이어야 합니다.
- 문자열(예: JSON 문자열)
- `FormData`객체 -- `form/multipart` 형태로 데이터를 전송하기 위해 쓰입니다.
- `Blob`나 `BufferSource` -- 바이너리 데이터 전송을 위해 쓰입니다.
- [URLSearchParams](info:url) -- 데이터를 `x-www-form-urlencoded` 형태로 보내기 위해 쓰이는데, 요즘엔 잘 사용하지 않습니다.
=======
- **`method`** -- HTTP-method, e.g. `POST`,
- **`body`** -- the request body, one of:
- a string (e.g. JSON-encoded),
- `FormData` object, to submit the data as `multipart/form-data`,
- `Blob`/`BufferSource` to send binary data,
- [URLSearchParams](info:url), to submit the data in `x-www-form-urlencoded` encoding, rarely used.
>>>>>>> upstream/master

대부분은 JSON을 요청 본문에 실어 보내게 됩니다.

Expand Down Expand Up @@ -318,7 +296,6 @@ fetch(url, options)
.then(result => /* 결과 처리 */)
```

<<<<<<< HEAD
응답 객체의 프로퍼티는 다음과 같습니다.
- `response.status` -- 응답의 HTTP 코드
- `response.ok` -- 응답 상태가 200과 299 사이에 있는 경우 `true`
Expand All @@ -330,19 +307,6 @@ fetch(url, options)
- **`response.formData()`** -- 응답을 `FormData` 객체 형태로 반환(form/multipart 인코딩에 대한 내용은 다음 챕터에서 다룸)
- **`response.blob()`** -- 응답을 [Blob](info:blob)(타입이 있는 바이너리 데이터) 형태로 반환
- **`response.arrayBuffer()`** -- 응답을 [ArrayBuffer](info:arraybuffer-binary-arrays)(바이너리 데이터를 로우 레벨로 표현한 것) 형태로 반환
=======
Response properties:
- `response.status` -- HTTP code of the response,
- `response.ok` -- `true` if the status is 200-299.
- `response.headers` -- Map-like object with HTTP headers.

Methods to get response body:
- **`response.text()`** -- return the response as text,
- **`response.json()`** -- parse the response as JSON object,
- **`response.formData()`** -- return the response as `FormData` object (`multipart/form-data` encoding, see the next chapter),
- **`response.blob()`** -- return the response as [Blob](info:blob) (binary data with type),
- **`response.arrayBuffer()`** -- return the response as [ArrayBuffer](info:arraybuffer-binary-arrays) (low-level binary data),
>>>>>>> upstream/master

지금까지 배운 `fetch` 옵션은 다음과 같습니다.
- `method` -- HTTP 메서드
Expand Down
10 changes: 1 addition & 9 deletions 5-network/02-formdata/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,7 @@ HTML에 `form` 요소가 있는 경우, 위와 같은 코드를 작성하면 해
</script>
```

<<<<<<< HEAD
요청을 받아 처리하는 서버 측 코드는 튜토리얼 범위를 넘어서서 추가하진 않았는데, 서버는 POST 요청을 받아 '저장 성공'이라는 응답을 보내준다고 정도만 알고 계시면 됩니다.
=======
In this example, the server code is not presented, as it's beyond our scope. The server accepts the POST request and replies "User saved".
>>>>>>> upstream/master
이 예시에서 요청받아 처리하는 서버 코드는 튜토리얼 범위를 벗어나므로 제시하지 않습니다. 서버는 POST 요청을 받고 "저장 성공"이라고 응답을 보내준다는 정도만 알고 계시면 됩니다.

## FormData 메서드

Expand Down Expand Up @@ -172,11 +168,7 @@ formData.append("image", imageBlob, "image.png");

[FormData](https://xhr.spec.whatwg.org/#interface-formdata) 객체는 `fetch` 등의 네트워크 메서드를 통해 HTML 폼을 보내는데 사용됩니다.

<<<<<<< HEAD
`FormData` 객체는 HTML 폼(`form`)을 직접 넘겨 `new FormData(form)`으로 만들 수도 있고, HTML 폼 없이 다음과 같은 메서드로 필드를 추가해 만들 수도 있습니다.
=======
We can either create `new FormData(form)` from an HTML form, or create an object without a form at all, and then append fields with methods:
>>>>>>> upstream/master

- `formData.append(name, value)`
- `formData.append(name, blob, fileName)`
Expand Down
148 changes: 54 additions & 94 deletions 5-network/04-fetch-abort/article.md
Original file line number Diff line number Diff line change
@@ -1,87 +1,60 @@

# Fetch: Abort
# Fetch: 요청 중단하기

As we know, `fetch` returns a promise. And JavaScript generally has no concept of "aborting" a promise. So how can we cancel an ongoing `fetch`? E.g. if the user actions on our site indicate that the `fetch` isn't needed any more.
`fetch`는 프라미스를 반환합니다. 그런데 자바스크립트에는 일반적으로 프라미스를 '중단'한다는 개념이 없습니다. 그렇다면 진행 중인 `fetch`는 어떻게 취소할 수 있을까요? 예를 들어 사이트에서 사용자 행동을 보고 더 이상 `fetch`가 필요 없다고 판단한 경우처럼 말이죠.

There's a special built-in object for such purposes: `AbortController`. It can be used to abort not only `fetch`, but other asynchronous tasks as well.
이런 목적을 위해 만들어진 특별한 내장 객체가 있습니다. 바로 `AbortController`입니다. `AbortController`를 사용하면 `fetch`뿐만 아니라 다른 비동기 작업도 중단할 수 있습니다.

The usage is very straightforward:
사용법은 아주 간단합니다.

## The AbortController object
## AbortController 객체

Create a controller:
컨트롤러를 하나 만듭니다.

```js
let controller = new AbortController();
```

A controller is an extremely simple object.
컨트롤러는 아주 단순한 객체입니다.

- It has a single method `abort()`,
<<<<<<< HEAD
- And a single property `signal` that allows to set event liseners on it.
=======
- And a single property `signal` that allows to set event listeners on it.
>>>>>>> upstream/master
- 메서드는 `abort()` 하나뿐입니다.
- 이벤트 리스너를 설정할 수 있는 프로퍼티도 `signal` 하나뿐입니다.

When `abort()` is called:
- `controller.signal` emits the `"abort"` event.
- `controller.signal.aborted` property becomes `true`.
`abort()`가 호출되면 다음 일이 일어납니다.
- `controller.signal`에서 `"abort"` 이벤트가 발생합니다.
- `controller.signal.aborted` 프로퍼티 값이 `true`가 됩니다.

<<<<<<< HEAD
Generally, we have two parties in the process:
1. The one that performs an cancelable operation, it sets a listener on `controller.signal`.
2. The one one that cancels: it calls `controller.abort()` when needed.
=======
Generally, we have two parties in the process:
1. The one that performs a cancelable operation, it sets a listener on `controller.signal`.
2. The one that cancels: it calls `controller.abort()` when needed.
>>>>>>> upstream/master
보통 이 과정에는 두 주체가 있습니다.
1. 취소 가능한 작업을 수행하는 쪽은 `controller.signal`에 리스너를 설정합니다.
2. 취소하는 쪽은 필요할 때 `controller.abort()`를 호출합니다.

Here's the full example (without `fetch` yet):
전체 예시를 살펴봅시다. 아직 `fetch`는 사용하지 않습니다.

```js run
let controller = new AbortController();
let signal = controller.signal;

<<<<<<< HEAD
// The party that performs a cancelable operation
// gets "signal" object
=======
// The party that performs a cancelable operation
// gets the "signal" object
>>>>>>> upstream/master
// and sets the listener to trigger when controller.abort() is called
signal.addEventListener('abort', () => alert("abort!"));
// 취소 가능한 작업을 수행하는 쪽은
// "signal" 객체를 받고,
// controller.abort()가 호출되었을 때 실행될 리스너를 설정합니다.
signal.addEventListener('abort', () => alert("중단!"));

// The other party, that cancels (at any point later):
controller.abort(); // abort!
// 취소하는 쪽은 나중에 언제든 다음을 호출합니다.
controller.abort(); // 중단!

// The event triggers and signal.aborted becomes true
// 이벤트가 발생하고 signal.aborted가 true가 됩니다.
alert(signal.aborted); // true
```

<<<<<<< HEAD
As we can see, `AbortController` is just a means to pass `abort` events when `abort()` is called on it.
예시에서 볼 수 있듯이 `AbortController`는 `abort()`가 호출되었을 때 `abort` 이벤트를 전달하는 수단입니다.

We could implement same kind of event listening in our code on our own, without `AbortController` object at all.
`AbortController` 객체 없이도 코드에서 이런 이벤트 리스닝 방식을 직접 구현할 수 있습니다.

But what's valuable is that `fetch` knows how to work with `AbortController` object, it's integrated with it.
하지만 중요한 점은 `fetch`가 `AbortController` 객체와 함께 동작하는 방법을 알고 있다는 것입니다. `fetch`와 `AbortController`는 통합되어 있습니다.

## Using with fetch
## fetch와 함께 사용하기

To become able to cancel `fetch`, pass the `signal` property of an `AbortController` as a `fetch` option:
=======
As we can see, `AbortController` is just a mean to pass `abort` events when `abort()` is called on it.

We could implement the same kind of event listening in our code on our own, without the `AbortController` object.

But what's valuable is that `fetch` knows how to work with the `AbortController` object. It's integrated in it.

## Using with fetch

To be able to cancel `fetch`, pass the `signal` property of an `AbortController` as a `fetch` option:
>>>>>>> upstream/master
`fetch`를 취소할 수 있게 하려면 `AbortController`의 `signal` 프로퍼티를 `fetch` 옵션으로 넘기면 됩니다.

```js
let controller = new AbortController();
Expand All @@ -90,26 +63,22 @@ fetch(url, {
});
```

The `fetch` method knows how to work with `AbortController`. It will listen to `abort` events on `signal`.
`fetch` 메서드는 `AbortController`와 함께 동작하는 방법을 알고 있습니다. `fetch`는 `signal`의 `abort` 이벤트를 감지합니다.

<<<<<<< HEAD
Now, to to abort, call `controller.abort()`:
=======
Now, to abort, call `controller.abort()`:
>>>>>>> upstream/master
이제 중단하려면 `controller.abort()`를 호출하면 됩니다.

```js
controller.abort();
```

We're done: `fetch` gets the event from `signal` and aborts the request.
이게 전부입니다. `fetch``signal`로부터 이벤트를 받아 요청을 중단합니다.

When a fetch is aborted, its promise rejects with an error `AbortError`, so we should handle it, e.g. in `try..catch`.
`fetch`가 중단되면 해당 프라미스는 `AbortError` 에러와 함께 거부됩니다. 따라서 `try..catch` 등으로 이를 처리해야 합니다.

Here's the full example with `fetch` aborted after 1 second:
다음은 1초 후 `fetch`를 중단하는 전체 예시입니다.

```js run async
// abort in 1 second
// 1초 후 중단
let controller = new AbortController();
setTimeout(() => controller.abort(), 1000);

Expand All @@ -118,71 +87,62 @@ try {
signal: controller.signal
});
} catch(err) {
if (err.name == 'AbortError') { // handle abort()
alert("Aborted!");
if (err.name == 'AbortError') { // abort() 처리
alert("중단되었습니다!");
} else {
throw err;
}
}
```

## AbortController is scalable
## AbortController는 확장성이 좋습니다

<<<<<<< HEAD
`AbortController` is scalable, it allows to cancel multiple fetches at once.
=======
`AbortController` is scalable. It allows to cancel multiple fetches at once.
>>>>>>> upstream/master
`AbortController`는 확장성이 좋습니다. 여러 `fetch`를 한꺼번에 취소할 수 있습니다.

Here's a sketch of code that fetches many `urls` in parallel, and uses a single controller to abort them all:
다음은 여러 `url`을 병렬로 가져오고, 하나의 컨트롤러로 모든 요청을 중단하는 코드 예시입니다.

```js
let urls = [...]; // a list of urls to fetch in parallel
let urls = [...]; // 병렬로 가져올 url 목록

let controller = new AbortController();

// an array of fetch promises
// fetch 프라미스 배열
let fetchJobs = urls.map(url => fetch(url, {
signal: controller.signal
}));

let results = await Promise.all(fetchJobs);

// if controller.abort() is called from anywhere,
// it aborts all fetches
// 어디서든 controller.abort()가 호출되면
// 모든 fetch가 중단됩니다.
```

If we have our own asynchronous tasks, different from `fetch`, we can use a single `AbortController` to stop those, together with fetches.
`fetch`와는 다른 자체 비동기 작업이 있다면 하나의 `AbortController`를 사용해 해당 작업과 `fetch`를 함께 멈출 수 있습니다.

We just need to listen to its `abort` event in our tasks:
작업 안에서 `abort` 이벤트를 감지하기만 하면 됩니다.

```js
let urls = [...];
let controller = new AbortController();

let ourJob = new Promise((resolve, reject) => { // our task
let ourJob = new Promise((resolve, reject) => { // 자체 작업
...
controller.signal.addEventListener('abort', reject);
});

let fetchJobs = urls.map(url => fetch(url, { // fetches
let fetchJobs = urls.map(url => fetch(url, { // fetch 작업들
signal: controller.signal
}));

// Wait for fetches and our task in parallel
// fetch 작업과 자체 작업을 병렬로 기다립니다.
let results = await Promise.all([...fetchJobs, ourJob]);

// if controller.abort() is called from anywhere,
// it aborts all fetches and ourJob
// 어디서든 controller.abort()가 호출되면
// 모든 fetch와 ourJob이 중단됩니다.
```

## Summary
## 요약

<<<<<<< HEAD
- `AbortController` is a simple object that generates `abort` event on it's `signal` property when `abort()` method is called (and also sets `signal.aborted` to `true`).
- `fetch` integrates with it: we pass `signal` property as the option, and then `fetch` listens to it, so it becomes possible to abort the `fetch`.
=======
- `AbortController` is a simple object that generates an `abort` event on its `signal` property when the `abort()` method is called (and also sets `signal.aborted` to `true`).
- `fetch` integrates with it: we pass the `signal` property as the option, and then `fetch` listens to it, so it's possible to abort the `fetch`.
>>>>>>> upstream/master
- We can use `AbortController` in our code. The "call `abort()`" -> "listen to `abort` event" interaction is simple and universal. We can use it even without `fetch`.
- `AbortController`는 `abort()` 메서드가 호출되면 `signal` 프로퍼티에서 `abort` 이벤트를 발생시키는 단순한 객체입니다. 이때 `signal.aborted`도 `true`로 설정됩니다.
- `fetch`는 `AbortController`와 통합되어 있습니다. `signal` 프로퍼티를 옵션으로 넘기면 `fetch`가 이를 감지하므로 `fetch`를 중단할 수 있습니다.
- `AbortController`는 일반 코드에서도 사용할 수 있습니다. `abort()` 호출과 `abort` 이벤트 감지로 이어지는 상호작용은 단순하고 범용적입니다. `fetch` 없이도 사용할 수 있습니다.
Loading