-
-
Save atronov/fbd7e728b78606a3f5ee to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| window.addEventListener("load", function() { | |
| var resultMessage = ""; | |
| var defaultName = "Japan"; | |
| var name = defaultName; // по умолчанию будет выбрано Japan | |
| var askPopulation = function() { | |
| var message = (resultMessage && resultMessage+"\n") + "Put country or city name"; | |
| // Я бы никогда не стал использовать prompt, но так написано в задании =) | |
| name = window.prompt(message, name); | |
| if (name && name.trim().length > 0) { | |
| name = name.trim(); | |
| getCityOrCountryPopulation(name, function(error, result) { | |
| if (error) { | |
| resultMessage = "Error happens: " + error; | |
| console.error(error); | |
| } else { | |
| resultMessage = [ | |
| (result.city)? "Population of city " + name + " - " + result.city: null, | |
| (result.country)? "Population of country " + name + " - " + result.country: null] | |
| .filter(function(line) { return line; }) | |
| .join("/n"); | |
| if (resultMessage.length === 0) { | |
| resultMessage = "No country nor city with name " + name; | |
| } | |
| } | |
| // если пользователь ввёл что-то то выводим результат сразу | |
| askPopulation(); | |
| }); | |
| } else { | |
| name = defaultName; | |
| resultMessage = "You put nothing. Try again."; | |
| // если ничено не вводил или нажал Cancel, ждём 4 секунды и позволяем закрыть эту ужасную страницу | |
| setTimeout(askPopulation, 4000); | |
| } | |
| }; | |
| askPopulation(); | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>ШРИ - Задаие 2</title> | |
| <script src="shri.js" type="application/javascript"></script> | |
| <script src="app.js" type="application/javascript"></script> | |
| </head> | |
| <body> | |
| <!-- Не нужно контента, всё через window.prompt --> | |
| </body> | |
| </html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Реализация API, не изменяйте ее | |
| * @param {string} url | |
| * @param {function} callback | |
| */ | |
| function getData(url, callback) { | |
| var RESPONSES = { | |
| '/countries': [ | |
| {name: 'Cameroon', continent: 'Africa'}, | |
| {name :'Fiji Islands', continent: 'Oceania'}, | |
| {name: 'Guatemala', continent: 'North America'}, | |
| {name: 'Japan', continent: 'Asia'}, | |
| {name: 'Yugoslavia', continent: 'Europe'}, | |
| {name: 'Tanzania', continent: 'Africa'} | |
| ], | |
| '/cities': [ | |
| {name: 'Bamenda', country: 'Cameroon'}, | |
| {name: 'Suva', country: 'Fiji Islands'}, | |
| {name: 'Quetzaltenango', country: 'Guatemala'}, | |
| {name: 'Osaka', country: 'Japan'}, | |
| {name: 'Subotica', country: 'Yugoslavia'}, | |
| {name: 'Zanzibar', country: 'Tanzania'} | |
| ], | |
| '/populations': [ | |
| {count: 138000, name: 'Bamenda'}, | |
| {count: 77366, name: 'Suva'}, | |
| {count: 90801, name: 'Quetzaltenango'}, | |
| {count: 2595674, name: 'Osaka'}, | |
| {count: 100386, name: 'Subotica'}, | |
| {count: 157634, name: 'Zanzibar'} | |
| ] | |
| }; | |
| setTimeout(function () { | |
| var result = RESPONSES[url]; | |
| if (!result) { | |
| return callback('Unknown url'); | |
| } | |
| callback(null, result); | |
| // этот код нельзя менять, но тут бага: Math.random это функция, а не свойство | |
| // Math.round(Math.random * 1000) === NaN | |
| // setTimeout воспринимает NaN, как 0 | |
| }, Math.round(Math.random() * 1000)); | |
| } | |
| /** | |
| * Ваши изменения ниже | |
| */ | |
| // 1) ошибка происходит из-за переменной request | |
| // описал подробно ниже; | |
| // 2) также проблемы могут возникнуть с использованием переменных в глобальной области видимости (без var) | |
| // i, l, K, j, | |
| // можно было избежать с помощью use strict | |
| // и все другие переменные, которые даже c var но вне функции, будут помещаться в глобальную область видимости, | |
| // если не оборачивать этот код в функцию; | |
| // 3) в API предусмотрена передача ошибки, но в методе она никак не использовалась; | |
| // 4) я бы ещё нормальные имена переменным дал =) | |
| // этот метод я специально не менял, а добавил новые для страны и города ниже | |
| /** | |
| * Get population of country | |
| * @param {string} continent | |
| * @param {function} onPopulation | |
| */ | |
| function getContinentPopulation(continent, onPopulation) { | |
| var requests = ['/countries', '/cities', '/populations']; | |
| var responses = {}; | |
| for (var i = 0; i < 3; i++) { | |
| // тело for не создаёт новой области видимости | |
| // и всегда будет использован один экземпляр переменной request | |
| // в каждом вызове callback всегда будет request="/populations", | |
| // т.к. API работает асинхронно, то все итерации for будут выполнены до первого вызова callback | |
| // нужно создавать новую переменную для каждого вызова callback | |
| // например через bind | |
| // появиться такая ошибка могла из-за того, что разработчик не учел, что облостью видимости | |
| // в JS является всегда функция, так обычно пологают разработчики других ЯП, например Java, | |
| // избежать ошибки можно было не используя оределение функции в теле for, а определить отдельную функцию | |
| // в таком случае нельзя было бы сослаться на переменную request | |
| // в ES6 такая проблема может решаться ключевым словом let, вместо var | |
| var request = requests[i]; | |
| var callback = function (request, error, result) { | |
| if (error) { | |
| onPopulation(error); | |
| return; | |
| } | |
| responses[request] = result; | |
| var l = []; | |
| for (var K in responses) | |
| l.push(K); | |
| if (l.length == 3) { | |
| var c = [], cc = [], p = 0; | |
| for (var i = 0; i < responses['/countries'].length; i++) { | |
| if (responses['/countries'][i].continent === continent) { | |
| c.push(responses['/countries'][i].name); | |
| } | |
| } | |
| for (i = 0; i < responses['/cities'].length; i++) { | |
| for (var j = 0; j < c.length; j++) { | |
| if (responses['/cities'][i].country === c[j]) { | |
| cc.push(responses['/cities'][i].name); | |
| } | |
| } | |
| } | |
| for (i = 0; i < responses['/populations'].length; i++) { | |
| for (j = 0; j < cc.length; j++) { | |
| if (responses['/populations'][i].name === cc[j]) { | |
| p += responses['/populations'][i].count; | |
| } | |
| } | |
| } | |
| onPopulation(null, p); | |
| } | |
| }.bind(this, request); | |
| getData(request, callback); | |
| } | |
| } | |
| /** | |
| * Проверка функции | |
| * Запустить, чтобы проверить работоспособность | |
| */ | |
| function test() { | |
| getContinentPopulation("Africa", function (error, population) { | |
| if (error) { | |
| console.error(error); | |
| } else { | |
| console.log('Total population in African cities:', population); | |
| } | |
| }); | |
| } | |
| /** | |
| * @param {string} city | |
| * @param {function(Object, number)} onPopulation | |
| */ | |
| function getCityPopulation(city, onPopulation) { | |
| var callback = function(error, result) { | |
| if (error) { | |
| onPopulation(error); | |
| return; | |
| } | |
| return onPopulation(null, calcCityPopulation(city, result)); | |
| }; | |
| getData("/populations", callback); | |
| } | |
| /** | |
| * @param {string} country | |
| * @param {function(Object, number)} onPopulation | |
| */ | |
| function getCountryPopulation(country, onPopulation) { | |
| var results = { | |
| "/populations": undefined, | |
| "/cities": undefined | |
| }; | |
| var callback = function(request, error, result) { | |
| if (error) { | |
| onPopulation(error); | |
| return; | |
| } | |
| results[request] = result || []; | |
| if (results["/populations"] && results["/cities"]) { | |
| var population = calcCountryPopulation(country, results["/cities"], results["/populations"]); | |
| onPopulation(null, population); | |
| } | |
| }; | |
| for (var request in results) { | |
| getData(request, callback.bind(null, request)); | |
| } | |
| } | |
| /** | |
| * @param {string} name City or country name | |
| * @param {function(Object, {country: number, city: number})} onPopulation | |
| */ | |
| function getCityOrCountryPopulation(name, onPopulation) { | |
| // сделан отдельный метод, а не просто вызов getCountryPopulation и getCityPopulation | |
| // что-бы не делать лишних вызовов API | |
| var results = { | |
| "/populations": undefined, | |
| "/cities": undefined | |
| }; | |
| var callback = function(request, error, result) { | |
| if (error) { | |
| onPopulation(error); | |
| return; | |
| } | |
| results[request] = result || []; | |
| var cities = results["/cities"]; | |
| var populations = results["/populations"]; | |
| if (populations && cities) { | |
| // считаем и для города и для стрраны, т.к. может быть город и страна с одиним названием | |
| var countryPopulation = calcCountryPopulation(name, cities, populations); | |
| var cityPopulation = calcCityPopulation(name, populations); | |
| onPopulation(null, { | |
| country: countryPopulation, | |
| city: cityPopulation | |
| }); | |
| } | |
| }; | |
| for (var request in results) { | |
| getData(request, callback.bind(null, request)); | |
| } | |
| } | |
| /** | |
| * @param {string} country | |
| * @param {Array.<{name: string, country: string}>} cities | |
| * @param {Array.<{name: string, count: number}>} populations | |
| * @return {number} | |
| */ | |
| function calcCountryPopulation(country, cities, populations) { | |
| var cityNamesOfCountry = cities | |
| .filter(function(city) { return city.country === country; }) | |
| .map(function(city) { return city.name; }); | |
| var population = populations | |
| .filter(function(city) {return cityNamesOfCountry.indexOf(city.name) !== -1;}) | |
| .reduce(function(cur, next) {return cur+next.count;}, 0); | |
| return population; | |
| } | |
| /** | |
| * @param {string} city | |
| * @param {Array.<{name: string, count: number}>} populations | |
| * @return {number} | |
| */ | |
| function calcCityPopulation(city, populations) { | |
| for (var i in populations) { | |
| var name = populations[i].name, | |
| count = populations[i].count; | |
| if (name === city) { | |
| return count; | |
| } | |
| } | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment