Это часть четвертой из шести частей, посвященных моему прогрессу в изучении курса программирования Гарвардского университета CS50W (веб-программирование с использованием Python и JavaScript).

Эта запись охватывает недели 5, 6 и проект Почта. Для видеопрохождения моего решения проекта нажмите ЗДЕСЬ. Моя предыдущая запись из этой серии находится ЗДЕСЬ.

Сообщить("Привет, Мир!");

До сих пор наш опыт веб-программирования с Python и JavaScript был довольно упрощенным для JavaScript… до сих пор.

1: JavaScript

В (значительно упрощенном) смысле JavaScript — это просто еще один язык программирования с его знакомыми IFs, WHILEs и ORs, а также с некоторыми менее знакомыми синтаксисом и особенностями. В другом (чуть менее упрощённом) смысле JavaScript принципиально отличается: это основная технология Всемирной паутины и основной язык сценариев на стороне клиента. Эти различия означают, что JavaScript выглядит, ощущается и работает по-разному. В отличие от других языков, которые мы рассмотрели в рамках CS50W, код JavaScript не существует изолированно, а написан непосредственно (или связан) через файл HTML; выполняется и отображается в веб-браузере, таком как Chrome или Firefox; и предназначен для прямого взаимодействия и управления DOM веб-страницы.

События, прослушиватели и селекторы

JavaScript поддерживает программирование, управляемое событиями. В этой парадигме события обнаруживаются и вызывают реакцию. Проще говоря, событие — это почти все, что пользователь может сделать для взаимодействия с веб-страницей — нажатие кнопки, перемещение курсора, загрузка страницы и т. д. Обнаружение выполняется с помощью прослушивателей событий, которые спокойно ждут определенных событий, готовых выполнить функцию при срабатывании.

Конкретные элементы веб-страницы могут быть выбраны из DOM с помощью функции выбора запросов JavaScript. Сохраняя возвращаемый элемент в переменной, можно управлять его содержимым. Комбинируя эти возможности — способность обнаруживать события и способность выбирать и воздействовать на элементы DOM, — мы можем создавать еще более интерактивные веб-сайты.

Больше, чем браузер…

В предыдущие недели мы в основном писали и тестировали наш код в текстовых редакторах и IDE. В этом отношении JavaScript снова работает по-другому: код пишется в текстовом редакторе, но выполняется в веб-браузере. Во время лекции мы обнаружили, что все современные браузеры имеют скрытую встроенную консоль для написания и тестирования небольших фрагментов кода и отладки наших приложений. Из-за отсутствия узнаваемой функции печати в JavaScript значения переменных можно записывать в консоль с помощью команды console.log.

Функции со стрелками

Хотя JavaScript довольно удобочитаем, его синтаксис для функций может быть немного менее интуитивным. В дополнение к традиционной нотации JavaScript дает нам возможность использовать стрелочную нотацию. В этом сокращенном синтаксисе за вводом в функцию следует типизированная стрелка (=>), за которой следует блок кода, который необходимо выполнить. Поскольку функции появляются повсюду в коде JavaScript, стрелочная нотация считается чище, чем стандартная нотация, позволяя определять функции всего в одной строке кода.

Локальное хранилище

Основным ограничением приложений, которые мы написали в предыдущие недели, было отсутствие их сохранения, т. е. перезагрузка наших браузеров сбрасывала наши веб-приложения в их базовое состояние как закодированное. В то время как базы данных дали нам возможность хранить данные (в широком смысле), лекция на этой неделе познакомила нас с концепцией локального хранилища — возможностью хранить информацию в веб-браузере пользователя в виде пар ключ-значение. Получить и установить значения в локальном хранилище так же просто, как вызвать функции localStorage.getItem и localStorage.setItem соответственно.

API

В будущих проектах мы можем захотеть создать веб-приложения, которые могут считывать и использовать информацию с других веб-сайтов, таких как Google Maps, BBC Weather или служба обмена валюты. Для этой цели многие веб-сайты предоставляют Интерфейс процесса приложения или API — документированный программный посредник, позволяющий двум приложениям разговаривать друг с другом. Конечно, для успешного взаимодействия наши два приложения должны иметь возможность говорить на одном языке, даже если они написаны на разных языках!

С этой целью мы познакомились с объектами JavaScript, простыми контейнерами для нескольких значений, выраженных в виде пар ключ-значение. Объекты JavaScript могут, в свою очередь, хранить другие объекты JavaScript, что позволяет создавать сложные, но единообразные и предсказуемые структурированные данные. При преобразовании в текстовый формат мы получаем JavaScript Object Notation (JSON) — вычислительный лингва-франка — обычно используемый при передаче данных через API.

2. Пользовательский интерфейс

