위의 명령어를 실행하여 이미지를 내려 받습니다. “이 이미지의 최근 버젼은 -d 플래그가 없이 이미지가 실행되지 않습니다. -d 플래그는 detached mode를 가능하게 해줍니다. (detached mode는 터미널/쉘로 부터 컨테이너를 실행시키는 것을 detach하고, 컨테이너 시작 이후에 명령어를 리턴해줍니다.) 보통 이미지의 문제들은 디버깅을 하고 있지만, 지금은 첫번째 예제에 사용하기 위해 -d 를 사용합니다.”
그래서 이 명령어를 실행하면 어떤 일이 일어날까?
도커 호스트에 이미지가 존재하지 않기 때문에 도커 데몬은 레지스트리로 부터 첫번째로 fetch를 한다. 그리고 컨테이너로 이미지를 실행시킵니다.
서버는 실행이되고 있고, 웹사이트를 볼 수 있을까? 무슨 포트가 실행이 되고 있는 중인가요? 그리고 좀 더 중요하게, 어떻게 우리들의 호스트 머신으로 부터 직접적으로 컨테이너에 접근을 할까?
실질적으로, 아직 이 질문에 답변을 할 수 없을 것이다. 이 케이스에서 클라이언트는 어느 포트에서 publish되기 위한 도커 엔진인지 알 수 없다. 그래서 docker run 명령어를 다시 재실행하는 것이 필요합니다.
재실행 하여 publish할 포트와 화면에 보여질 컨테이너의 이름을 커스텀마이징 하여봅시다. detached mode을 해당 컨테이너에서 -d 옵션을 다시 사용할 것입니다.
첫번째, 실행되어져 있는 컨테이너를 멈춰야한다. 그러기 위해서는 컨테이너 아이디가 필요합니다. detached mode에서 컨테이너는 실행되어져있기 때문에 우리는 이를 위해 다른 터미널을 실행할 필요가 없습니다. docker ps를 통해 실행되어져 있는 컨테이너를 확인합니다.
$ docker ps
CONTAINER ID컬럼에서 체크아웃을 합니다. 우리는 CONTAINER ID값을 필요로 합니다. 여기서 CONTAINER ID는 긴 문자열의 시퀀스이고, 원하는 컨테이너를 멈추고나서 지우려고 하는 값입니다. 아레의 예는 시스템에서 CONTAINER ID을 제공합니다. 터미널에서 보는 이 값을 사용해야한다.
$ docker stop 멈추려고 하는 CONTAINER ID $ docker rm 지우려고 하는 CONTAINER ID
“좋은 기능은 전체에 CONTAINER ID을 쓸 필요가 없다는 것입니다. 시작하는 문자열의 몇 글자를 입력할 수 있고, 실행 되어진 컨테이너들 중만약 모든 컨테이너들 중에 유니크 하다면, 도커 클라이언트는 똑똑하게 그것을 집어낸다.” ex) CONTAINER ID가 35a9d35beb20라면 docker stop 35a …
아래의 명령어처럼 deched mode에서 컨테이너를 실행시켜보자.
$ docker run –name static-site-sample -e AUTHOR=”scarlett.kim” -d -P dockersamples/static-site
위의 명령어에서 -d : 터미널로 부터 detach되어진 프로세스와 함께 컨테이너를 만드는 것. -P : 노출된 모든 컨테이너 포트를 도커 호스트의 임의의 포트에 publish함. -e : 컨테이너에 다양한 환경을 pass 하는 것. –name : 컨테이너 이름을 지정하는 것. -AUTHOR : 환경 변수이름이고 Your Name은 이름pass할수 있는 값이다. (작성자 느낌…) docker port명령어를 실행시켜서 port를 볼 수 있습니다.
$ docker port static-site-sample (–name로 지정한 컨테이너 이름)
실제 서버에 이를 배포하기 위해서는 우리는 도커 인스톨 그리고 docker(환경 변수로 passed된 도커의 AUTHER을 볼 수 있다.) 명령어 위에서 실행시키는 것이 필요합니다.
지금 도커 컨테이너안에서 웹서버를 실행시키는 방법은 ? 도커이미지를 어떻게 자신의 것으로 생성하는가? 다음 주제에서 다루지만, 먼저 사용하지 않는 컨테이너들을 모두 멈추고 지워야합니다.
도커이미지
이 부분에서는 도커이미지에 대해 깊게 파고 들려고 합니다. 이미지를 만들고 해당 이미지를 사용하여 로컬에서 응옹프로그램을 실행하고 마지막으로 일부 이미지를 도커 클라우드로 푸시 할 것입니다. 도커 이미지는 컨테이너를 기반으로 하고 있습니다. 이전 예제에서는 레지스트리에서 dockersamples/static-site 이미지를 꺼내 도커 클라이언트에게 해당 이미지를 기반으로 컨테이너를 실행하도록 요청 했습니다.
시스템의 로컬에 사용가능한 이미지들을 보기 위해 docker images 명령어를 실행합니다.
$ docker images
TAG 컬럼은 이미지의 특정 스냅샷을 말하며, ID(IMAGE ID)는 해당 이미지에 해당하는 고유 식별자 입니다.
간단히 설명하면 깃 저장소의 이미지로 생각할 수 있습니다. (이미지는 변경된 것들을 커밋할 수 있고, 다양한 버젼을 가집니다) 특별한 버젼 넘버를 제공하지 않는다면, 클라이언트는 latest가 기본값입니다.
예를 들어 ubuntu이미지의 특정 버젼을 내려 받을 수 있습니다.
$ docker pull ubuntu:12.04
이미지의 버젼 정보를 지정하지 않으면 도커 클라이언트는 기본값으로 latest로 지정이 됩니다. 예를 들어 아래 docker pull명령어는 ubunto:latest의 이미지를 가져 옵니다.
$ docker pull ubuntu
새로운 도커 이미지를 가져오기 위해 레지스트리로부터(도커 스토어와 같은) 이미지를 얻거나 자신의 이미지를 만들 수 있습니다.
도커 스토어에는 사용가능한 이미지들이 수 십 만개의 이미지가 있습니다.
docker search라는 명령어를 통해 직접적으로 이미지들을 찾을수 있습니다.
이미지아 관련하여 중요한 차이점은 base image와 child image이다.
Base image는 parent 이미지를 가지지 않고, 일반적으로 ubuntu, apline 또는 debian과 같은 OS가 있는 이미지입니다.
Child image는 base image을 구축하고 추가적인 기능을 기반으로 추가하는 이미지 입니다.
또 다른 핵심 개념은 Official image와 User image입니다. (둘다 base image 이거나 child images입니다)
Official image는 도커가 승인한 이미지 입니다. Docker, Inc는 모든 공식 리포지토리 콘텐츠를 검토하고 게시하는 전용 팀을 후원 합니다. 이 팀은 업스트림 소프트웨어 관리자, 보안 전문가 및 광범위한 Docker 커뮤니티와 협력합니다. 이러한 이름 앞에는 조직 또는 사용자 이름이 붙지 않습니다.
위의 이미지 목록에서 파이썬, 노드, alpine, nginx 이미지는 공식 (기본) 이미지 입니다.
User image는 사용자가 만들고 공유하는 이미지 입니다. base images를 구축하고 추가적인 기능을 기반으로 추가하는 이미지 입니다. 일반적으로 이들은 user/image-name형태를 가집니다. user값은 도커스토어 user 이름 이거나 조직 이름의 값입니다.
pull 명령어는 도커 레지스트리에서 부터 시스템에 ‘alpine’ 이미지를 fetch하고 save하는 명령어 입니다. 시스템에 모든 이미지의 리스트를 보려면 docker images라는 명령어를 치면 됩니다.
$ docer images
docker Run
이미지로부터 도커 컨테이너를 run 하기 위해서는 docker run 명령어를 사용합니다.
$ docker run apline ls -l
run을 하면 내부적으로 수 많은 일들이 일어납니다.
도커 클라이언트는 도커 데몬을 연결합니다.
도커 데몬은 로컬 저장소를 확인합니다. 이미지가 (여기서는 alpine이미지) 로컬에서 사용할 수 있는지, Docker Store로부터 다운로드가 가능한지에 대한 여부를 확인합니다.(docker pull alpine를 하기 전에 문제가 생긴 다면, 다운로드에 실패합니다.)
docker run alpine를 실행하면, ls -l과 같은 명령어를 입력하면 도커는 지정한 명령어를 실행하고, list하고 있는 것들을 볼수 있습니다.
좀 더 흥미로운 아래의 명령어를 입력해보면
$docker run alpine echo “hello from alpine”
화면에 “hello from alpine”를 볼 수 있습니다. 이 케이스는 도커 클라이언트가 alpine 컨테이너로 부터 echo 명령어를 실행하고 종료하는 케이스 입니다. 만약 해당 명령어를 이미 실행했었다면, 빠르게 실행이 됩니다. 이미지는 가상 머신을 부팅하고, 명령어를 실행하고, killing합니다. 컨테이너가 훨씬 더 빠른 것을 알 수 있습니다.
$ docker run apline /bin/sh
기다리면, 아무 것도 발생하지 않습니다. 이건 버그가 아닙니다. 대화식 쉘은 대화식 터미널에서 실행시키지 않는다면, 명령어를 실행한 후 종료 됩니다. ( 그래서 이 예제에서 이 명령어가 종료 되지 않게 하기 위해서는 docker run -it alpine /bin/sh 명령어를 사용합니다.)
컨테이너 쉘 내부에서는 ls -l, uname -a와 같은 몇몇의 명령어를 사용할 수 있습니다. exit 명령어는 컨테이너를 종료하는 명령어입니다.
docker ps라는 명령어는 최근에 실행된 모든 도커 컨테이너를 보는 명령어입니다.
$ docker ps
실행되고 있는 컨테이너가 없다면, 빈 줄을 볼 수 있습니다. 유용히 쓰이는 명령어는 ‘docker ps -a’
위의 명령어를 통해 실행했던 모든 컨테이너 목록을 볼 수 있습니다. STATUS 컬럼을 통해 이들 컨테이너가 종료된 시간을 알 수 있습니다.
컨테이너에 하나의 명령어만 입력할 수 있을까요? NO!
$ docker run -it run alpine /bin/sh / # ls / # uname -a
run 명령어에 -it를 플래그를 같이 쓰면 컨테이너에서의 대화식 tty을 사용할 수 있습니다. (컨테이너에서 여러개의 명령어를 입력하여 사용할 수 있습니다.)
docker run명령어는 편하고 시간을 단축 시켜주는 가장 자주 사용하는 명령어입니다. run에 대해 훨씬 더 많이 알고 싶으면 docker run –help이라는 명령어를 사용하면 지원하는 모든 플래그 리스트들을 볼 수 있습니다.
도커를 사용하면서 docker run명령어는 자주 보게 될 것 입니다.
Terminology
수 많은 도커 용어를 볼 수 있는데, 도커 용어에 대해서 설명하려 합니다.
Image : 파일 시스템과 애플리케이션의 형태는 컨테이너를 생성하여 사용합니다. docker inspect alpine을 실행하면 이에 대한 자세한 것을 알 수 있다. alpine이미지를 다운 받기 위해 docker pull 명령어를 사용할 수 있습니다. docker run hello-world라는 명령어를 실행하면, docker pull이 백그라운드에서 실행되어 hello-world 이미지를 다운 받습니다.
Container : 도커 이미지의 인스턴스를 실행하면 컨테이너는 실질적인 애플리케이션을 실행합니다. 컨테이너는 애플리케이션, 의존성이 있는 컨테이너들을 포함합니다. 이것은 다른 컨테이너에 있는 커널을 공유하고, 호스트 OS위에 있는 공간에 유저에 있는 연관되어진 프로세스들을 실행합니다. 컨테이너는 다운로드 받아진 alpine 이미지를 docker run 명령어를 통해서 컨테이너가 생성됩니다. docker ps 명령어를 사용하여 실행되어진 컨테이너 리스트를 볼 수 있습니다.
Docker daemon : 도커 컨테이너를 구축, 실행 및 배포하는 호스트에서 실행되는 백그라운드 서비스입니다.
Docker client : 도커 데몬과 함께 사용자와 상호 작용할 수 있게 허용하는 명령어 툴입니다.
Docker Store : 컨테이너, 플러그인 등등 도커 에디션을 찾을 수 있고, 엔터프라이즈에서 사용할 수 있는 도커 이미지 레지스트리이다. (https://store.docker.com/)
아래의 글은 번역을 하였음을 사전에 알려 드립니다 (관련 수치는 해당 원글을 참고하였습니다.) (출처 : http://zuu.kr/izgd)
효과적인 성능 개선 가이드
인터넷을 사용하는 사용자들도 늘어나고 있고, 웹 플랫폼도 점점 커지고 있습니다. 이를 개발하는 우리들은 인터넷 네트워크 환경, 데이터 크기 등등 복잡성을 반영하지 못하는 경우가 많지만 웹에서 사용자들은 느낄 수 있습니다.
오늘날의 웹 상태를 살펴보면 평균 네트워크 속도는 7Mb/s의 속도 제한을 가지고 있고, 전 세계 74억 인구 중 단지 46%만이 인터넷에 접속할 수 있습니다. 인터넷 사용자의 93%가 모바일 기기를 통해 온라인에 접속하고 있습니다.
독일과 브라질과 같은 인터넷이 발달하지 않은 나라에서는 데이터 500MB 패킷을 구매하는데 1시간에서 13 시간 정도 소요됩니다.
웹사이트는 완벽한 형태가 아니어서 평균적으로 사이트는 약 3MB정도 입니다. (이미지는 400MB, 1.7MB의 대역폭) 이는 웹 플랫폼에만 관련된 문제는 아닙니다.
불특정 버그 수정을 위해 200MB를 다운로드 해야하는 사례도 있었습니다.
플랫폼들을 개발하는 기술자들은 항상 최신의 노트북, 초고속 인터넷 환경에서 진행하고 있기 때문에 대부분의 사용자들(일반적인 유저)의 환경을 고려하지 않기도 합니다.
어떻게 하면 성능을 염두에 두고 개발할 수 있을지에 대해 이제 설명을 하려고 합니다.
모든 asset을 최적화하기
성능을 크게 향상시키는 가장 강력하지만 활용도가 낮은 방법 중 하나는 브라우저가 asset을 분석하고 제공하는 방법을 이해하는 것 부터 시작됩니다. 브라우저는 context 분석과 동시에 우선 순위를 결정하는 동안 리소스를 발견하는 데 매우 유용합니다.
request는 사용자의 뷰포트 내에 콘텐츠를 렌더링하는 데 필요한 asset이 포함되어있는 경우 중요합니다.
대부분의 사이트에서 asset은 HTML, CSS, 로고, 웹 글꼴 및 이미지로 볼 수 있습니다. 그 외 javascript, 추적코드, 광고 등등 수십 가지의 asset이 있다. 하지만 이 중 가장 중요한 asset에 대해 우선순위를 정하여 최적화를 시킬 수 있습니다.
를 사용하면 원하는 콘텐츠가 제 시간에 렌더링 되도록 asset의 우선 순위를 high로 수동으로 강요할 수 있습니다.
이 기술은 Time to Interactive 메트릭에서 상당한 개선을 가져와 최적의 사용자 경험을 가능하게합니다.
Light Lighthouse 성능 도구 및 Critical Request Chains 검사를 사용 하거나 Chrome 개발자 도구의 네트워크 탭에서 요청 우선 순위를 확인하여 요청의 우선 순위 를 정하는 방법을 추적합니다 .
일반적인 성능 체크리스트
캐시하기
압축 사용
중요 asset의 우선 순위 지정
콘텐츠 전송 네트워크 사용
이미지 최적화
이미지는 종종 웹 페이지의 전송 된 페이로드의 대부분을 차지하므로 이미지에서 최적화가 가장 큰 성능 향상을 가져올 수 있습니다. 여분의 바이트를 제거하는 데 도움이되는 기존의 많은 전략과 도구가 있지만 질문 할 첫 번째 질문은 “이 이미지가 메시지와 효과를 전달하는 것이 필수적입니까?” 입니다. 이를 제거 할 수 있다면 대역폭을 절약 할뿐만 아니라 요청도 줄일 수 있습니다. 어떤 경우에는 다른 기술로도 비슷한 결과를 얻을 수 있습니다. CSS에는 그림자, 그라디언트, 애니메이션 또는 모양과 같은 아트 방향에 대한 다양한 속성이있어 적절하게 스타일이 지정된 DOM 요소에 대한 asset을 교환 할 수 있습니다.
이미지의 올바른 형식 선택
저작물을 삭제할 수없는 경우 어떤 형식이 적합할지 결정하는 것이 중요합니다. 초기 선택은 벡터 그래픽과 래스터 그래픽 사이에 적용됩니다.
벡터 : 해상도는 독립적이며 대개 크기가 상당히 작습니다. 기본 도형 (선, 다각형, 원 및 점)으로 구성된 로고와 같은 간단한 asset이 적합합니다.
래스터 : 훨씬 더 자세한 결과를 제공합니다. 사진에 적합합니다.
이 결정을 내린 후에는 JPEG, GIF, PNG-8, PNG-24 또는 WEBP 또는 JPEG-XR과 같은 최신 형식 중에서 선택할 수있는 적절한 형식의 비트가 있습니다. 이러한 선택의 폭이 넓어지면 우리는 어떻게 올바른 선택을 할 수 있을까요? 가장 적합한 형식을 찾는 기본 방법은 다음과 같습니다.
JPEG : 다양한 색상의 사진 (예 : 사진) PNG-8 : 몇 가지 색상의 이미지 PNG-24 : 부분 투명성이있는 이미지 GIF : 애니메이션 이미지
이미지 형식의 스펙트럼에서 WebP, JPEG 2000 및 JPEG-XR과 같은 새로운 플레이어가 있습니다. 이 모든 것은 브라우저 공급 업체가 개발했습니다. WebP by Google, Apple의 JPEG 2000, Microsoft의 JPEG-XR입니다.
WebP 는 무손실 압축과 손실 압축을 모두 지원하므로 가장 널리 사용되는 경쟁자입니다. 무손실 WebP는 PNG보다 26 % 작으며 JPG보다 25-34 % 작습니다. 74 % 브라우저 지원을 통해 폴백 (fallback)과 함께 안전하게 사용할 수 있으며 전송 된 바이트의 1/3 비용 절감 효과가 있습니다. JPG 및 PNG는 Photoshop 및 기타 이미지 처리 응용 프로그램뿐만 아니라 명령 줄 인터페이스 ( brew install webp) 를 통해 WebP로 변환 될 수 있습니다 .
이미지를 도구 및 알고리즘으로 최적화
일반적으로 크기가 비교적 작은 SVG를 선택했다면 SVG도 압축해야합니다. SVGO 는 불필요한 메타 데이터를 제거하여 SVG를 신속하게 최적화 할 수있는 명령줄 도구입니다. 또는 웹 인터페이스를 선호하거나 운영 체제에 따라 제한되는 경우 Jake Archibald의 SVGOMG 를 사용 하면 됩니다. SVG는 XML 기반 형식이기 때문에 서버 측에서 GZIP 압축을받을 수도 있습니다.
ImageOptim 은 대부분의 다른 이미지 유형에 탁월한 선택입니다. pngcrush, pngquant, MozJPEG, Google Zopfli 등으로 구성된 포괄적 인 오픈 소스 패키지에 훌륭한 도구 모음이 번들로 제공됩니다. Mac OS 응용 프로그램, 명령 줄 인터페이스 및 Sketch 플러그인으로 제공되는 ImageOptim은 기존 워크 플로우에 쉽게 구현할 수 있습니다. Linux 또는 Windows 사용자의 경우 대부분의 ImageOptim CLI는 사용중인 플랫폼에서 사용할 수 있습니다.
올해 초 신형 인코더를 사용해 보려면 Google은 Guetzli를 사용하면 됩니다. WebP 및 Zopfli에 대한 학습에서 파생 된 Open Source 알고리즘입니다. Guetzli는 사용 가능한 다른 압축 방법보다 최대 35 % 더 작은 JPEG을 생성합니다. 유일한 단점은 처리 속도가 느리다는 것입니다 (메가 픽셀 당 1 분의 CPU).
원하는 결과를 얻고 팀의 워크 플로우에 맞는 도구를 선택하는 것이 좋습니다. 최적화 과정을 자동화하는 것이 이상적입니다. 최적화되지 않은 균열을 미끄러지는 이미지는 없습니다.
책임 있고 반응이 빠른 이미지
10 년 전에 모든 것을 제공하기 위해 한 가지 해결책을 찾지 못했지만 끊임없이 변화하고 반응이 빠른 웹 환경은 오늘날 매우 다릅니다. 그렇기 때문에 신중하게 최적화 된 시각적 리소스를 구현하고 뷰포트 및 장치의 다양한 기능을 제공 할 수 있도록 특별한주의를 기울여야합니다. 다행히도 Responsive Images Community Group (https://responsiveimages.org/) 덕분에 picture요소 및 srcset속성 (둘 다 85 % 이상 지원)을 제공 할 수 있습니다.
이미지의 srcset속성
srcset사용자의 화면 밀도와 크기를 기반으로 이미지를 표시하고자 할 때 해상도 전환 시나리오에서 가장 효과적입니다. 미리 정의 된 규칙의 집합을 기반으로 srcset하고 sizes브라우저가 뷰포트에 따라 제공하는 최상의 이미지를 선택합니다. srcset속성은특히 모바일 사용자를 위해 대역폭을 크게 늘리고 절감을 요청할 수 있습니다.
picture 요소
picture요소 및 media속성은 아트 방향을 쉽게 만들 수 있도록 설계되었습니다. 다양한 조건에 대해 다양한 소스를 제공함으로써 (테스트를 통해 테스트 됨 media-queries), 우리는 해상도에 관계없이 항상 가장 중요한 이미지 요소를 사용할 수있게되었습니다.
성능에 대한 마지막 단계는 전달입니다. 모든 asset은 콘텐츠 전송 네트워크를 사용하면 이익을 얻을 수 있지만 Cloudinary 또는 imgx 와 같이 이미지를 타겟팅하는 특정 도구가 있습니다 . 이러한 서비스를 사용하면 서버의 트래픽을 줄이고 응답 대기 시간을 크게 줄일 수 있습니다.
CDN은 이미지가 많은 사이트에서 응답성이 뛰어난 최적화 된 asset을 제공함으로써 많은 복잡성을 겪을 수 있습니다. 오퍼링은 다르기는하지만 대부분의 경우 크기 조정, 자르기 및 장치 및 브라우저를 기반으로 사용자에게 제공하는 것이 가장 적합한 형식 결정을 처리합니다. 또한 압축, 픽셀 밀도 감지, 워터 마크, 얼굴 인식 및 후 처리를 기능을 제공합니다. 이러한 강력한 기능과 이미지를 제공하는 URL에 매개 변수를 추가 할 수 있습니다.
이미지 성능 점검표
올바른 형식 선택
가능하면 벡터 사용
변화가 눈에 띄지 않으면 품질을 낮추십시오.
새로운 형식으로 실험 해보기
도구 및 알고리즘으로 최적화
srcset및picture 에 대해 알아보기
이미지 CDN 사용
웹 글꼴 최적화
사용자 정의 글꼴을 사용할 수있는 기능은 매우 강력한 디자인 도구입니다. 강력하지만 웹 글꼴을 사용하는 웹 사이트의 68%가 이 유형의 자산은 가장 큰 성능 위반자중 하나입니다. (쉽게 1백킬로바이트 평균 변형 및 서체의 수에 따라). 무게가 가장 중요한 문제가 아니더라도, 보이지 않는 텍스트 (FOIT)의 플래시입니다 . FOIT는 웹 글꼴이 여전히로드되거나 가져 오지 못한 경우에 발생합니다. 그러면 빈 페이지가 생겨 액세스 할 수없는 내용이됩니다. 웹 글꼴이 필요한지 여부 를 신중하게 검토하는 것이 가치가있을 수 있습니다. 그렇다면 실적에 부정적인 영향을 줄 수있는 몇 가지 전략이 있습니다.
웹글꼴의 올바른 형식 선택
EOT, TTF, WOFF 및 최근 WOFF2의 네 가지 웹 글꼴 형식이 있습니다. TTF와 WOFF가 가장 널리 채택되어 90% 이상의 브라우저 지원을 자랑합니다. 타겟팅하는 지원에 따라 WOFF2를 제공 하고 이전 브라우저의 경우 WOFF로 대체 하는 것이 가장 안전 합니다. WOFF2를 사용하는 장점은 사용자 지정 사전 처리 및 압축 알고리즘(예 : Brotli )의 조합으로 인해 약 30 %의 파일 크기 감소 및 향상된 구문 분석 기능입니다.
웹 글꼴 소스를 정의 할 때 @font-face사용할 format()형식을 지정하는 힌트를 사용하면 됩니다.
글꼴을 제공하기 위해 Google Fonts 또는 Typekit을 사용하는 경우이 두 도구는 실적 발자국을 완화하기위한 몇 가지 전략을 구현했습니다. Typekit은 이제 모든 키트를 비동기 적으로 지원하므로 FOIT를 방지 할뿐만 아니라 JavaScript 키트 코드 (10 분이 아닌)를 10일 연장 할 수 있습니다. Google 글꼴은 사용자 기기의 기능에 따라 가장 작은 파일을 자동으로 제공합니다.
유니 코드 범위 하위 집합을 사용하면 큰 글꼴을 더 작은 집합으로 분할 할 수 있습니다. 상대적으로 진보 된 전략이지만 특히 아시아 언어를 타겟팅 할 때 상당한 절약 효과를 가져올 수 있습니다 (중국어 글꼴의 평균 글꼴 크기는 20,000 글리프입니다). 첫 번째 단계는 글꼴을 라틴어, 그리스어 또는 키릴 어와 같이 필요한 언어 집합으로 제한하는 것입니다. 웹 글꼴이 로고 유형 사용에만 필요하면 유니 코드 범위 설명자를 사용하여 특정 문자를 선택하는 것이 좋습니다. Filament Group 은 파일이나 URL을 기반으로 필요한 글리프 목록을 생성 할 수있는 글리프 행거 (glyph hanger) 라는 오픈 소스 명령 줄 유틸리티를 출시했습니다 . 또는 웹 기반 글꼴 다람쥐 웹 글꼴 생성기 는 고급 하위 설정 및 최적화 옵션을 제공합니다. Google Fonts 또는 Typekit을 사용하는 경우 서체 선택기 인터페이스에 언어 하위 집합을 선택하면 기본 하위 집합을 더 쉽게 만들 수 있습니다.
글꼴로드 전략 수립
브라우저는 DOM과 CSSOM을 모두 빌드해야하기 때문에 글꼴은 렌더링을 차단합니다. 웹 글꼴은 기존 노드와 일치하는 CSS 선택기에서 사용되기 전에 다운로드되지 않습니다. 이 동작으로 인해 텍스트 렌더링이 상당히 지연 되어 이전에 언급 한 FOIT (Flash of Invisible Text)가 발생합니다. FOIT는 느린 네트워크 및 모바일 장치에서 더욱 두드러집니다.
글꼴로드 전략을 구현하면 사용자가 귀하의 콘텐츠에 액세스 할 수 없게됩니다. 종종 FAS (Flash of Unstyled Text)를 선택하는 것이 가장 쉽고 효과적인 솔루션입니다.
다행히 Typekit의 Web Font Loader 와 Bram Stein의 Font Face Observer 는 글꼴 로딩 동작을 관리하는 데 도움이 될 수 있습니다. 또한 웹 글꼴 성능 전문가 인 Zach Leatherman은 글꼴로드 전략에 대한 포괄적 인 안내서를 게시 하여 프로젝트에 올바른 방법을 선택하는 데 도움을줍니다. (https://www.zachleat.com/web/comprehensive-webfonts/)
웹 폰트 성능 체크리스트
적절한 형식 선택
글꼴 선택 감사
유니 코드 범위 하위 집합 사용
글꼴로드 전략 수립
자바 스크립트 최적화
현재 JavaScript 번들의 평균 크기는 446KB 이며, 이미 이미지 크기에 따라 두 번째로 큰 asset 유형이됩니다.
우리가 깨닫지 못할 수도있는 점은 우리가 사랑하는 자바 스크립트 뒤에 숨겨진 성능 병목 현상이 훨씬 더 심각 하다는 것입니다 .
분석 및 분석 시간 분석은 앱이 언제 상호 작용할 준비가되었는지를 이해하는 데 중요합니다. 이러한 타이밍은 사용자 장치의 하드웨어 기능에 따라 크게 다릅니다. 파싱 및 컴파일은 로우 엔드 모바일에서 2-5 배 높일 수 있습니다 . Addy의 조사에 따르면 평균적인 전화에서 앱은 대화형 상태에 도달하는 데 16초가 걸리고 데스크톱에서는 8초가 걸리는 것으로 나타났습니다. 이러한 통계를 분석하는 것이 중요하며 다행스럽게도 Chrome DevTools를 통해 이를 수행 할 수 있습니다.
현대 패키지 관리자가 작업하는 방식은 종속성의 수와 크기를 쉽게 가려 낼 수 있습니다. webpack-bundle-analyzer 및 Bundle Buddy 는 코드 중복, 가장 큰 성능 위반자 및 오래된 불필요한 종속성을 식별하는 데 도움이되는 훌륭한 시각 도구입니다.
작동중인 Webpack 번들 분석기.
VS 코드 와 Atom 을 Import Cost확장 하면 가져온 패키지 비용을 훨씬 더 쉽게 볼 수 있습니다.
코드 분할 구현
가능할 때마다 필요한 사용자 경험을 생성하는 데 필요한 asset만 제공해야합니다. bundle.js사용자에게 보이지 않는 코드 처리 상호 작용을 포함 하여 전체 파일을 보내는 것은 최적이 아닙니다 (방문 페이지를 방문 할 때 전체 앱을 처리하는 자바 스크립트를 다운로드하는 경우). 마찬가지로 특정 브라우저 또는 사용자 에이전트를 타겟팅하는 코드를 보편적으로 게재해서는 안됩니다.
가장 널리 사용되는 모듈 번들 중 하나 인 Webpack에는 코드 분할 지원이 제공 됩니다. 가장 간단한 코드 분할은 페이지 당 ( home.js방문 페이지, contact.js연락처 페이지 등) 구현할 수 있지만 Webpack은 동적 가져 오기 또는 지연로드 와 같은 기능을 제공하므로 한 번 살펴 볼 수 있습니다.
대안 프레임 워크 고려
JavaScript 프론트 엔드 프레임 워크는 끊임없이 증가하고 있습니다. 스크립트 2016 설문 조사따르면 React은 가장 인기있는 프레임웍입니다. 조심스럽게 아키텍처 선택 사항을 검사 하겠지만 Preact 와 같은 훨씬 가벼운 대안을 사용하는 것이 더 나을 것 입니다 (Preact는 완전한 React 구현, 높은 성능의 적은 가상 DOM 라이브러리 임). (참고 preact : https://preactjs.com/) 마찬가지로, 우리는 작은 대안을 moment.js에 대한 date-fns(또는 특별한 경우에 moment.js 제거되지 않은locales) 와 같은 더 큰 라이브러리를 교체 할 수 있습니다. 새 프로젝트를 시작하기 전에 어떤 종류의 기능이 필요한지 결정하고 필요와 목표에 가장 적합한 프레임 워크를 선택하는 것이 좋습니다. 때로는 바닐라가 자바 스크립트를 대신하는 것을 의미 할 수도 있습니다.
자바 스크립트 성능 체크리스트
얼마나 많은 JavaScript가 전달되는지 모니터하십시오.
불필요한 의존성 제거
코드 분할 구현
대안 프레임 워크 고려
추적 성능 및 앞으로의 도로
우리는 대부분의 경우 구축 중인 제품의 사용자 경험에 긍정적인 변화를 가져올 수있는 몇 가지 전략에 대해 이야기했습니다. 성능은 까다로운 부분이 될 수 있으며, 우리의 비틀기의 장기적인 결과를 추적하는 것이 필요합니다.
사용자 중심의 성과 측정 기준
뛰어난 성능 측정 기준은 가능한 사용자 경험을 묘사하는데 근접하는 것을 목표로 합니다. 오랫동안 onLoad, onContentLoaded 또는 SpeedIndex에 기반하여 사이트가 얼마나 빨리 상호작용할 수 있는지에 대해 알려주지 않습니다. asset 전달에만 집중할 경우 인지 된 성과 를 수치화하는 것은 쉽지 않습니다 . 다행스럽게도 콘텐츠가 얼마나 빨리 표시되고 대화식으로 표시되는지에 대한 포괄적인 그림을 그리는 몇 가지 타이밍이 있습니다. 이러한 측정 항목은 First Paint, First Meaningful Paint, Visually Complete 및 Interactive Time입니다.
첫 번째 페인트 : 브라우저가 흰색 화면에서 첫 번째 시각적 변경으로 변경되었습니다. 첫 번째 의미있는 페인트 : 텍스트, 이미지 및 주요 항목을 볼 수 있습니다. 시각적으로 완료 : 뷰포트의 모든 내용이 표시됩니다. 대화형 시간 : 뷰포트의 모든 내용이 표시되며 상호 작용할 준비가되었습니다 (주요한 주요 스레드 JavaScript 활동 없음).
이러한 타이밍은 사용자가 보는 것과 직접적으로 일치하므로 추적을위한 훌륭한 후보자가됩니다. 가능하다면 모두를 기록하고 그렇지 않으면 1-2 가지를 선택하여인지 된 성능을 더 잘 이해하십시오. 다른 측정 항목들, 특히 우리가 전송하는 바이트 수 (최적화 및 압축 해제)에 주목할 필요가 있습니다.
이 과정은 한 번에 한 큐브 씩 프로그래밍 방식으로 문자를 형성하는 것으로 구성됩니다. 대부분의 노력은 코드의 값을 미세 조정하여 비율, 위치 및 전체 렌더링을 수정 한 다음 마지막으로 사용자 입력 (마우스 이동, 클릭, 드래그 등)에 따라 각 파트를 이동하는 데 소요되었습니다.
이 프로세스의 이점은 분명하지 않습니다. 하지만 텍스트 편집기 만 사용하여 전체 실험을 만들 수 있으므로 많은 도구를 사용하여 자산을 내보내고 문자의 속성을 조정하는 모든 노력을 피할 수 있습니다. Codepen에서 제공하는 실시간 미리보기를 활용 하면 전체 프로세스가 매우 유연 해졌 습니다.
즉, 프로세스는 관리하기 쉽도록 자체적 인 제약 조건을 갖게되었습니다. 가능한 한 적은 수의 파트로 문자를 작성해야했습니다. 각 부분은 매우 낮은 수의 정점으로 구성됩니다. 애니메이션은 제한된 수의 행동을 목표로해야했습니다.
참고 : 이 과정은 3D 앱이 마음에 들면 모델을 만들 때 사용하는 것이 좋습니다. 가능한 한 효과적 이도록 자신의 기술간에 올바른 균형을 찾는 것입니다. 필자의 경우 모든 프로세스를 하나의 도구로 유지할 때 훨씬 효율적입니다.
제약 조건을 기회로 전환
이 과정에서 요구되는 미니멀리즘은 궁극적으로 각 행동 (편안함, 기쁨, 실망 등)을 묘사하는 가장 정확한 동작을 찾는 좋은 기회였습니다.
모든 입방체와 모든 움직임에 대해 질문을 받았다. 나는 이것을 정말로 필요로 하는가? 그것은 경험을 더 좋게 만들지 않습니까, 아니면 그냥 열렬한 캐릭터 디자이너의 변덕입니까?
나는 매우 단순한 장난감으로 끝을 맺었습니다. 모두 조용하고 미니멀 한 환경에 살고있었습니다.
프로그래밍 방식으로 사물을 애니메이션화하는 것은 아마도 가장 큰 도전이었습니다. 애니메이션 소프트웨어 나 시각적 타임 라인없이 자연 및 유기적인 움직임을 어떻게 조성합니까? 이 애니메이션을 자연스러운 상태에서 사용자 입력에 어떻게 응답합니까?
1 단계 : 관측
이 실험을 시작하기 전에 나는 전하고 싶었던 느낌을 관찰하고 기억하고 고안하는 데 시간을 보냈다.
Chill the Lion을 만들 때까지, 나의 개를 애 태우는 것은 영감의 위대한 원천이되었습니다. 나는 그가 즐거움을 위해 눈을 감은 방법을 관찰하고 그의 목에 긁힘을달라고 요청했다. 프로그래밍 방식으로이를 번역 할 올바른 알고리즘을 찾는 것은 공감과 기본 수학 기술을 혼합 한 것입니다.
“paranoid 새”(아래)에 대해, 나는 한순간의 표정을 가진 불편한 외모를 모방 한 것을 기억하고, 얼마나 많은 시간이 눈과 머리 움직임을 분리했는지 알아내어 설득력있는 행동을 보이도록 노력했습니다.
그러나 때때로, 당신은 당신의 자신의 경험에 의지 할 수 없습니다. 시각적 영감은 때때로 특정 형태을 파악하는 데 필요합니다. 다행히도, 어떤 종류의 미묘한 표현을 찾을 수있는 Giphy 가 있습니다. YouTube와 Vimeo에서 올바른 움직임을 찾기 위해 많은 시간을 보냈습니다.
// Initialize variables.
var scene, camera, renderer, WIDTH, HEIGHT;
var PI = Math.PI;
var angle = 0;
var radius = 10;
var cube;
var cos = Math.cos;
var sin = Math.sin;
function init(event) {
// Get the container that will hold the animation.
var container = document.getElementById('world');
// Get window size.
HEIGHT = window.innerHeight;
WIDTH = window.innerWidth;
// Create a three.js scene; set up the camera and the renderer.
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 50, WIDTH / HEIGHT, 1, 2000 );
camera.position.z = 100;
renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
renderer.setSize(WIDTH, HEIGHT);
renderer.setPixelRatio(window.devicePixelRatio ? window.devicePixelRatio : 1);
container.appendChild(renderer.domElement);
// Create the cube.
var geom = new THREE.CubeGeometry(16,8,8, 1);
var material = new THREE.MeshStandardMaterial({
color: 0x401A07
});
cube = new THREE.Mesh(geom, material);
// Add the cube to the scene.
scene.add(cube);
// Create and add a light source.
var globalLight = new THREE.AmbientLight(0xffffff, 1);
scene.add(globalLight);
// Listen to the window resize.
window.addEventListener('resize', handleWindowResize, false);
// Start a loop that will render the animation in each frame.
loop();
}
function handleWindowResize() {
// If the window is resized, we have to update the camera aspect ratio.
HEIGHT = window.innerHeight;
WIDTH = window.innerWidth;
renderer.setSize(WIDTH, HEIGHT);
camera.aspect = WIDTH / HEIGHT;
camera.updateProjectionMatrix();
}
function loop(){
// Call the update function in each frame to update the cube position.
update();
// Render the scene in each frame.
renderer.render(scene, camera);
// Call the loop function in next frame.
requestAnimationFrame(loop);
}
// Initialize the demo when the page is loaded.
window.addEventListener('load', init, false);``
여기서는 기본적으로 장면, 카메라, 조명 및 큐브를 만들었습니다. 그런 다음 각 프레임에서 큐브의 위치를 업데이트하는 루프를 시작했습니다.
이제 우리는 update()함수 를 추가 할 필요가 있습니다. 삼각 함수 공식을 삽입하여 다음과 같이 플레이 할 수 있습니다
function update(){
// The angle is incremented by 0.1 every frame. Try higher values for faster animation.
angle += .1;
// Try modifying the angle and/or radius for a different movement.
cube.position.x = cos(angle) * radius;
cube.position.y = sin(angle) * radius;
// You might want to use the same principle on the rotation property of an object. Uncomment the next line to see what happens.
//cube.rotation.z = cos(angle) * PI/4;
//Or vary the scale. Note that 1 is added as an offset to avoid a negative scale value.
//cube.scale.y = 1 + cos(angle) * .5;
/*
Your turn! You might want to:
- comment or uncomment the lines above to try new combinations,
- replace cos by sin and vice versa,
- replace radius with an other cyclic function.
For example :
cube.position.x = cos(angle) * (sin(angle) *radius);
...
*/
}
잃어버린 느낌이라면 Codepen 에서 사용할 준비가 된 것 입니다. 사인 및 코사인 함수를 사용하여 큐브를 다른 방식으로 이동하고 애니메이션에 삼각법을 활용하는 방법을 더 잘 이해할 수 있습니다.
또는 다음 데모로 이동하여 자신의 걷기 또는 달리기 사이클을 시작하기위한 출발점으로 사용할 수 있습니다.
삼각법을 사용하여 걷기 또는 달리기 사이클을 만드는 방법
이제는 코드를 사용하여 큐브를 움직이는 방법을 배웠고 동일한 원리를 사용하여 단계별로 간단한 걷기 사이클을 만들 계획입니다.
우리는 이전과 같은 설정을 주로 사용합니다. 가장 큰 차이점은 다른 신체 부위를 만들기 위해 더 많은 큐브가 필요하다는 것입니다.
three.js를 사용하면 다른 그룹 안에 오브젝트 그룹을 내장 할 수 있습니다. 예를 들어 다리, 팔, 머리를 지탱하는 몸체 그룹을 만들 수 있습니다.
우리의 주인공이 어떻게 만들어 졌는지 보자.
Hero = function() {
// This will be incremented later at each frame and will be used as the rotation angle of the cycle.
this.runningCycle = 0;
// Create a mesh that will hold the body.
this.mesh = new THREE.Group();
this.body = new THREE.Group();
this.mesh.add(this.body);
// Create the different parts and add them to the body.
var torsoGeom = new THREE.CubeGeometry(8,8,8, 1);//
this.torso = new THREE.Mesh(torsoGeom, blueMat);
this.torso.position.y = 8;
this.torso.castShadow = true;
this.body.add(this.torso);
var handGeom = new THREE.CubeGeometry(3,3,3, 1);
this.handR = new THREE.Mesh(handGeom, brownMat);
this.handR.position.z=7;
this.handR.position.y=8;
this.body.add(this.handR);
this.handL = this.handR.clone();
this.handL.position.z = - this.handR.position.z;
this.body.add(this.handL);
var headGeom = new THREE.CubeGeometry(16,16,16, 1);//
this.head = new THREE.Mesh(headGeom, blueMat);
this.head.position.y = 21;
this.head.castShadow = true;
this.body.add(this.head);
var legGeom = new THREE.CubeGeometry(8,3,5, 1);
this.legR = new THREE.Mesh(legGeom, brownMat);
this.legR.position.x = 0;
this.legR.position.z = 7;
this.legR.position.y = 0;
this.legR.castShadow = true;
this.body.add(this.legR);
this.legL = this.legR.clone();
this.legL.position.z = - this.legR.position.z;
this.legL.castShadow = true;
this.body.add(this.legL);
// Ensure that every part of the body casts and receives shadows.
this.body.traverse(function(object) {
if (object instanceof THREE.Mesh) {
object.castShadow = true;
object.receiveShadow = true;
}
});
}
이제 이 캐릭터를 장면에 추가해야합니다.
function createHero() {
hero = new Hero();
scene.add(hero.mesh);
}
이것은 three.js로 간단한 캐릭터를 만드는 방법입니다. three.js를 사용하여 문자를 만드는 방법에 대해 자세히 알고 싶으면 Codrops에 대한 자세한 자습서 를 읽어보십시오 .
이 몸체를 만든 후에는 간단한 걷기 사이클에 도달 할 때까지 점차적으로이 모든 부분을 하나씩 움직이게 할 것입니다.
전체 논리는 객체 의 run함수에 위치 Hero합니다.
Hero.prototype.run = function(){
// Increment the angle.
this.runningCycle += .03;
var t = this.runningCycle;
// Ensure that the angle we will use is between 0 and 2 Pi.
t = t % (2*PI);
// Amplitude is used as the main radius of the legs movement.
var amp = 4;
// Update the position and rotation of every part of the body.
this.legR.position.x = Math.cos(t) * amp;
this.legR.position.y = Math.max (0, - Math.sin(t) * amp);
this.legL.position.x = Math.cos(t + PI) * amp;
this.legL.position.y = Math.max (0, - Math.sin(t + PI) * amp);
if (t<PI){
this.legR.rotation.z = Math.cos(t * 2 + PI/2) * PI/4;
this.legL.rotation.z = 0;
} else{
this.legR.rotation.z = 0;
this.legL.rotation.z = Math.cos(t * 2 + PI/2) * PI/4;
}
this.torso.position.y = 8 - Math.cos( t * 2 ) * amp * .2;
this.torso.rotation.y = -Math.cos( t + PI ) * amp * .05;
this.head.position.y = 21 - Math.cos( t * 2 ) * amp * .3;
this.head.rotation.x = Math.cos( t ) * amp * .02;
this.head.rotation.y = Math.cos( t ) * amp * .01;
this.handR.position.x = -Math.cos( t ) * amp;
this.handR.rotation.z = -Math.cos( t ) * PI/8;
this.handL.position.x = -Math.cos( t + PI) * amp;
this.handL.rotation.z = -Math.cos( t + PI) * PI/8;
}
코드 기반 애니메이션이 부 자연스러운 움직임을 일으킨다 고 생각할 수도 있습니다. 오히려 나는 매우 유연한 방식으로 움직임을 조정할 수있는 좋은 기회를 제공하여 자신의 성격에 맞는 설득력있는 행동을 쉽게 취할 수 있다고 믿습니다.
행복의 순간 (Moments of Happiness) 은 다양한 실험의 모음이며 각 실험마다 고유 한 문제가 있습니다. 이 기사에서는 실행주기를 만드는 데 사용 된 솔루션을 자세히 설명했습니다. 내 Codepen 페이지에서이 모든 실험을 원하는대로 사용할 수 있습니다. 자유롭게 놀고 대화 형 장난감을 만들 수 있습니다.
자바 스크립트를 배우기 시작하거나 AirBnB와 같은 대규모 인터뷰를 준비할 때, 더 깨끗한 코드를 작성하는 데 도움이되는 5 가지 스타일 가이드가 있습니다.
스타일 가이드 란 무엇일까요?
스타일 가이드는 코드를 작성하고 구성하는 방법을 설명하는 표준 집합입니다. 이 가이드를 읽으면서 각 회사에서 코드를 작성하는 방법에 대한 아이디어를 얻을 수 있습니다.
스타일 가이드가 필요한 이유는 무엇입니까?
한 가지 주된 이유로는 누구나 코드를 다르게 작성합니다. 한 가지 방법으로 뭔가를하고 싶을 수도 있고, 다른 방식으로하고 싶을 수도 있습니다. 우리가 코드에 대해 작업하는 한 괜찮습니다. 하지만 10, 100, 심지어 1,000 명의 개발자가 모두 동일한 코드베이스에서 작업 할 때 어떤 일이 발생할까요? 상황이 매우 지저분 해집니다. 스타일 가이드는 새로운 개발자가 코드 기반을 신속하게 익히고 다른 개발자가 쉽고 빠르게 이해할 수있는 코드를 작성할 수 있도록 만들어졌습니다!
https://github.com/rwaldron/idiomatic.js/ 얼마나 많은 사람들이 공헌했는지에 관계없이 모든 코드 기반의 모든 코드는 한 사람이 입력 한 것처럼 보입니다. 가장 많이 사용되는 JavaScript 스타일 가이드 중 하나 인 관용구 가이드는 여러 언어로 제공되며 요청을 받아 들일 수 있습니다.