Skip to content
Merged
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
65 changes: 65 additions & 0 deletions contributions/65838.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
---
pr-url: https://github.com/nodejs/node/pull/65838
---

<!-- 아래 양식은 작성 예시입니다. 필요에 따라 자유롭게 수정해 주세요. -->

## 문제 내용

[`Primoridials`를 학습하면서](https://github.com/ossca-node/lab/issues/17) Node.js 빌트인 모듈 내부의 JS API를 사용자가 임의로 수정한다면 그 상위의 모듈들의 동작에도 큰 영향을 끼친다는 것을 학습하였습니다.

이에 대해서도 Node.js에서는 [Implicit use of user-mutable methods](https://github.com/nodejs/node/blob/main/doc/contributing/primordials.md#implicit-use-of-user-mutable-methods)라는 문서를 관리하며 mutable한 속성을 갖고 있는 배열을 조작할 때, 어떤 것들을 주의하며 구현해야할 지에 대해 정의해두었습니다.

그 중 `Avoid for-of loops on arrays` 항목에서는 `for...of` 패턴 대신, 인덱스를 통해 반복문을 순회하는 `for(;;;)` 방식을 사용할 것을 명시하였습니다.

`for...of` 패턴은 내부적으로 JS Array 객체의 `Symbol.iterator` 속성을 프로토타입으로 상속받아 사용하며, `iterator.next()`를 통해 값을 하나씩 순회하는 방식입니다.

```js
{
const iterator = array[Symbol.iterator]();

let { done, value: item } = iterator.next();
while (!done) {
console.log(item);
({ done, value: item } = iterator.next());
}
}
```

하지만 만약 사용자가 `Symbol.iterator`의 구현방식을 다음과 같이 수정해버린다면, `for...of`로 동작하던 빌트인 모듈의 동작이 깨져버릴 수 있습니다.

```js
// 순회하기도 전에, 순회를 종료
Array.prototype[Symbol.iterator] = () => ({
next: () => ({ done: true }),
});
```

이에 대해서, 실제 이미 구현되어 있는 빌트인 모듈 중 내부적으로 `for..of`를 사용하여 구현되어있는 부분들을 `for(;;;)` 방식으로 변경해주는 간단한 수정내용이었습니다.

## 해결 과정과 검증

`/lib/internal/cli_table.js`에서 결과값을 표를 통해 보여줄 때, 다음과 같이 보여주고 있었습니다.

```js
for (const row of rows){
result += `${renderRow(row, columnWidths)}\n`;
}
```

이 부분을 단순히 `for(;;;)` 방식으로 수정해주었습니다.

```js
for (let i = 0; i < rows.length; i++) {
const row = rows[i];
result += `${renderRow(row, columnWidths)}\n`;
}
```

## 기여 회고

그 외에서 다양한 빌트인 모듈 내부에서 `for..of`를 사용하고 있었어 수정할 부분이 많았습니다. 또한 `for...of` 외에도 Primordials의 규칙은 다수 존재하니 이를 통해 구현된 모듈 내부를 살펴보는 것도 좋을 것 같습니다.

하지만 한 가지 고려해야할 점은, [Primordials를 사용할 때 성능적인 이슈가 발생](https://github.com/nodejs/node/blob/main/doc/contributing/primordials.md#primordials-with-known-performance-issues) 할 수도 있기 때문에 고의적으로 수정하지 않는 부분도 존재합니다.

`array.push()`를 `ArrayPrototypePush()`로 수정하면 `array.push()`에 적용되는 V8 최적화가 동일하게 적용되지 않거나 추가 호출 비용이 남을 수 있습니다. 그렇기에 이런 수정에 대해서는 벤치마킹과 함께 PR을 올리는 것이 좋을 것 같습니다 :)