diff --git a/contributions/65838.md b/contributions/65838.md new file mode 100644 index 00000000..fcf0d8ce --- /dev/null +++ b/contributions/65838.md @@ -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을 올리는 것이 좋을 것 같습니다 :)