자바스크립트는 너의 눈물을 좋아해.
자바스크립트는 너의 눈물을 좋아해.
이것은 내가 JavaScript의 동기화 및 비동기화 행위에 대해 몇 차례 강연한 것이다.실제 통화는 일종의 반실시간 인코딩 통화다.강연이 끝난 후 실제 코드를 사람들에게 남겨 두는 것이 긴장되어 이 글을 만들었다.
Single-Threaded and Asynchronous JavaScript?
교란판
JavaScript의 핵심은 동기화, 블록 분리, 단일 스레드 언어입니다.이것은 한 번에 한 가지 일만 발생할 수 있다는 것을 의미한다.
사람들이 자바스크립트를 비동기적인 언어라고 말할 때, 그들의 뜻은 당신이 비동기적인 행동을 실현하기 위해 자바스크립트를 조종할 수 있다는 것이다.
비동기식 경계
정의
병행성: 다중 스레드 처리와 스케줄링 (동시).
비동기: 단일 스레드와 이벤트 순환.
관리인
병발성: 같은 시간 내에 발생할 수 있는 더 높은 단계의 임무.
논쟁: 여러 가지 일이 동시에 발생해야 한다.
JavaScript 엔진 세부 정보
이것은 JS 엔진의 일부분이 아니다.브라우저 또는 NodeJS 런타임 환경에 포함됩니다.
시간 초과 설정(4ms 지연);MDN setTimeout의 이 글을 참조하십시오.
In modern browsers, setTimeout()/setInterval() calls are throttled to a minimum of once every 4ms when successive calls are triggered due to callback nesting (where the nesting level is at least a certain depth), or after certain number of successive intervals. - MDN
지옥으로 돌아가다
마지막 피라미드:
주의사항
데이터 조정:
다음 코드는 무엇을 합니까?
export class ThoughtExercise {
_time = 10000;
_wrapper = null
constructor() {};
changeColor = () => {
this._wrapper = document.getElementById('thought-wrapper');
this._wrapper.style.backgroundColor = 'red';
};
changeLayout = () => {
let p = document.createElement('p');
p.setAttribute('id', 'thought-run');
p.innerText = 'Thought Exercise ...';
this._wrapper.appendChild(p);
};
wait = () => {
const start = Date.now();
while(Date.now() < start + this._time) {};
};
event = () => {
this.changeColor();
this.changeLayout();
this.wait();
};
start = () => {
const button = document.getElementById('thought-button');
button.classList.remove('hide');
button.addEventListener('click', this.event);
};
}
회답
이 코드는 본질적으로 단추를 연결합니다. 이 단추를 눌렀을 때changeColor,changeLayout,wait 함수를 자극합니다.
버튼을 클릭하면 코드가 스레드에 잠깁니다. 이때까지_시간은 이미 지나갔다.10000ms가 지나기 전까지는 배경색이 변하지 않습니다.
비동기식 코드
다음 코드를 지정합니다...
export class NonAsynchronous {
_numbers = [1, 2, 3];
constructor() {};
forEachSync = (items, callback) => {
for (const item of items) {
callback(item);
}
};
forEachAsync = (items, callback) => {
for (const item of items) {
setTimeout(() => {
callback(item);
}, 0, item);
}
};
runSync = () => {
console.log('The Start');
this.forEachSync(this._numbers, (number) => {
console.log(number * 2);
});
console.log('The End');
};
runAsync = () => {
console.log('The Start');
this.forEachAsync(this._numbers, (number) => {
console.log(number * 2);
});
console.log('The End');
};
start = (async = false) => {
if (!async) {
this.runSync();
} else {
this.runAsync();
}
}
}
기본적으로 여기서 두 가지 다른 **시작이 발생할 수 있습니다: 비비동기와 비동기;각각 runSync*와 runAsync의 실행 옵션이 있습니다.각 실행은 연관된 forEach 기능으로 사용됩니다.이걸로runSync 자극, 우리는 콘솔에서 아래의 내용을 보아야 한다...
***이거.runAsync 자극, 우리는 아래의 내용을 보아야 한다...
이곳의 차이를 주의하십시오.동기화가 실행될 때, 모든 것은 우리가 예상한 순서에 따라 발생한다.비동기식으로 실행할 때 콘솔의 숫자는 정상적인 JavaScript 실행 흐름 외부에 표시됩니다.
단순 네트워크(아날로그)
답조
export class SimpleNetwork {
_time = 10000;
constructor() {};
networkRequest = () => {
setTimeout(() => {
console.log(`Async Code after ${this._time}ms.`);
}, this._time);
};
start = () => {
console.log('The Start');
this.networkRequest();
console.log('The End');
};
};
이 코드에서 우리는 기본적으로 네트워크 요청을 모의했다.setTimeout을 사용하여 10초 지연을 제공합니다.네트워크 요청이 정상적인 JavaScript 실행 흐름 밖에서 완료되는 것을 보아야 합니다...이 코드를 실행할 때 마지막 줄은 실제로 10초 지연된 후에 표시됩니다.
복잡한 네트워크(아날로그)
중첩 시간 초과 시뮬레이션을 통해 복잡한 네트워크.
export class ComplexNetwork {
_time = 0;
constructor() {};
first = () => {
setTimeout(() => {
console.log('2');
this.second();
console.log('4');
}, this._time);
};
second = () => {
setTimeout(() => {
console.log('3');
}, this._time);
};
start = () => {
console.log('1');
this.first();
console.log('5');
};
}
이 시뮬레이션을 검사할 때, 우리가 기대해야 할 것은 순서가 1, 5, 2, 4, 3이어야 한다는 것이다.ES2015 간단한 약속
완료 및 오류 이벤트 처리 제어 반전 문제.
승낙 신탁
export class SimplePromise {
_time = 0;
constructor() {}
timeout = () => {
setTimeout(() => {
console.log('setTimeout Fired');
}, this._time);
};
promise = () => {
new Promise((resolve, reject) => {
resolve('Resolved');
})
.then(res => console.log(res))
.catch(err => console.log(err));
};
start = () => {
console.log('The Start');
this.timeout();
this.promise();
console.log('The End');
};
}
이 코드는'시작'을 터치한 다음 시간 초과와 약속 함수를 터치하고 마지막에'끝'을 터치해야 합니다.이 경우 작업 순서는 시작이고 끝을 표시해야 합니다.promise가 즉시 해결되고 정상적인 JavaScript 실행 흐름을 초과하는 내용이 없기 때문에 다음 페이지에 표시해야 합니다.마지막으로 시간 초과 기능이 표시됩니다.ES2015 복합 약속
시간 초과와 링크 약속이 있는 복잡한 비동기식.
export class ComplexPromise {
_time = 0;
constructor() {}
timeout = () => {
setTimeout(() => {
console.log('setTimeout Fired');
}, this._time);
};
promise1 = () => {
return new Promise((resolve, reject) => {
resolve('Resolved 1');
})
.then(res => console.log(res))
.catch(err => console.log(err));
};
promise2 = () => {
return new Promise((resolve, reject) => {
resolve('Resolved 2');
})
.then(res => {
console.log(res);
this.promise3();
})
.catch(err => console.log(err));
};
promise3 = () => {
new Promise((resolve, reject) => {
resolve('Resolved 3');
})
.then(res => console.log(res))
.catch(err => console.log(err));
};
start = () => {
console.log('The Start');
this.timeout();
this.promise1();
this.promise2();
console.log('The End');
};
};
여기서 우리는 간단한 약속과 유사한 것들을 보았다.가장 큰 차이점은 연쇄 승낙 2와 3이다.여기서 우리는 간단한 약속 예시와 같은 내용을 보아야 한다. 모든 약속은 시간을 초과하여 운행하기 전에 완성된다.발전기 절류
합작 합병과 선점 합병.
export function * throttle(func, time) {
let timerID = null;
function throttled(arg) {
clearTimeout(timerID);
timerID = setTimeout(func.bind(window, arg), time);
}
while(true) throttled(yield);
}
export class GeneratorThrottle {
constructor() {};
start = () => {
thr = throttle(console.log, 3000);
thr.next('');
};
};
여기, 발전기가 작동할 때,thr는 운행 컨트롤러로 초기화됩니다.3초 후에 기록하다.현재, 우리는 초기화된 후, 다음 함수가 세 번 호출된 것을 볼 수 있다...그러나 컨트롤러는 3초 동안 창이 끝날 때 터치됩니다.
사용자 상호 작용
export class UserInteraction {
constructor() {};
dragStart = (event) => {
event.dataTransfer.setData('text/plain', event.target.id);
console.log('drag start', event);
};
dragOver = (event) => {
event.preventDefault();
event.dataTransfer.dropEffect = 'move';
console.log({ x: event.pageX, y: event.pageY });
};
drop = (event) => {
const id = event.dataTransfer.getData('text');
console.log('drop', id);
const element = document.getElementById('drag');
event.target.appendChild(element);
};
}
기본적으로 이 코드는 드래그 앤 드롭 이벤트가 JavaScript에 대해 스레드를 잠그지 않는 것을 볼 수 있도록 합니다.이벤트 탐지기
이벤트 탐지기는 동기화됩니다 (비동기식)
export class EventListeners {
_btn = null;
_time = 100;
constructor() {};
output = (content) => {
console.log(content);
};
setupListeners = () => {
this._btn.addEventListener('click', this.output.bind(null, 'Click Handler 1'));
this._btn.addEventListener('click', this.output.bind(null,'Click Handler 2'));
};
triggerListeners = () => {
setTimeout(() => {
console.log('The Start');
this._btn.click();
console.log('The End');
}, this._time);
};
start = () => {
this._btn = document.getElementById('event-listener-link');
this.setupListeners();
this.triggerListeners();
};
}
우리는 클릭 사건이 모두 촉발되는 것을 보아야 한다. 왜냐하면...네트워크 종사자
노동자 수
onmessage = function() {
for (let step = 0, len = 10; step <= len; step++) {
postMessage(step * 10);
const start = Date.now();
while (Date.now() < start + 1000) {};
}
}
이것은 웹 워커 코드를 사용하는 코드입니다...export class WebWorkers {
_worker = new Worker('scripts/presentation/crunch-numbers.js');
_inlineProgress = null;
_workerProgress = null;
contructor() {};
crunchNumbersInline = (callback) => {
for (let step = 0, len = 10; step <= len; step++) {
callback(step * 10);
const start = Date.now();
while (Date.now() < start + 1000) {};
}
};
displayPercentInline = (percent) => {
console.log(`inline percent: ${percent}`);
this._inlineProgress.value = percent;
};
displayPercent = (message) => {
console.log(`web-worker percent: ${message.data}`);
this._workerProgress.value = message.data;
}
runSync = () => {
this._inlineProgress = document.getElementById('inline-worker');
this.crunchNumbersInline(this.displayPercentInline);
};
runAsync = () => {
this._workerProgress = document.getElementById('web-worker');
this._worker.postMessage('start');
this._worker.onmessage = this.displayPercent;
};
start = (async = false) => {
if (!async) {
this.runSync();
} else {
this.runAsync();
}
};
}
관련 HTML 페이지를 실행하지 않으면 여기에서 무슨 일이 일어났는지 보기 어렵다.이것은 내연 프로세스가 스레드에 잠겨 있음을 나타냅니다. 백분율은 시간이 만료되기 전에 아무것도 하지 않고 한 번의'점프'에서 100% 를 표시합니다.웹 Worker의 경우 10% 씩 증가분이 정확하게 표시되고 JavaScript는 스레드에 잠기지 않습니다.
부하 시간
원본 내용 (코드를 통해 변경하고자 함)
올바른 내용 변경 (코드를 통해)
위에 표시된 것은...
class LoadTiming {
_time = 10000;
constructor() {};
loadSync = () => {
const element = document.getElementById('first-timing');
if (element) {
element.innerHTML = 'Changed Content Correctly (via code)';
}
};
loadAsync = () => {
setTimeout(() => {
const element = document.getElementById('second-timing');
if (element) {
element.innerHTML = 'Changed Content Correctly (via code)';
}
}, this._time);
};
start = () => {
this.loadSync();
this.loadAsync();
};
}
const code11 = new LoadTiming();
code11.start();
보시다시피 위의 코드는 즉시 동기화와 비동기화 코드를 불러옵니다.여기에 있는 JavaScript는 헤더 내용에 불러오기 때문에, 주체 내용(DOM)이 위치하기 전에 실행되며, 동기화 기능은 getelementById에서 소리 없이 실패합니다.비동기식 버전은 DOM이 준비되었는지 확인하고 코드의 내용을 업데이트할 수 있는 충분한 지연이 있습니다.시간 초과 타이머 설정
이 코드에서 set Timeout 지연이 실제로 얼마나 되는지 보고 싶습니다.
시간 초과 지연 설정은 얼마나 됩니까?
(테스트 지연 조심... 1000회 교체)
export class SetTimeoutTimer {
_repetitions = 0;
_totalRepetitions = 1000;
_delay = 0;
_totalActualDelay = 0;
constructor() {};
getActualDelay = () => {
return this._totalActualDelay / this._totalRepetitions;
};
iterate = () => {
let start = new Date();
setTimeout(() => {
this._totalActualDelay += new Date() - start;
this.testDelay();
}, this._delay);
};
testDelay = () => {
if (this._repetitions++ > this._totalRepetitions) {
console.log(`Requested Delay: ${this._delay}, Acual Average Delay: ${this.getActualDelay()}`);
return;
}
this.iterate();
};
start = (delay = 0) => {
this._delay = delay;
this._repetitions = 0;
this._totalActualDelay = 0;
this.testDelay();
};
}
여기 답은 42가 아니에요.setTimeout의 기본값은 보통 4ms입니다.나는 서로 다른 기계와 브라우저에서 4ms에서 8ms 정도의 변화를 보았다.또한 여기에서 보듯이 이것은 사실상 정수가 아닙니다. (4ms에서 촉발되지 않으며, 그 후 일정 시간 동안 자바스크립트에서 처리할 수 있습니다.)ES2017 비동기식/대기
export class AsyncAwait {
_time = 2000;
_resolve = true;
_success = `Doing something here ... after ${this._time}ms.`;
_fail = `Failed here ... after ${this._time}ms.`;
constructor() {};
asyncProcess = () => {
return new Promise((resolve, reject) => {
setTimeout(() => { (this._resolve === true) ? resolve(this._success) : reject(this._fail); }, this._time);
});
};
asyncAwait = async () => {
try {
console.log(await this.asyncProcess());
} catch (error) {
console.log(error);
}
};
start = (resolveState = true) => {
this._resolve = resolveState;
console.log('The Start');
this.asyncAwait();
console.log('The End');
};
}
기본적으로, 이 코드가 시작될 때,promise의 비동기/대기 버전을 실행합니다.실제로 강연에서, 나는 약속을 거부하는 것을 어떻게 처리하는지 물었고, 나는 그것을 찾아야 했다. (try/catch block)다음은 정확한 해석을 위한 비동기/대기...
... 거부와 같은 코드...
총결산
우리는 검사했다.
결론
이 모든 것은 JavaScript의 동기화와 비동기화 행위에 대한 저의 몇 차례의 강연에서 나온 것입니다.실제 통화는 일종의 반실시간 인코딩 통화다.강연이 끝난 후 실제 코드를 사람들에게 남겨 두는 것이 긴장되어 이 글을 만들었다.
Single-Threaded and Asynchronous JavaScript?
Reference
이 문제에 관하여(자바스크립트는 너의 눈물을 좋아해.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/rfornal/javascript-enjoys-your-tears-4el텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)