1.동기, 비동기/ajax/json/node.js
2022. 8. 22. 17:21ㆍjavascript
2022.08.22.월
1.동기/비동기
-동기 방식
/*
synchronous : 동기적인
함수가 호출된 순서대로 순차적으로 실행됨 - 동기(sync) 방식
*/
//1.순차 실행
const firstFunc = () => {console.log('첫 번째 함수가 호출 됨.');}
const someLongWork = () => {
console.log('--------------------');
console.log('특정 작업 처리중... 시간이 오래 걸림');
console.log('--------------------');
}
const secondFunc = () => {console.log('두 번째 함수가 호출 됨.');}
//함수들이 작성한 순서대로 순차적으로 ㅗ출됨
firstFunc();
someLongWork();
secondFunc();
/*
한번의 하나의 작업만 처리하기 때문에
특정 작업(ex 특정함수의 호출 someLongWork())이
길어질 경우 secondFunc()는 someLongWork()가
처리될 때까지 작업이 중단됨(Blocking, 블로킹).
*/
console.log(Date.now()); //1970년 1월 1일부터 지금까지 흘러간 초(ms)
function sleep(callbackFn, delay){
console.log('시간 지연중...');
const deleyedTime = Date.now() + delay;
while(Date.now() < deleyedTime);
callbackFn();
}
function firstWork(){
console.log('첫번째 작업 수행');
}
function SecondWork(){
console.log('두번째 작업 수행');
}
sleep(firstWork, 3 * 1000);
SecondWork();
/*
현재 실행 중인 작업이 종료할 때까지
다음에 실행될 작업이 대기하는 방식을
동기(asynchronous) 처리라고 함
장점 : 작업을 순서대로 하나씩 처리, 실행 순서가 보장됨
단점 : 앞선 작업들이 처리될 때까지 다음 작업들이 블로킹됨
-비동기 방식
//2.비동기 방식(asynchronous)
/*
현재 실행 중인 작업이 아직 종료되지 않은 상태라고 해도,
다음에 해야 할 작업을 곧바로 실행시키는 방식
*/
function firstWork(){
console.log('첫번째 작업 수행중');
}
function SecondWork(){
console.log('두번째 작업 수행중');
}
//비동기 기술을 제공하는 몇가지 함수들(setTimeout(), addEventListner())
setTimeout(firstWork, 3 * 1000);
SecondWork();
/*
장점 : 비동기 처리 방식은 현재 실행 중인 작업이 종료되지 않은 상태라고 해도
다음 작업(secondWork)을 곧 바로 실행하기 때문에 블로킹이 발생하지 않는다
단점 : 작업의 수행 순서가 보장되지 않음
비동기 처리 방식으로 동작하는 JS 함수
setTimeout(), setInterval(), HTTP 요청, EventHandler
*/
2.ajax(Asynchronous JavaScript And XML)
//XMLHttpRequest API 객체 생성
const xhr = new XMLHttpRequest();
//XMLHttpRequest 객체가 제공하는
//메서드를 활용하면 HTTP 요청 전송 가능
//요청을 보낼 준비
//xhr.open(요청 메서드, 요청 URL 주소);
//'GET', 서버의 데이터를 조회하고 싶을 때
xhr.open('GET', 'https://jsonplaceholder.typicode.com/todos');
//readyState 프로퍼티 : 요청 준비 상태 체크
console.log(`OPENED, ${xhr.readyState}`);
//준비 상태(readyState) 프로퍼티의 값이
//바뀔 때마다 아래의 함수가 호출됨
xhr.onreadystatechange = () => {
if(xhr.readyState === 2) {
console.log(`HEADERS_RECEIVED, ${xhr.readyState}`);
}
//데이터가 응답, 로딩완료
if(xhr.readyState === 4 && xhr.status === 200) {
console.log(`DONE, ${xhr.readyState}`);
//서버로부터 받은 데이터를 조회할 수 있는 부분
console.log(xhr.responseText); //서버로 부터 응답받은 데이터
}
};
xhr.onprogress = () => {console.log(`LOADING, ${xhr.readyState}`);};
xhr.onload = () => {console.log(`DONE, ${xhr.readyState}`);};
//실제로 요청 전송
xhr.send();
/*
1.readyState : HTTP 요청의 현재 상태를 가지고 있는 함수값 프로퍼티
0-(UNSENT) - 초기화 전, open() 호출하기 전
1-(OPENED) - 열림, open()을 호출하고, send()는 호출하지 않은 상태
2-(HEADERS_RECEIVED) - 요청 전송, send() 호출했지만 서버로부터 응답은 받지 못한 상태
3-(LOADING) - 데이터 수신중, 응답 데이터의 일부를 받고 있는 상태
4-(DONE) - 완료, 응답 데이터를 모두 받은 상태
2.status : HTTP요청에 대한 응답의 성공 여부를 나타내느 값
ex) 200(응답 성공), 404(요청 실패, 잘못된 경로 요청으로 인한)
3.statusText : HTTP요청에 대한 응답 메시지를 나타내는 문자열
ex) status가 200일 경우, 'OK'
4.response Type : 응답된 데이터의 타입
ex)document, json, text, blob 등
5.response : HTPP 요청에 대한 응답 몸체 부분(body)
이벤트 핸들러와 관련된 프로퍼티
onreadstatechange : readystate 프로퍼티의 값이 변경된 경우
메서드
1.open() : HTTP 요청 초기화(준비 단계)
2.send() : HTTP 요청 실제 전송
*/
3.json
/*
json : JavaScript Object Notation
annotation : @, at기호
클라이언트와 서버 간의 HTTP 통신을 위한 텍스트 데이터 포맷(format)
.json이라는 확장자의 파일
JS에 종속되지 않는 언어 독립형 데이터 포맷
대부분의 프로그래밍 언어에서 사용하는 대표적인 포맷팅 개념
*/
//json의 작성 방식 Javascript 객체 작성 방식과 유사함
//JS object
const book = {
title : '노인과 바다',
author : '헤밍웨이',
isSold : false,
genre : ['소설', '경험담'],
}
// JSON 작성 방식 : key 값 및 문자열은 ""(쌍따옴표만 가능)로 작성해야함, 홑따옴표 불가
// {
// "title": "노인과 바다",
// "author": "헤밍웨이",
// "isSold": false,
// "genre": ["novel", "essay"],
// }
//Client 측에서 서버로 데이터(일반적으로 객체)를
//전송하기 위해서 객체를 문자열화(직렬화, Serialization)해야 함
console.log(book);
console.log(book.title); //JS object 정상적으로 접근 가능
const jsonData = JSON.stringify(book);
console.log(typeof jsonData); //type:string
console.log(jsonData.title); //undefined
console.log(jsonData[10]); //문자열이기 때문에 인덱스로 접근
/*
JSON.stringfy() 객체 뿐만 아니라 배열(Array)도
JSON 포맷의 문자열로 직렬화할 수 있음
->일반적으로 서버로 보내는 데이터는 한개(객체) 일 수도 있지만,
여러개(배열) 일 수도 있기 때문에
*/
const books = [
{id:1, title:'하농', author:'하농', isSold:false},
{id:2, title:'체르니', author:'체르니', isSold:false},
{id:3, title:'부르크밀러', author:'부르크밀러', isSold:true},
];
//배열을 JSON 포맷의 문자열로 변환
const jsonData2 = JSON.stringify(books);
console.log(typeof jsonData2, jsonData2);
//jsonData2가 서버로부터 응답받은 json 데이터라고 가정.
//JSON 포맷의 문자열을 JS object로 변환(parsing)
const parsedData = JSON.parse(jsonData2);
console.log(parsedData);
4.node.js
-NPM(Node Package Manager)
Package : JS파일들(모듈)이 모여있는 묶음
Manager : 그런 묶음 폴더들을 관리해주는 사람
→누군가가 JS기반으로 여러 편의 기능들을 라이브러리의 형태로 개발해서
패키로 묶고(패키징), 다른 사람들도 사용할 수 있도록 공개
→패키징된 라이브러리들을 검색, 설치해서 사용할 수 있는 사이트(npmjs.com)
→일련의 자바스크립트 코드들이 패키지의 형태로 구성되어 있음
04.practice folder : Node.js 기반의 프로젝트 root 폴더
package.json
npm으로 시작하는 명령어를 쓰기 위해서는
package.json 파일이 위치한 경로에서만 명령어 사용이 가능
//Node.js, Express FW를 활용하여 간단한 Backend 서버 구성
//express 패키지 import
const express = require('express');
const dotenv = require('dotenv');
dotenv.config();
const app = express();
const clientId = process.env.CLIENT_ID;
const clientSecret = process.env.CLIENT_SECRET;
const request = require('request');
//express static 미들웨어 활용
//express한테 static 파일들의 경로가 어디에 있는지 명시
app.use(express.static("public"));
//express의 json 미들웨어 활용
app.use(express.json());
//일반적으로 /를 root 경로라고함
//root url : 127.0.0.1/
//IP주소 : 127.0.0.1, Port : 3000
//127.0.0.1의 Domain name : localhost
//http://localhost:3000
//app.get() -> 첫번째 인수로 지정한 경로로 클라이언트로부터 요청이 들어왔을 때
//두번째 인수로 작성된 콜백함수가 호출되면서 동작함
//그 콜백함수는 2개의 인수를 받음, 1)reqeust(req), 2)response(res)
app.get('/', (req, res) => {
// res.send('응답 완료!');
//root url, 즉 메인 페이지로 접속했을 때
//우리가 만든 Node 서버는 papago의 메인 화면인
//public/index.html을 응답해줘야 함
res.sendFile("index.html");
});
//localhost:3000/detectLangs 경로로 요청했을 때
app.post('/detectLangs', (req, res) => {
console.log('/detectLangs로 요청됨');
//request.getParameter();
console.log(req.body);
//text 프로퍼티에 있는 값을 query 변수에 담고 싶고,
//targetLanguage는 동일한 이름의 변수로 담고 싶음
const { text:query, targetLanguage } = req.body;
console.log(query, targetLanguage);
//실제 papago 서버에 요청 전송, 택배를 보낼 주소
const url ='https://openapi.naver.com/v1/papago/detectLangs';
const options = { //택배를 보낼 물건
url,
form: { query },
headers: {
'X-Naver-Client-Id': clientId,
'X-Naver-Client-Secret': clientSecret
},
};
//실제 언어 감지 서비스 요청 부분
//options 변수에 요청 전송시 필요한 데이터 및 보낼 주소 동봉
//() => {} : 요청에 따른 응답 정보를 확인하는 부분
request.post(options, (error, response, body) => {
if(!error && response.statusCode === 200) { //응답이 성공적으로 완료되었을 경우
//body를 parsing처리
const parseData = JSON.parse(body);
//papago 번역 url('/translate')로 redirect(요청 재지정)
res.redirect(`translate?lang=${parseData['langCode']}&targetLanguage=${targetLanguage}&query=${query}`);
} else { //응답이 실패했을 경우
console.log(`error = ${response.statusCode}`);
}
});
});
//papgo 번역 요청 부분
app.get('/translate', (req, res) => {
const url = 'https://openapi.naver.com/v1/papago/n2mt';
const source = req.query.lang;
const target = req.query.targetLanguage;
const text = req.query.query;
//req.query = {source, target, text};
console.log(source, target, text);
const options = {
url,
form: { source, target, text },
headers: {
'X-Naver-Client-Id': clientId,
'X-Naver-Client-Secret': clientSecret
},
}
//실제 번역 요청 전송부분
request.post(options, (error, response, body) => {
if(!error && response.statusCode === 200) { //응답이 성공적으로 완료되었을 경우
res.send(body); //front에 해당하는 app.js에 papago로부터 받은 응답 데이터를 전송
} else { //응답이 실패했을 경우
console.log(`error = ${response.statusCode}`);
}
});
});
//서버가 실행되었을 때 몇번 포트에서 실행시킬 것인지
app.listen(3000, () => console.log('http://127.0.0.1:3000/ app listening on port 3000'));
//Node.js 기반의 js파일 실행시에는 node로 시작하는 명렁어
//파일명까지 작성하면 됨
//ex) node server.js -> server.js 실행
//server.js는 express framework로 구성한 백엔드 서버 실행 코드 있음
//변수 네이밍 컨벤션, 도메인과 관련된 용어를 미리 정의
//source : 번역할 텍스트와 관련된 명칭
//target : 번역된 결과와 관련된 명칭
//[왼쪽 텍스트 영역, 오른쪽 텍스트 영역]
const [sourceTextArea, targetTextArea] = document.getElementsByClassName('Card__body__content');
const [sourceSelect, targetSelect] = document.getElementsByClassName('form-select');
//번역하고자 하는 언어의 타입(ko? en? ja?)
let targetLanguage = 'en'; //기본값으로 en
//어떤 언어로 번역할지 선택하는 target select박스의
//선택지의 값이 바뀔 때마다 이벤트 발생하고
//지정한 언어의 타입 값을 targetlanguage 변수에 할당, 출력
//change 이벤트 사용, select 박스가 객체가 가지고 있는 프로퍼티
targetSelect.addEventListener('change', () => {
const targetValue = targetSelect.value;
console.log(targetValue);
targetLanguage = targetValue;
});
let debouncer;
sourceTextArea.addEventListener('input', (event) => {
if(debouncer){
clearTimeout(debouncer);
}
//setTimeout(callback, 지연할 시간(ms))
//콜백함수 : 지연된 시간 후에 동작할 코드
debouncer = setTimeout(() => {
const text = event.target.value; //sourceTextArea의 입력한 값
console.log(text);
//ajax 활용하여 비동기 HTTP 요청 전송
const xhr = new XMLHttpRequest();
const url = '/detectLangs'; //node 서버의 특정 url 주소
xhr.onreadystatechange = () => {
if(xhr.readyState === 4 && xhr.status === 200) {
//최종적으로 papago가 번역해준 번역된 텍스트 결과를 받는 부분
//서버의 응답 결과 확인하는 부분
const parsedData = JSON.parse(xhr.responseText);
const result = parsedData.message.result;
targetTextArea.value = result.translatedText;
const options = sourceSelect.options;
for (let i = 0; i < options.length; i++) {
if(options[i].value === result.srcLangType) {
sourceSelect.selectedIndex = i;
}
}
}
}
//요청 준비
xhr.open('POST', url);
//요청 보낼 때 동봉할 객체(object)
const requestData = {
text, //text: text 프로퍼티와 변수명이 동일한 경우 하나만 작성 가능
targetLanguage,
};
//클라이언트가 서버에게 보내는 요청
//데이터의 형식이 json 형식임을 명시
xhr.setRequestHeader('Content-type', 'application/json'); //header : 제품의 설명서
//보내기 전에 해야 할 일, JS obejct JSON으로 변환(직렬화)
const jsonData = JSON.stringify(requestData);
//실제 요청 전송
xhr.send(jsonData);
}, 3000);
})
'javascript' 카테고리의 다른 글
2.ES6/Promise (0) | 2022.09.13 |
---|---|
0.javascript 문법 (0) | 2022.08.18 |