// 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))
}