Затем мы обратили внимание на улучшение пользовательских интерфейсов наших веб-сайтов (то есть на то, как посетители взаимодействуют с веб-страницей). В предыдущие недели наши веб-сайты были разделены на несколько страниц — страница для просмотра товаров для продажи, страница для покупки товара, страница для оформления заказа и так далее.

Благодаря использованию JavaScript мы получили возможность загружать одну веб-страницу и, манипулируя ее DOM, изменять определенные разделы страницы, оставляя другие нетронутыми. Простым примером этой парадигмы является нажатие на статическую панель навигации в верхней части страницы, при которой разное содержимое появляется и исчезает по мере необходимости, а не переходит на совершенно другую веб-страницу.

Конечно, было бы неэффективно загружать все содержимое веб-сайта, если в любой момент времени должна быть видна только его часть — например, Twitter загружает только несколько десятков твитов при загрузке, а не каждый твит, который когда-либо был опубликован! Чтобы устранить эту потенциальную неэффективность, мы можем воспользоваться преимуществами асинхронного JavaScript и XML (AJAX) для доступа к данным с сервера только по запросу, загружая данные на нашу веб-страницу без перезагрузки всей нашей HTML-страницы.

Окно

Одним из недостатков использования одностраничных веб-сайтов является то, что URL-адрес потенциально менее информативен, оставаясь статичным, когда мы переходим от просмотра к просмотру. Мы можем решить эту проблему с помощью JavaScript’s History API. С помощью этого API мы получаем возможность изменять URL-адрес веб-сайта без полного обновления страницы. Предоставив несколько простых аргументов функции history.pushState, мы можем изменить не только URL-адрес нашей страницы, но и перейти назад по нашему сеансу с помощью кнопки Назад в браузере.

Чтобы получить доступ к истории нашего браузера, мы используем объект JavaScript, известный как Window. В отличие от объекта документа, который представляет всю веб-страницу сайта, объект окна представляет то, что на экране видно пользователю прямо сейчас. С помощью окна мы можем определить ширину и высоту окна пользователя в пикселях (и сделать что-то с этими значениями), открыть окно, закрыть его, переместить, изменить размер, определить, как далеко пользователь прокрутил от верхней части экрана. страница и так далее.

Анимации

Еще один способ сделать наши веб-сайты визуально более интересными — использовать простую анимацию. В дополнение к стилизации наших веб-сайтов, CSS дает нам возможность анимировать HTML-элементы. Чтобы создать простую анимацию, мы просто определяем начальный и конечный стили, предваряя наш блок кода @keyframes NAME. После определения мы можем применить анимацию к определенному элементу, указав три параметра: имя нашей анимации; желаемая продолжительность нашей анимации, т. е. время перехода между ее начальным и конечным состояниями; и третье значение с довольно загадочным названием animation-fill-mode. Благодаря включению JavaScript мы можем управлять нашими творениями, например, запуская или приостанавливая анимацию одним нажатием кнопки.

Реакция

В предыдущие недели мы использовали Bootstrap, чтобы сократить количество написанного нами базового CSS, что позволило нам сосредоточиться на более важных вещах. В том же духе в этой лекции мы познакомились с React — популярным фреймворком JavaScript для пользовательских интерфейсов. В то время как большая часть нашего предыдущего программирования была императивной (т. е. мы даем компьютеру набор инструкций для выполнения), React позволяет нам использовать декларативное программирование, т. е. мы сообщаем компьютеру, что мы хотим дисплей, не беспокоясь о том, как он работает под капотом.

3: Проект 3 — Почта

Описание

Для четвертого задания курса Почта нам было поручено создать почтовый клиент, способный выполнять вызовы API для отправки, получения, чтения, составления, архивирования и разархивирования электронных писем. В дополнение к пересмотру некоторых концепций, описанных в предыдущих PSET, для выполнения задания требовалось широкое использование JavaScript.

Подход

В отличие от предыдущих PSET, большая часть внутреннего кода приложения была предоставлена ​​нам инструкторами курса, что позволило нам сосредоточиться на API веб-сайта и общем пользовательском интерфейсе.

Прежде чем реализовать отдельные функции приложения, я сначала занялся общей навигацией. Как было показано в предыдущей лекции, Mail должен был быть (в основном) одностраничным приложением, содержимое которого появлялось и исчезало из окна по мере необходимости. Получив возможность отображать различные представления веб-сайта (входящие, исходящие и т. д.), нажимая кнопки навигации в панели навигации приложения и обновляя свойство style.display соответствующих блоков кода, я перешел к бизнес-концу веб-сайта.

Как и в случае с предыдущими заданиями, я разбил приложение на составные части — просматривать электронные письма, составлять электронные письма и т. д. — и решать их одну за другой. Как я обещал в своей предыдущей записи в этой серии, я — наконец — укусил пулю и использовал Git для задания, создавая ветку для каждого компонента приложения и откатываясь к предыдущим коммитам, когда я не мог Ctrl-Z выйти из самовольный тупик! Хотя включение Git в мой проект создало еще более крутую кривую обучения, в конечном итоге это значительно облегчило мою работу, и я буду продолжать использовать его в будущих заданиях.

