// Chat // Используя функцию jsonPost на адрес http://students.a-level.com.ua:10012 напишите чат-клиент, который: {// jsonPost function function jsonPost(url, data) { return new Promise((resolve, reject) => { var x = new XMLHttpRequest() x.onerror = () => reject(new Error('jsonPost failed')) x.open('POST', url, true) x.send(JSON.stringify(data)) x.onreadystatechange = () => { if (x.readyState == XMLHttpRequest.DONE && x.status == 200) { resolve(JSON.parse(x.responseText)) } else if (x.status != 200) { reject(new Error('status is not 200')) } } }) } // общий div const allChat = document.createElement('div') allChat.style.cssText = ` margin: 0 auto; width: min-content; padding: 10px; border: 1px solid #e5e5e5; border-radius: 10px; box-shadow: 5px 5px 10px 0px rgb(173 173 173); ` document.body.append(allChat) // Stage 1 - работает нормаль, отслеживаем nextMessageId и записываем его в getMessageId const chatDiv = document.createElement('div') chatDiv.style.cssText = ` border: 1px solid #e5e5e5; width: 550px; padding: 10px; margin-bottom: 20px; ` allChat.append(chatDiv) const nickName = document.createElement('input') nickName.type = 'text' nickName.placeholder = 'Введите свой никнейм' nickName.value = 'Anon' chatDiv.append(nickName) let lineBreak = document.createElement('br') chatDiv.append(lineBreak) const inputText = document.createElement('textarea') inputText.maxlength = 500 inputText.required inputText.style.cssText = ` resize: none; margin: 20px 0px; height: 90px; width: 90%; ` inputText.placeholder = 'Введите текст сообщения' inputText.value = 'Hi everyone!' chatDiv.append(inputText) lineBreak = document.createElement('br') chatDiv.append(lineBreak) const sendBtn = document.createElement('button') sendBtn.innerText = 'Send' sendBtn.style.padding = '3px 40px' chatDiv.append(sendBtn) // отправка сообщения по нажатию кнопки let getMessageId = 0 sendBtn.onclick = () => { async function sendMessage() { const result = jsonPost('http://students.a-level.com.ua:10012', { func: 'addMessage', nick: `${nickName.value}`, message: inputText.value }) await result.then(res => getMessageId = res.nextMessageId) console.log(getMessageId) return result.data } sendMessage() } // stage2 { const chat = document.createElement('div') chat.style.cssText = ` min-height: 500px; padding: 10px; height: 60%; width: 550px; overflow-y: scroll; overflow-x: hidden; ` allChat.append(chat) async function getAllMessages() { const result = await jsonPost('http://students.a-level.com.ua:10012', { func: "getMessages", messageId: 0 }) const chat = document.createElement('div') chat.style.cssText = ` min-height: 500px; padding: 10px; height: 60%; width: 550px; overflow-y: scroll; overflow-x: hidden; ` allChat.append(chat) for (const message of ((result.data).sort((a, b) => b.timestamp - a.timestamp))) { const chatBlock = document.createElement('div') chatBlock.style.cssText = ` border: 1px solid #e5e5e5; border-radius: 10px; width: 500px; padding: 10px; margin-bottom: 20px; box-shadow: 5px 5px 10px 0px rgb(173 173 173); ` chat.append(chatBlock) for (const [key, value] of Object.entries(message)) { const messageBlock = document.createElement('p') messageBlock.style.margin = '5px 0' messageBlock.innerHTML = `${key}: ${typeof value === 'string' ? value : new Date(value)}` chatBlock.append(messageBlock) } } return result.data } getAllMessages() } // stage3 let getNewMessageId = 0 const chat = document.createElement('div') chat.style.cssText = ` min-height: 500px; padding: 10px; height: 60%; width: 550px; overflow-y: scroll; overflow-x: hidden; ` allChat.append(chat) async function getMessages(param) { const result = await jsonPost('http://students.a-level.com.ua:10012', { func: "getMessages", messageId: param }) for (const message of result.data) { const chatBlock = document.createElement('div') chatBlock.style.cssText = ` border: 1px solid #e5e5e5; border-radius: 10px; width: 500px; padding: 10px; margin-bottom: 20px; box-shadow: 5px 5px 10px 0px rgb(173 173 173); ` chat.prepend(chatBlock) for (const [key, value] of Object.entries(message)) { const messageBlock = document.createElement('p') messageBlock.style.margin = '5px 0' messageBlock.innerHTML = `${key}: ${typeof value === 'string' ? value : new Date(value)}` chatBlock.append(messageBlock) } } getNewMessageId = result.nextMessageId return result.data } getMessages(getNewMessageId) // stage 4 const intervalId = setInterval(() => getMessages(getNewMessageId), 4000) // stage 5 { function jsonPost(url, data) { return new Promise((resolve, reject) => { var x = new XMLHttpRequest() x.onerror = () => reject(new Error('jsonPost failed')) x.open('POST', url, true) x.send(JSON.stringify(data)) x.onreadystatechange = () => { if (x.readyState == XMLHttpRequest.DONE && x.status == 200) { resolve(JSON.parse(x.responseText)) } else if (x.status != 200) { reject(new Error('status is not 200')) } } }) } // общий div const allChat = document.createElement('div') allChat.style.cssText = ` margin: 0 auto; width: min-content; padding: 10px; border: 1px solid #e5e5e5; border-radius: 10px; box-shadow: 5px 5px 10px 0px rgb(173 173 173); ` document.body.append(allChat) const chatDiv = document.createElement('div') chatDiv.style.cssText = ` border: 1px solid #e5e5e5; width: 550px; padding: 10px; margin-bottom: 20px; ` allChat.append(chatDiv) const nickName = document.createElement('input') nickName.type = 'text' nickName.placeholder = 'Введите свой никнейм' nickName.value = 'Anon' chatDiv.append(nickName) let lineBreak = document.createElement('br') chatDiv.append(lineBreak) const inputText = document.createElement('textarea') inputText.maxlength = 500 inputText.required inputText.style.cssText = ` resize: none; margin: 20px 0px; height: 90px; width: 90%; ` inputText.placeholder = 'Введите текст сообщения' inputText.value = 'Hi everyone!' chatDiv.append(inputText) lineBreak = document.createElement('br') chatDiv.append(lineBreak) const sendBtn = document.createElement('button') sendBtn.innerText = 'Send' sendBtn.style.padding = '3px 40px' chatDiv.append(sendBtn) // отправка сообщения по нажатию кнопки let getMessageId = 0 // async function sendMessage(nick, message) отсылает сообщение. async function sendMessage() { const result = jsonPost('http://students.a-level.com.ua:10012', { func: 'addMessage', nick: `${nickName.value}`, message: inputText.value }) await result.then(res => getMessageId = res.nextMessageId) console.log(getMessageId) return result.data } // async function getMessages() получает сообщения и отрисовывает их в DOM const chat = document.createElement('div') chat.style.cssText = ` min-height: 500px; padding: 10px; height: 60%; width: 550px; overflow-y: scroll; overflow-x: hidden; ` allChat.append(chat) let getNewMessageId = 0 async function getMessages(param) { const result = await jsonPost('http://students.a-level.com.ua:10012', { func: "getMessages", messageId: param }) for (const message of result.data) { const chatBlock = document.createElement('div') chatBlock.style.cssText = ` border: 1px solid #e5e5e5; border-radius: 10px; width: 500px; padding: 10px; margin-bottom: 20px; box-shadow: 5px 5px 10px 0px rgb(173 173 173); ` chat.prepend(chatBlock) for (const [key, value] of Object.entries(message)) { const messageBlock = document.createElement('p') messageBlock.style.margin = '5px 0' messageBlock.innerHTML = `${key}: ${typeof value === 'string' ? value : new Date(value)}` chatBlock.append(messageBlock) } } getNewMessageId = result.nextMessageId return result.data } getMessages(getNewMessageId) // async function sendAndCheck() использует две предыдущие для минимизации задержки между отправкой сообщения и приходом их.Именно эта функция должна запускаться по кнопке. async function sendAndCheck() { await Promise.all([sendMessage(), getMessages(getNewMessageId)]) } sendBtn.onclick = () => sendAndCheck() // async function checkLoop() использует delay и бесконечный цикл для периодического запуска getMessages(). async function checkLoop(param) { const delay = ms => new Promise(ok => setTimeout(() => ok(ms), ms)) while (true) { await delay(param).then(() => getMessages(getNewMessageId)) } } checkLoop(5000) } // stage 6 // Заменить внутренности jsonPost на код, использующий fetch вместо XMLHttpRequest. { function jsonPost(url, data) { return new Promise((resolve, reject) => { fetch(url, { method: 'POST', body: JSON.stringify(data) }) .then(res => res.json()) .then(data => resolve(data), () => reject(new Error('status is not 200'))) }) } // общий div const allChat = document.createElement('div') allChat.style.cssText = ` margin: 0 auto; width: min-content; padding: 10px; border: 1px solid #e5e5e5; border-radius: 10px; box-shadow: 5px 5px 10px 0px rgb(173 173 173); ` document.body.append(allChat) const chatDiv = document.createElement('div') chatDiv.style.cssText = ` border: 1px solid #e5e5e5; width: 550px; padding: 10px; margin-bottom: 20px; ` allChat.append(chatDiv) const nickName = document.createElement('input') nickName.type = 'text' nickName.placeholder = 'Введите свой никнейм' nickName.value = 'Anon' chatDiv.append(nickName) let lineBreak = document.createElement('br') chatDiv.append(lineBreak) const inputText = document.createElement('textarea') inputText.maxlength = 500 inputText.required inputText.style.cssText = ` resize: none; margin: 20px 0px; height: 90px; width: 90%; ` inputText.placeholder = 'Введите текст сообщения' inputText.value = 'Hi everyone!' chatDiv.append(inputText) lineBreak = document.createElement('br') chatDiv.append(lineBreak) const sendBtn = document.createElement('button') sendBtn.innerText = 'Send' sendBtn.style.padding = '3px 40px' chatDiv.append(sendBtn) // отправка сообщения по нажатию кнопки let getMessageId = 0 // async function sendMessage(nick, message) отсылает сообщение. async function sendMessage() { const result = jsonPost('http://students.a-level.com.ua:10012', { func: 'addMessage', nick: `${nickName.value}`, message: inputText.value }) await result.then(res => getMessageId = res.nextMessageId) console.log(getMessageId) return result.data } // async function getMessages() получает сообщения и отрисовывает их в DOM const chat = document.createElement('div') chat.style.cssText = ` min-height: 500px; padding: 10px; height: 60%; width: 550px; overflow-y: scroll; overflow-x: hidden; ` allChat.append(chat) let getNewMessageId = 0 async function getMessages(param) { const result = await jsonPost('http://students.a-level.com.ua:10012', { func: "getMessages", messageId: param }) for (const message of result.data) { const chatBlock = document.createElement('div') chatBlock.style.cssText = ` border: 1px solid #e5e5e5; border-radius: 10px; width: 500px; padding: 10px; margin-bottom: 20px; box-shadow: 5px 5px 10px 0px rgb(173 173 173); ` chat.prepend(chatBlock) for (const [key, value] of Object.entries(message)) { const messageBlock = document.createElement('p') messageBlock.style.margin = '5px 0' messageBlock.innerHTML = `${key}: ${typeof value === 'string' ? value : new Date(value)}` chatBlock.append(messageBlock) } } getNewMessageId = result.nextMessageId return result.data } getMessages(getNewMessageId) // async function sendAndCheck() использует две предыдущие для минимизации задержки между отправкой сообщения и приходом их.Именно эта функция должна запускаться по кнопке. async function sendAndCheck() { await Promise.all([sendMessage(), getMessages(getNewMessageId)]) } sendBtn.onclick = () => sendAndCheck() // async function checkLoop() использует delay и бесконечный цикл для периодического запуска getMessages(). async function checkLoop(param) { const delay = ms => new Promise(ok => setTimeout(() => ok(ms), ms)) while (true) { await delay(param).then(() => getMessages(getNewMessageId)) } } checkLoop(5000) } } // SWAPI Links // Напишите промисифицированную функцию, которая будет принимать параметром ссылку на swapi.dev(например, https://swapi.dev/api/people/20) и скачивать всю информацию по ссылке, включая вложенные ссылки. Все ссылки внутри скачанного объекта должны заменяться на скачанные объекты. Полученный общий объект должен стать результатом промиса, который возвращает функция. { const swapiLinks = async (url) => { let result = {} let arrWithLinks = [] let arrWithPromises = [] const hero = await fetch(url) const heroData = await hero.json() for (const [key, values] of Object.entries(heroData)) { // сортируем массивы/ссылки/строки из fetch и складываем ссылки (обычные и из массивов) в новый массив if (Array.isArray(values)) { if (values.length > 0) { for (const value of values) { arrWithLinks.push({ [key]: value, }) } } else { result[key] = values } } else if (values.startsWith('https://swapi.dev/api/')) { arrWithLinks.push({ [key]: values, }) } else { result[key] = values } } // итерируем новый массив со ссылками, запускаем параллельный fetch для каждой ссылки for (const item of arrWithLinks) { for (const [keyToParse, urlToParse] of Object.entries(item)) { arrWithPromises.push(fetch(urlToParse) .then(res => res.json()) .then(res => { let itemOfPromise = { [keyToParse]: res } return itemOfPromise })) } } // парсим все ссылки и возвращаем все в объект const resultsAll = Promise.all(arrWithPromises) .then(res => { // собираем все обратно в лоб let arrKeys = [] let resultObj = {} // удаляем дубли повторяющихся ключей и пушим оригинальные в массив for (const item of res) { for (const key in item) { if (!(arrKeys.includes(key))) { arrKeys.push(key) } } } // собираем все в один объект с массивами в ключах for (const item of arrKeys) { resultObj[item] = [] for (const itemObject of res) { for (const [key, value] of Object.entries(itemObject)) { if (key === item) { resultObj[item].push(value) } } } } Object.assign(result, resultObj) return result // расскомментировать, когда будет все готово. этот result отвечает за вывод всего в консоль }) return resultsAll } swapiLinks("https://swapi.dev/api/people/20/") .then(res => console.log('FULL RESULT: ', JSON.stringify(res, null, 4))) } // domEventPromise // Реализуйте промисифицированную функцию, которая резолвит промис по событию в DOM: // Функция должна: // используя addEventListener повесить свой обработчик события на DOM element событие eventName // по событию зарезолвить промис отдав в качестве результата объект события // убрать обработчик с DOM - элемента, используя removeEventListener. { function domEventPromise(element, eventName) { function executor(resolve) { function event(param) { resolve(param) element.removeEventListener(eventName, event) } element.addEventListener(eventName, event) } return new Promise(executor) } const btn = document.createElement('button') btn.innerHTML = `click` document.body.append(btn) domEventPromise(btn, 'click').then(e => console.log('event click happens', e)) }