firebase 회원가입 속도개선(feat : performance)

bebrain·2023년 3월 6일
0
post-thumbnail

우리 사이트를 테스트할 때 유독 회원가입과정이 느려 react-hook-form으로 리팩토링했지만 성능이 전혀 개선되지 않았다.
form을 입력하고 firebase로 보내면 회원가입성공이라는 toast를 띄워주는데 알림이 뜨기까지 2초이상 소요가 되었다. 유저피드백에도 회원가입이 느리다는 얘기가 있어 코드점검을 해보았다.

느렸던 원래 코드

    const signUp = () => {
        createUserWithEmailAndPassword(
            authService,
            getValues("email"),
            getValues("pw")
        )
            .then(async (data) => {
                await setDoc(doc(dbService, "user", data.user.uid), {
                    userId: data.user.uid,
                    userNickname: getValues("nickname"),
                    userEmail: getValues("email"),
                    userPw: getValues("pw"),
                    userImg: "null",
                });
                await updateProfile(data.user, {
                    displayName: getValues("nickname"),
                    photoURL: "null",
                });
                toast.success("회원가입성공! 로그인해주세요", {
                    hideProgressBar: true,
                });
                setTimeout(() => {
                    signOut(authService).then(() => {
                        sessionStorage.clear();
                        location.href = "/login";
                    });
                }, 1500);

                return data.user;
            })
            .catch((error) => {
                console.log(error.message);
                if (error.message.includes("already-in-use")) {
                    toast.error("이미 가입한 회원입니다");
                    return;
                }
            });
    };

setDoc은 firebase의 db의 user collection에 user정보를 저장시켜주는 작업이고 updateProfile은 user의 프로필데이터를 업데이트시켜주는 작업인데 쓸데없이 await이 두 번 들어가서 속도를 늦추는 원인이 되었다.

async await만 제거

const signUp = () => {
        createUserWithEmailAndPassword(
            authService,
            getValues("email"),
            getValues("pw")
        ).then((data) => {
            setDoc(doc(dbService, "user", data.user.uid), {
                userId: data.user.uid,
                userNickname: getValues("nickname"),
                userEmail: getValues("email"),
                userPw: getValues("pw"),
                userImg: "null",
            }),
                updateProfile(data.user, {
                    displayName: getValues("nickname"),
                    photoURL: "null",
                }).catch((error) => {
                    console.log(error.message);
                    if (error.message.includes("already-in-use")) {
                        toast.error("이미 가입한 회원입니다");
                        return;
                    }
                });
            toast.success("회원가입성공! 로그인해주세요", {
                hideProgressBar: true,
            });
            setTimeout(() => {
                signOut(authService).then(() => {
                    sessionStorage.clear();
                    location.href = "/login";
                });
            }, 1500);

            return data.user;
        });
    };

Promise all 사용

출처 : https://code-masterjung.tistory.com/91

Promise all은 비동기함수를 병렬로 실행시켜 준다.
하나씩 순서대로 작업하는 것이 아니라 배열 안에 넣어준 여러 작업들이 동시에 진행되기 때문에 결과적으로 속도가 빨라지는 효과를 얻을 수 있다.

뿐만 아니라 중간에 어떤 함수에서 에러가 나면 즉시 에러를 반환한다.

예를 들어 a(3초), b(1초), c(2초)이라는 작업을 수행한다고 하자. await의 경우 b에서 에러가 발생해도 a의 작업이 끝나는 3초동안 기다렸다가 에러를 반환하지만 Promise all의 경우에는 실행순서와 상관없이 가장 먼저 에러를 반환하는 함수를 기준으로 동작한다. 물론 await에서 가장 빨리 실행되는 함수부터 정렬하면 되지만 현실적으로 각 작업이 얼마나 걸리는지 예상하고 그에 맞게 정렬한다는 것은 불가능하며 비효율적인 작업인 것이다.

    const signUp = () => {
        createUserWithEmailAndPassword(
            authService,
            getValues("email"),
            getValues("pw")
        )
            .then((data) => {
                Promise.all([
                    setDoc(doc(dbService, "user", data.user.uid), {
                        userId: data.user.uid,
                        userNickname: getValues("nickname"),
                        userEmail: getValues("email"),
                        userPw: getValues("pw"),
                        userImg: "null",
                    }),
                    Success("회원가입성공! 로그인해주세요"),
                ]);
                setTimeout(() => {
                    signOut(authService).then(() => {
                        sessionStorage.clear();
                        location.href = "/login";
                    });
                }, 1000);
            })
            .catch((error) => {
                console.log(error.message);
                if (error.message.includes("already-in-use")) {
                    Error("이미 가입한 회원입니다");
                    return;
                }
            });
    };


0개의 댓글