`Promise.all()`은 여러 개의 프로미스 객체를 받아 이들이 모두 완료될 때까지 기다리는 JavaScript의 비동기 처리 메서드입니다. 다음은 `Promise.all()`의 장단점입니다:
장점: 1. 병렬 실행: `Promise.all()`은 여러 프로미스를 병렬로 실행하므로 여러 개의 비동기 작업을 동시에 처리할 수 있습니다. 이는 성능 향상에 도움이 됩니다. 2. 대기 시간 최소화: 모든 프로미스가 완료될 때까지 대기하므로, 모든 작업이 완료되는 데 가장 긴 시간을 기다리는 것만큼의 시간이 소요됩니다. 이는 대기 시간을 최소화하고 효율적인 처리를 가능하게 합니다. (장점이 아닌 것처럼 보일 수 있습니다만, 순서대로 실행시키고 기다리는 시간보다 병렬로 실행하면 가장 긴 시간과 가장 적은 시간의 호출을 동시에 시작하게 만들 수 있다는 뜻으로 보입니다) E.g. 1초가 걸리는 호출을 3번 호출하면 응답에 필요한 시간은 총 3초. 반면에 1초가 걸리는 호출을 병렬로 실행하면 응답에 필요한 시간은 총 1초
단점: 1. 하나의 프로미스 실패 시 실패: `Promise.all()`은 모든 프로미스가 성공적으로 완료되어야 전체가 성공으로 처리됩니다. 하나의 프로미스라도 실패하면 전체 `Promise.all()`이 실패합니다. 이것은 실패 처리 및 오류 복구가 어려울 수 있습니다. 2. 순서 보장 없음: `Promise.all()`은 프로미스의 순서를 보장하지 않습니다. 따라서 프로미스가 완료되는 순서에 의존하지 않아야 합니다. 3. 모든 프로미스 필요: 모든 프로미스가 필요하며, 일부만 완료되더라도 결과를 얻을 수 없습니다.
`Promise.all()`을 사용할 때는 이러한 장단점을 고려하여 프로젝트 요구사항에 맞게 적절하게 사용해야 합니다.
async function a() {
return 'a';
}
async function b() {
return 'b';
}
await Promise.all([a(), b()]);
Node.js에서 Sequelize ORM같은 것을 사용하지 않고 raw query를 사용하고자 할 때 mysql2 package를 받아 사용할 수 있다. 이 경우 패키지에서 제공하는 prepare/unprepare를 통해 prepared statement injection attack를 방지할 수 있는 방법이 있다.
Prepared statement가 Injection attack을 당했을 경우 예시
// PHP예시를 JavaScript로 변경하여 작성하였으므로 오류가 있을 수 있습니다.
const originData = 1;
const query = `SELECT * FROM user WHERE id = ${originData}`;
// 위처럼 의도하고자 하는 데이터가 올바르게 들어갈 경우 문제는 없다
const spoiledData = '1; DROP TABLE user;';
const query = `SELECT * FROM user WHERE id = ${spoiledData}`;
// 위처럼 데이터가 변조당해 쿼리가 실행될 경우 user 테이블이 drop되는 공격을 받을 수 있다
mysql2 package를 이용해 injection attack을 방지하여 사용하는 예시
const mysql = require('mysql2/promise'); // mysql2의 promise를 사용
const mysqlPool = mysql.createPool(
host: 'localhost',
user: 'root',
database: 'test'
);
const connection = await pool.getConnection();
const data = ['david', 25];
const query = 'SELECT * FROM user WHERE name = ? AND age = ?';
const [rows, fields] = await connection.execute(query, data);
connection.unprepare(query); // unprepare로 만들고 싶을 경우(단 한 번만 쓰는 구문일 경우)
// If you execute same statement again, it will be picked from a LRU cache
// which will save query preparation time and give better performance
mysql2 패키지를 이용하면 데이터와 쿼리문을 분리해서 적용하기 때문에 injection을 방지할 수 있다. 예상되는 로직으로는 mysql2에서 query를 먼저 받아 자체적으로 sanitize? 또는 분류? 작업을 통해 하나의 프로그램이 아닌 것으로 나눈다. 그리고 ?로 해당하는 곳에 data로 넘겨받은 파라미터를 하나씩 적용해준다. 이 과정에서 injection을 검증하는 과정(?)을 거치기 때문에 우리는 안전하게 prepare statement를 사용할 수 있으며 추가적으로 cache효과까지 얻을 수 있다.
이 글에서 하고싶은 말은, 우리는 DB와 통신할 때 prepared statement injection attack을 대비해야 한다는 것이며 만약 Node.js를 사용하고 있다면 mysql2 packge를 이용해 injection attack을 방지함과 동시에 cache효과를 얻을 것을 제안한다는 것이다.
인스턴스가 막 초기화된 후. Called synchronously immediately after the instance has been initialized, before data observation and event/watcher setup.
2. created
인스턴스가 막 만들어진 후. Called synchronously after the instance is created. At this stage, the instance has finished processing the options which means the following have been set up: data observation, computed properties, methods, watch/event callbacks. However, the mounting phase has not been started, and the$elproperty will not be available yet.
3. beforeMount
마운트되기 바로 전. Called right before the mounting begins: therenderfunction is about to be called for the first time.
This hook is not called during server-side rendering.
4. mounted
마운트된 후. Called after the instance has been mounted, whereelis replaced by the newly createdvm.$el. If the root instance is mounted to an in-document element,vm.$elwill also be in-document whenmountedis called.
Note thatmounteddoesnotguarantee that all child components have also been mounted. If you want to wait until the entire view has been rendered, you can usevm.$nextTickinside ofmounted:
mounted: function () {
this.$nextTick(function () {
// Code that will run only after the
// entire view has been rendered
})
}
5. beforeUpdate
DOM에 변화된 데이터가 붙기 전. Called when data changes, before the DOM is patched. This is a good place to access the existing DOM before an update, e.g. to remove manually added event listeners.
This hook is not called during server-side rendering, because only the initial render is performed server-side.
6. updated
DOM에 변화된 데이터가 붙은 후. Called after a data change causes the virtual DOM to be re-rendered and patched.
The component’s DOM will have been updated when this hook is called, so you can perform DOM-dependent operations here. However, in most cases you should avoid changing state inside the hook. To react to state changes, it’s usually better to use acomputed propertyorwatcherinstead.
Note thatupdateddoesnotguarantee that all child components have also been re-rendered. If you want to wait until the entire view has been re-rendered, you can usevm.$nextTickinside ofupdated:
updated: function () {
this.$nextTick(function () {
// Code that will run only after the
// entire view has been re-rendered
})
}
This hook is not called during server-side rendering.
7. activated
Called when a kept-alive component is activated.
This hook is not called during server-side rendering.
8. deactivated
Called when a kept-alive component is deactivated.
This hook is not called during server-side rendering.
9. beforeDestroy
인스턴스가 destroyed되기 전. Called right before a Vue instance is destroyed. At this stage the instance is still fully functional.
This hook is not called during server-side rendering.
10. destroyed
인스턴스가 destroyed된 후 Called after a Vue instance has been destroyed. When this hook is called, all directives of the Vue instance have been unbound, all event listeners have been removed, and all child Vue instances have also been destroyed.
This hook is not called during server-side rendering.
11. ErrorCaptured
Called when an error from any descendent component is captured. The hook receives three arguments: the error, the component instance that triggered the error, and a string containing information on where the error was captured. The hook can returnfalseto stop the error from propagating further.
message에 의존하는 것을 알고 있기 때문에message가 바뀔 때reversedMessage에 의존하는 바인딩을 모두 업데이트할 것입니다. computed 속성의 getter 함수는 사이드 이펙트가 없어 코드를 테스트하거나 이해하기 쉽습니다. computed 속성은 종속 대상을 따라 저장(캐싱)된다는 것입니다. 즉, reversedMessage를 여러 번 요청해도 계산을 다시 하지 않고 계산되어 있던 결과를 즉시 반환합니다.
3. method를 이용
메소드를 호출하면 렌더링을 다시 할 때마다항상함수를 실행합니다. 이 속성을 계산하려면 거대한 배열을 반복해서 다루고 많은 계산을 해야 합니다. 이렇게 불필요한 계산을 반복하는 것보다는 computed를 사용하는 것이 개발공학적으로 훨씬 이득이라고 생각이 듭니다.
Watch
Vue instance의 특정 프로퍼티가 변경될 때 실행되는 반응형 callback
debounce와 capitalize는 lodash에서 제공하는 기능입니다.
위 코드에서 볼 수 있듯, question에 들어오는 input을 감지하고 getAnswer method를 실행시켜 '?'가 포함되어 있는지 감지하거나 API를 호출해 답변을 얻습니다. watch 옵션을 사용하면 비동기 연산 (API 엑세스)를 수행하고, 우리가 그 연산을 얼마나 자주 수행하는지 제한하고, 최종 응답을 얻을 때까지 중간 상태를 설정할 수 있습니다. computed 옵션은 위 기능을 수행할 수 없습니다. watch 옵션은 데이터 변경에 대한 응답으로 비동기식 또는 시간이 많이 소요되는 조작을 수행하려는 경우에 가장 유용합니다.
Usage
computed로 작성이 되는 경우에는 무조건 computed로 작성할 것(이 경우 computed가 거의 옳다) watch로 작성할 경우 코드의 복잡성이 증가할 수 있음.
하지만, 비동기식 또는 시간이 많이 소요되는 조작을 수행하려는 경우에는 watch를 사용하는 것이 유용합니다. 저는 실무에서 특정 기능이 실행되면 반드시 어떤 함수를 실행시켜줘야할 때 사용했습니다. computed와 watch는 고급 Vue 프로그래밍을 하기 위해 반드시 익혀야할 옵션입니다.