Очевидно, что для просмотра или архивирования электронных писем необходимо было иметь хотя бы одно из них в моей связанной базе данных. Поэтому я сначала взялся за функции составления и отправки приложения. Составление электронного письма было относительно тривиальным (простая веб-форма HTML и кнопка отправки), но его отправка была немного сложнее, требуя запроса JavaScript fetch() для POST JSON-кодированных данных на сервер через API приложения — проще говоря, загрузка электронной почты на базу данных. Чтобы убедиться, что мои электронные письма действительно отправляются, я записал в консоль вывод почти каждой строки связанного кода и проверил содержимое маршрута /emails/sent API моего приложения при отправке в поисках чего-либо, кроме пустой страницы.

Остальные функции приложения реализовать было несколько проще — по сути это варианты описанной выше функции отправки. Например, для получения электронных писем или отдельного электронного письма из базы данных использовался запрос API выборки GET. С данными, возвращаемыми в формате JSON, требовалось некоторое размышление, чтобы правильно проанализировать содержимое результатов — отделить электронную почту от электронной почты, поле данных от поля данных. Также немного неудобной была возможность пометить электронные письма как прочитанные / непрочитанные или заархивированные / разархивированные для правильной обработки, т. Е. Пользователь не должен был иметь возможность архивировать заархивированное электронное письмо или видеть отправленное электронное письмо в своем почтовом ящике. Для этого я устанавливаю флаги на отдельные электронные письма. На практике это означало присвоение соответствующих значений TRUE/FALSE полям в записи базы данных объекта с помощью метода PUT команды выборки… просто(!)

После того, как все заработало, как и ожидалось, я углубился в статическую папку приложения, чтобы сделать некоторые общие украшения: собственный логотип для веб-сайта, значок вкладки и некоторые общие стили CSS.

Проблемы и уроки

Для меня работа с Mail была сложной задачей по трем основным причинам:

  1. PSET одновременно представил несколько основных новых методов и концепций, включая API, JSON и JavaScript (совершенно новый язык!). Несколько отличаясь от других языков, которые широко читаются и выполняются сверху вниз, я немного боролся с последовательностью событий JavaScript. слушатели, особенно когда они вложены в другие слушатели событий. Я также столкнулся с командой fetch, пытаясь полностью понять, что на самом деле происходит на каждом этапе, ее непрозрачные обещания и странный .then синтаксис. В том же ключе: обозначение стрелки. Хотя, по-видимому, это более чистый способ выражения функций в JavaScript, они остаются, по крайней мере для меня, более трудными для чтения и более неуклюжими, чем обычная нотация.
  2. Поначалу было сложно как следует закрепиться на задании. Делать что-либо с электронной почтой (т. е. 90% функциональности приложения) необходимо, чтобы электронная почта сначала появилась в нашей базе данных. Успешное создание этого первого электронного письма (т. е. составление и «отправка» его в папку «Входящие») представляло собой крутую кривую обучения, требующую, чтобы многие из этих новых концепций были связаны вместе и выполнялись последовательно. Как только это было взломано, оставшаяся часть задания была относительно простой.
  3. Хотя полезно иметь часть кода приложения, предоставленного нам, мне часто проще начать с нуля, чем строить на коде, написанном другими. Однако в конечном итоге это был ценный опыт обучения — больше соответствующий реальному миру, где несколько человек могут одновременно работать над одним и тем же проектом, и хорошее напоминание о том, что нужно правильно читать и понимать, что делает чужой код. К разочарованию / юмору, при решении задания я все больше злился, когда нажимал кнопку архива в моих электронных письмах, чтобы удалить их (функция, которую я даже не написал!) И только позже, когда я реализовал представление архива, я обнаружил, что они не удалялись… они удалялись из моего почтового ящика и отправлялись в мою архивную папку… точно так, как указано; точно так, как написано в коде, предоставленном инструкторами. Короче — читайте документацию!

В целом работа с Mail была сложной, но ценной задачей, которая способствовала нашему пониманию многих основных концепций веб-программирования. Хотя было слегка разочаровывающим, что некоторые из техник, представленных в шестой лекции, не требовались для завершения (а именно анимация и React), создание приложения на совершенно новом языке, вероятно, было достаточно сложной задачей без дополнительных «приятных вещей». Кроме того, всегда есть следующий раз…

В следующих двух лекциях мы немного отступим от написания кода, чтобы изучить некоторые из современных передовых методов веб-разработки: тестирование, CI/CD, масштабируемость и безопасность. После этого наши финальные проекты! До .then