Browse Source

HW 12 done

Olga_Brekhuntsova 2 năm trước cách đây
mục cha
commit
f9d5ea78de

+ 104 - 0
hw-js-12-async-promise/.gitignore

@@ -0,0 +1,104 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+
+# Diagnostic reports (https://nodejs.org/api/report.html)
+report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+*.lcov
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# TypeScript v1 declaration files
+typings/
+
+# TypeScript cache
+*.tsbuildinfo
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Microbundle cache
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
+.env.test
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+
+# Next.js build output
+.next
+
+# Nuxt.js build / generate output
+.nuxt
+dist
+
+# Gatsby files
+.cache/
+# Comment in the public line in if your project uses Gatsby and *not* Next.js
+# https://nextjs.org/blog/next-9-1#public-directory-support
+# public
+
+# vuepress build output
+.vuepress/dist
+
+# Serverless directories
+.serverless/
+
+# FuseBox cache
+.fusebox/
+
+# DynamoDB Local files
+.dynamodb/
+
+# TernJS port file
+.tern-port

+ 12 - 0
hw-js-12-async-promise/.prettierrc.json

@@ -0,0 +1,12 @@
+{
+    "printWidth": 80,
+    "tabWidth": 2,
+    "useTabs": false,
+    "semi": true,
+    "singleQuote": true,
+    "trailingComma": "all",
+    "bracketSpacing": true,
+    "jsxBracketSameLine": false,
+    "arrowParens": "avoid",
+    "proseWrap": "always"
+  }

+ 3 - 0
hw-js-12-async-promise/.vscode/settings.json

@@ -0,0 +1,3 @@
+{
+  "liveServer.settings.port": 5502
+}

+ 1 - 0
hw-js-12-async-promise/README.md

@@ -0,0 +1 @@
+Хостинг http://hw_js_12.olgapistryak.fe.a-level.com.ua/

+ 14 - 0
hw-js-12-async-promise/index.html

@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html lang="ru">
+<head>
+<meta charset="UTF-8" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>hw-js-12-async-promise</title>
+</head>
+<body style="padding:30px">
+  <div id="root"></div>
+    <script src="/js/countries.js" type="module"></script>
+  <script src="/js/promiseBasic.js" type="module"></script>
+</body>
+</html>
+

+ 63 - 0
hw-js-12-async-promise/js/countries.js

@@ -0,0 +1,63 @@
+// JSON. 
+
+// -------------УСЛОВИЕ-------------
+// Загрузить используя XMLHttpRequest и распарсить как ассоциативный массив.
+// Организовать выбор страны и города, используя два select и ассоциативный массив из примера выше.
+// При выборе страны в списке городов должны быть только города из выбранной страны.
+
+// -------------РЕШЕНИЕ-------------
+
+  //Начальная разметка
+    const task01block = document.createElement('div');
+   task01block.style = "border: 2px solid green; border-radius:5px; margin-bottom:10px; padding:10px";
+    const task01title = document.createElement('h2');
+    task01title.innerText = 'Task-01  Countries choice';
+    const countrySelect = document.createElement('select');
+    const citySelect = document.createElement('select');
+    countrySelect.innerHTML = "<option value='hide'> -- Country loading--</option>";
+    countrySelect.style = "margin-left:10px; margin-right:10px";
+    citySelect.style = "margin-left:10px";
+    citySelect.innerHTML = "<option value='hide'> -- City loading--</option>";
+  root.appendChild(task01block); 
+    task01block.appendChild(task01title); 
+    task01block.appendChild(countrySelect);
+    task01block.appendChild(citySelect);
+    
+ //Подставляет страну из запроса
+function chooseCountry(responseObj) {
+  const countryList = Object.keys(responseObj);
+ const countryStr = countryList.sort().map(item =>(!(item===''))&&("<option value=" + item + ">" + item + "</option>"));
+  countrySelect.innerHTML = "<option value='hide'> -- Select country --</option>" + countryStr;
+  countrySelect.onchange = () => { chooseCity(countrySelect.value, responseObj) }
+}
+//Подставляет города в зависимости от выбранной страны
+function chooseCity(countrySelected, responseObj) {
+   const cityStr = responseObj[countrySelected].sort().map(item => "<option value=" + item + ">" + item + "</option>");
+    citySelect.innerHTML = "<option value='hide'> -- Select city --</option>" + cityStr;
+ }
+
+
+var request = new XMLHttpRequest() 
+const url = 'https://raw.githubusercontent.com/David-Haim/CountriesToCitiesJSON/master/countriesToCities.json';
+request.open('GET', url, true) // последний параметр указывает на синхронность или асинхронность запроса. В данном случае запрос асинхронный
+
+
+
+request.onreadystatechange = function(){ //обработчик изменения статуса запроса. Статус == 4 сигнализирует о том, что запрос окончен.
+    if (request.readyState != 4){
+        return;
+    }
+
+    if (request.status == 200){
+        const responseObj = JSON.parse(request.responseText);
+        chooseCountry(responseObj );
+                  
+    }
+    else {
+        alert('shit happens: ' +  request.status + ', ' + request.statusText );
+    }
+}
+
+request.send() // инициируем запрос.
+
+  

