Skip to content
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