Вопросы?

Вопросы!

Занятие 3

Асинхронность

JS - однопоточный язык

  • Отрисовка DOM
  • Обработка пользовательского ввода
  • Выполнение JS кода
http://jsbin.com/gajoyis/edit?html,js,output
Очередь задач в js MDN + EventLoop
  • Среда выполнения содержит очередь событий (список событий, подлежащих обработке)
  • Каждое событие ассоциируется с некоторой функцией.
  • Каждый вызов функции добавляет запись в стек
  • При завершении функции запись изымается из стека
  • Когда стек освобождается, событие извлекается из очереди и обрабатывается (функция вызывается).
Жена послала мужа за хлебом...

Вопросы?

Создание асинхронности
  • setTimeout / setInterval / setImmediate
  • Асинхронное API (XHR/fetch/getUserMedia/getBattery/getCurrentPosition)
  • Event Listeners
  • Promise *

// передача callback
function check2(num, cb) {
  if(num % 2 === 0) {
    cb('Hola');
  }
}
  

function sleepCb1(cb, delay) {
  setTimeout(function() {
   cb()
  }, delay);
}

function sleepCb2(cb, delay) {
  setTimeout(cb, delay);
}

Стрелочные функции / Arrow functions


var func = function(a, b) {
  return a + b;
}

var func = (a, b) => {
  return a + b;
}

var func = (a, b) => a + b;

var x2 = x => x*2;

var double = a => a*2;

Promise


var p = new Promise((resolve, reject)
                    => setTimeout(() => resolve(1), 5000));
p.then; //
p.catch; //
        
https://learn.javascript.ru/promise
  • Может быть только в 3х состояниях (pending/fullfilled/rejected)
  • Меняет состояние только один раз
  • then-able интерфейс (метод then / catch опционален )
  • Асинхронный

var promise = new Promise(function(resolve, reject) {
  setTimeout(function() { resolve(1); }, 100);
  setTimeout(function() { reject(2); }, 200);
});
promise
  .then(function(data) { console.log('then', data); }); // ?
promise
  .catch(function(data) { console.log('catch', data); }); // ?

        

Callback


httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function() {
  if (httpRequest.readyState === XMLHttpRequest.DONE) {
    if (httpRequest.status === 200) {
      alert(httpRequest.responseText);
    } else {
      alert('There was a problem with the request.');
    }
  }
};
httpRequest.open('GET', 'test.html', true); // false for sync request
httpRequest.send();

Вопросы?

Работа с асинхронным кодом
  • Callback (http://callbackhell.com/)
  • Promises (https://promisesaplus.com/)
  • async / await

function getPostsInfo(done) {
  getPosts(function(posts) {
    getAuthors(posts, function(authors) {
      getCompiledInfo(posts, authors, function(compiledData) {
        done(compiledData);
      });
  });
});
}

function getPostsInfo() {
  let outerPosts;
  return getPosts()
    .then((posts) => getAuthors(outerPosts = posts))
    .then((authors) => getCompiledInfo(outerPosts, authors));
}

async function getPostsInfo() {
  let posts = await getPosts();
  let authors = await getAuthors(posts);
  let info = await getCompiledInfo(posts, authors);
  return info;
}

fetch('test.html')
  .then((resp) => resp.text())
  .then((html) => console.log(html));

Вопросы?

Обработка событий / делегирование


var btn = document.querySelector('button');
  // через свойство
  btn.onclick = function() {
  alert('onclick');
}
// через event-emitter интерфейс
btn.addEventListener('click', function() {
  alert('eventListener for click');
});
А разница?

var o = {
  x: function(data) {
    console.log('x', this, data);
  }
};
var btn = document.querySelector('button');

btn.addEventListener('click', o.x); // 1. ?
btn.addEventListener('click', o.x()); // 2. ?
btn.addEventListener('click', function() { // 3. ?
  o.x();
});
фазы работы с событиями
Объект события
https://developer.mozilla.org/ru/docs/Web/API/MouseEvent

Интерфейс MouseEvent представляет собой событие, которое происходит в результате взаимодествия пользователя с манипулятором ( например, мышью). Наиболее частые из таких событий: click, dblclick, mouseup, mousedown.

MouseEvent выводится из метода UIEvent, который в свою очередь происходит из метода Event. Метод MouseEvent.initMouseEvent() допустимо использовать для лучшей совместимости с предыдущими версиями, однако, для создания MouseEvent рекомендуется использовть конструктор метода MouseEvent().

AnimationEvent AudioProcessingEvent BeforeInputEvent BeforeUnloadEvent BlobEvent ClipboardEvent CloseEvent CompositionEvent CSSFontFaceLoadEvent CustomEvent DeviceLightEvent DeviceMotionEvent DeviceOrientationEvent DeviceProximityEvent DOMTransactionEvent DragEvent EditingBeforeInputEvent ErrorEvent FetchEvent FocusEvent GamepadEvent HashChangeEvent IDBVersionChangeEvent InputEvent KeyboardEvent MediaStreamEvent MessageEvent MouseEvent MutationEvent OfflineAudioCompletionEvent PageTransitionEvent PointerEvent PopStateEvent ProgressEvent RelatedEvent RTCDataChannelEvent RTCIdentityErrorEvent RTCIdentityEvent RTCPeerConnectionIceEvent SensorEvent StorageEvent SVGEvent SVGZoomEvent TimeEvent TouchEvent TrackEvent TransitionEvent UIEvent UserProximityEvent WebGLContextEvent WheelEvent

MDN -> Веб-технологии для разработчиков -> Интерфейсы веб API -> Event

Event.currentTarget Ссылка на текущий зарегистрированный объект, на котором обрабатывается событие.

Event.target Ссылка на целевой объект, на котором произошло событие.

Event.preventDefault() Отменяет событие (если его возможно отменить).

Event.stopPropagation() Остановка распространения события далее по DOM.

JSBIN

document.querySelectorAll('button').forEach((el) => {
  el.addEventListener('click', (ev) => alert(ev.target.innerHTML))
})
JSBIN - делегирование

document.querySelector('body').addEventListener('click', (ev) => 
  ev.target.tagName === 'BUTTON' && alert(ev.target.innerHTML));

document.body.addEventListener('click', ({target}) => target.tagName === 'BUTTON' && alert(target.innerHTML));

Вопросы?


// What is the output?
console.log(1);
setTimeout(function() {
  console.log(2);
}, 1000);
setTimeout(function() {
  console.log(3);
}, 0);
console.log(4);

// What is the output?
function say(a) {
  alert(a);
}
say(1);
  setTimeout(say(2), 5000);
  setTimeout(function() {
  say(3);
}, 1000);
setTimeout(say, 2000, 4);

// What's wrong? How fix?
var done = false;
$.ajax(url, function() { done = true });
while(!done) {
  someWaitingStuff();
}

// Next code print '0,1,2,3,4,4,3,2,1,0'
// Modify only functions ( not loops ) to get output as '4,3,2,1,0,0,1,2,3,4'
var a = function(i) { console.log(i); };
var b = function(i) { console.log(i); };
for(var i = 0; i < 5; i++) {  a(i); }
for(var i = 4; i>=0; i--) { b(i); }

// The following recursive code will cause a stack overflow if the array list is too large. 
// How can you fix this and still retain the recursive pattern?
var list = readHugeList();
var nextListItem = function() {
var item = list.pop();
if (item) {
  // process the list item...
  nextListItem();
}
};