+ 211 - 0
hw-js-12-async-promise/js/promiseBasic.js

@@ -0,0 +1,211 @@
+// Javascript Async: Promise Homework
+
+// fetch basic
+
+// -------------УСЛОВИЕ-------------
+// С помощью следующего кода считать и вывести информацию о Люке Скайвокере:
+// fetch('https://swapi.dev/api/people/1/')
+//   .then(res => res.json())
+//   .then(luke => console.log(luke))
+// Напишите функцию для отображения любого JSON в форме таблицы. Функция должна принимать два параметра:
+// DOM - элемент, в котором строится таблица
+// JSON, который нужно отобразить.
+
+// -------------РЕШЕНИЕ-------------
+const task02block = document.createElement('div');
+   task02block.style = "border: 2px solid green; border-radius:5px; margin-bottom:10px; padding:10px";
+    const task02title = document.createElement('h2');
+    task02title.innerText = 'Task-02 Fetch basic';
+     root.appendChild(task02block); 
+    task02block.appendChild(task02title); 
+  
+function drawTable(block, JSONdata) {
+  const  heroTable = document.createElement('table');
+  heroTable.innerHTML = "";
+  heroTable.border = "1";
+  heroTable.style.maxWidth="1000px";
+  heroTable.insertAdjacentHTML('beforeend', '<caption><b>Hero portfolio</b></caption>');
+  const heroTableHead = document.createElement('tr');
+    const  heroTableBody= document.createElement('tr');
+   heroTableHead.innerHTML = Object.keys(JSONdata).map(key => `<th>${key}</th>`).join('');
+  heroTableBody.innerHTML = Object.values(JSONdata).map(item => `<td>${item}</td>`).join('').split(',').join(', ');
+   heroTable.appendChild(heroTableHead);
+   heroTable.appendChild(heroTableBody);
+  block.appendChild(heroTable);
+}
+
+
+let url1 = 'https://swapi.dev/api/people/1/';
+
+fetch(url1)
+  .then(res => res.json())
+  .then(luke => drawTable(task02block, luke))
+
+// fetch improved
+
+// -------------УСЛОВИЕ-------------
+// Расширить функцию отображения:
+// Если одно из полей строка или массив.
+// Если строки или строка содержат в себе https://swapi.dev/api/, то выводить вместо текста строки кнопку, при нажатии на которую:
+// делается fetch данных по этой ссылке
+// функция отображения запускает сама себя(рекурсивно) для отображения новых данных в том же элементе.
+
+// -------------РЕШЕНИЕ-------------
+const task03block = document.createElement('div');
+   task03block.style = "border: 2px solid green; border-radius:5px; margin-bottom:10px; padding:10px";
+const task03title = document.createElement('h2');
+      const task03fetchBlock = document.createElement('div');
+    task03title.innerText = 'Task-03 Fetch improved';
+root.appendChild(task03block); 
+        task03block.appendChild(task03title); 
+    task03block.appendChild(task03fetchBlock); 
+  
+function drawTableImproved(block, JSONdata, url) {
+  block.innerHTML = '';
+  const link = 'https://swapi.dev/api/';
+  const  heroTable = document.createElement('table');
+  heroTable.innerHTML = "";
+  heroTable.border = "1";
+  heroTable.style.maxWidth="1000px";
+  let caption=url.split('/')[4];
+  heroTable.insertAdjacentHTML('beforeend', `<caption><b>${caption[0].toUpperCase() + caption.slice(1)}</b></caption>`);
+  const heroTableHead = document.createElement('tr');
+  const  heroTableBody= document.createElement('tr');
+  heroTableHead.innerHTML = Object.keys(JSONdata).map(key => `<th>${key}</th>`).join('');
+  for (let item of Object.values(JSONdata)) {
+    const tableBodyCell = document.createElement('td');
+   
+    if (isNaN(item)&&item.includes(link)) {
+           const btnBodyCell = document.createElement('button');
+      btnBodyCell.style.margin = '5px';
+      btnBodyCell.value = item;
+      btnBodyCell.innerText = "Go to";
+      url = item;
+      btnBodyCell.onclick = () => {fetchFunc( btnBodyCell.value)};
+      tableBodyCell.appendChild(btnBodyCell);
+    }
+    else {
+      if (Array.isArray(item) && item.filter(elem => elem.includes(link)).length) {
+        let i = 1;
+        for (let subItem of item) {
+          const btnBodyCell = document.createElement('button');
+          btnBodyCell.style.margin = '5px';
+           btnBodyCell.value = subItem;      
+          btnBodyCell.innerText = 'Go to ' + i;
+          url=subItem;
+          btnBodyCell.onclick = () => {fetchFunc(btnBodyCell.value)};
+          tableBodyCell.appendChild(btnBodyCell);
+          i++;
+        }
+      }
+      else { tableBodyCell.innerText = item; }
+    }
+     heroTableBody.appendChild(tableBodyCell);
+   }
+ 
+      heroTable.appendChild(heroTableHead);
+   heroTable.appendChild(heroTableBody);
+  block.appendChild(heroTable);
+}
+
+
+let url = 'https://swapi.dev/api/people/1/';
+function fetchFunc(url) {
+  fetch(url)
+  .then(res => res.json())
+  .then(luke => drawTableImproved(task03fetchBlock, luke, url))
+}
+fetchFunc(url);
+
+// myfetch
+
+// -------------УСЛОВИЕ-------------
+// Используя XMLHTTPRequest, напишите промисифицированную функцию myfetch, т.е.функцию, которая возвращает промис,
+// и работает схоже с fetch, только в один этап:
+// myfetch('https://swapi.dev/api/people/1/')
+//   .then(luke => console.log(luke))
+// Функция myfetch ожидает что ответ будет в формате JSON(используйте JSON.parse(response.text))
+// В случае ошибок(request.onerror или request.status не 200) не забудьте вызывать reject
+// function myfetch(url){
+//     return new Promise(function (resolve, reject){
+//         const xhr = new XMLHTTPRequest()
+//         ///...
+//     })
+// }
+
+// -------------РЕШЕНИЕ-------------
+
+const task04block = document.createElement('div');
+   task04block.style = "border: 2px solid green; border-radius:5px; margin-bottom:10px; padding:10px";
+const task04title = document.createElement('h2');
+      const task04fetchBlock = document.createElement('div');
+    task04title.innerText = 'Task-04 My fetch';
+root.appendChild(task04block); 
+        task04block.appendChild(task04title); 
+    task04block.appendChild(task04fetchBlock); 
+
+
+function myfetch(url) {
+  return new Promise(function(resolve, reject) {
+    const xhr = new XMLHttpRequest();
+    xhr.open('GET', url, true);
+
+    xhr.onload = function() {
+      if (this.status == 200) {
+         resolve(JSON.parse(xhr.responseText));
+      } else {
+        var error = new Error(this.statusText);
+        error.code = this.status;
+        alert(error);
+        reject(error);
+      }
+    };
+    xhr.onerror = function() {reject(new Error("Network Error"));
+    };
+
+    xhr.send();
+  });
+
+}
+
+myfetch(url)
+  .then(luke => {
+    console.log(luke);
+    drawTableImproved(task04fetchBlock, luke, url)
+  }
+  );
+
+// race
+
+// -------------УСЛОВИЕ-------------
+// Используя Promise.race запустите запрос на API(myfetch) параллельно с delay.
+// По результату определите, что было быстрее, запрос по сети, или определенный интервал времени.
+// Подберите параметр delay так, чтобы результат был неизвестен изначально, и при многократных запусках быстрее был то delay,
+//     то myfetch.
+
+// -------------РЕШЕНИЕ-------------
+
+const task05block = document.createElement('div');
+   task05block.style = "border: 2px solid green; border-radius:5px; margin-bottom:10px; padding:10px";
+const task05title = document.createElement('h2');
+      const task05fetchBlock = document.createElement('div');
+task05title.innerText = 'Task-05 race';
+    const runPromisesBtn = document.createElement('button');
+runPromisesBtn.innerText = 'Run promises';
+runPromisesBtn.style = 'margin-bottom:20px';
+root.appendChild(task05block); 
+task05block.appendChild(task05title); 
+task05block.appendChild(runPromisesBtn);
+task05block.appendChild(task05fetchBlock); 
+    
+runPromisesBtn.onclick = () => {
+  task05fetchBlock.innerHTML = '';
+
+  const delay = async (ms) => await new Promise((resolve, reject) => setTimeout(() => resolve('2-nd promise'), ms));
+  Promise.race([myfetch(url), delay(100)]).then((value) => {
+    console.log(value);
+    const firstPromise = document.createElement('p');
+    firstPromise.innerText = `Faster was ${JSON.stringify(value)}`;
+    task05fetchBlock.appendChild(firstPromise);
+  })
+}