О насБлогКонтакты
Технологии12 мая 1999 г. 6 мин 127Обновлено: 22 июня 2026 г.

Java-апплеты в казнете 1999 года: когда интерактивность стоила минут загрузки

AunimedaAunimeda
📋 Содержание

1999 год. Алматы. Типичное рабочее подключение к интернету - dial-up через модем на 33 кбит/с. Веб-страница с тремя-четырьмя картинками грузится 15-20 секунд. Скачать 200-килобайтный JAR-файл с апплетом - ещё минута сверху, плюс время на инициализацию JVM в браузере.

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


JDK 1.1 и AWT: основа апплетов 1999 года

// CurrencyTickerApplet.java - бегущая строка с курсами валют
// JDK 1.1, AWT, 1999 год
// Актуальное применение для казахстанских финансовых сайтов

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;

public class CurrencyTickerApplet extends Applet implements Runnable {

    // Данные из <param> тегов в HTML - курсы передавались вручную
    private String tickerText  = "USD/KZT 130.00  EUR/KZT 138.50  RUB/KZT 5.80";
    private int    scrollSpeed = 2;
    private Color  bgColor     = Color.black;
    private Color  textColor   = new Color(255, 215, 0);  // золотой - стиль финансового сайта

    private Thread animThread;
    private int    xPosition;
    private Font   tickerFont;
    private int    textWidth;

    @Override
    public void init() {
        String p = getParameter("rates");
        if (p != null) tickerText = p;

        String s = getParameter("speed");
        if (s != null) scrollSpeed = Integer.parseInt(s);

        tickerFont = new Font("Monospaced", Font.BOLD, 13);
        setBackground(bgColor);

        FontMetrics fm = getFontMetrics(tickerFont);
        textWidth = fm.stringWidth(tickerText);
        xPosition = getSize().width;
    }

    @Override
    public void start() {
        if (animThread == null || !animThread.isAlive()) {
            animThread = new Thread(this);
            animThread.start();
        }
    }

    @Override
    public void stop() {
        animThread = null;
    }

    @Override
    public void run() {
        while (Thread.currentThread() == animThread) {
            xPosition -= scrollSpeed;
            if (xPosition < -textWidth) xPosition = getSize().width;
            repaint();
            try { Thread.sleep(40); } catch (InterruptedException e) { break; }
        }
    }

    @Override
    public void paint(Graphics g) {
        g.setFont(tickerFont);
        g.setColor(textColor);
        g.drawString(tickerText, xPosition, getSize().height / 2 + 5);
    }

    // Двойная буферизация - без этого в AWT 1999 мерцало нещадно
    private Image    buf;
    private Graphics bufG;

    @Override
    public void update(Graphics g) {
        Dimension d = getSize();
        if (buf == null) {
            buf  = createImage(d.width, d.height);
            bufG = buf.getGraphics();
        }
        bufG.setColor(bgColor);
        bufG.fillRect(0, 0, d.width, d.height);
        paint(bufG);
        g.drawImage(buf, 0, 0, this);
    }
}

Компиляция и упаковка:

# JDK 1.1 на Windows 98 (стандартная рабочая машина разработчика в Алматы 1999)
# JDK скачивали с java.sun.com, размер ~10 МБ - несколько часов по dial-up

javac CurrencyTickerApplet.java
jar cvf currency.jar CurrencyTickerApplet.class

HTML-страница:

<!-- Курсы валют для казахстанского банковского сайта, 1999 год -->
<applet code="CurrencyTickerApplet.class"
        archive="currency.jar"
        width="480"
        height="28"
        alt="Требуется Java">
  <param name="rates" value="USD/KZT 130.00  EUR/KZT 138.50  RUB/KZT 5.80">
  <param name="speed" value="2">
  <p><b>Ваш браузер не поддерживает Java.</b>
  Курсы: USD 130.00, EUR 138.50, RUB 5.80</p>
</applet>

Интерактивная карта офиса

Другое применение апплетов, популярное в казнете 1999-2000 годов - интерактивная карта с кликабельными районами:

// OfficeMapApplet.java - кликабельная карта с районами Алматы
// Наведи на район - подсветка; кликни - переход на страницу

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.net.*;

public class OfficeMapApplet extends Applet
        implements MouseListener, MouseMotionListener {

    private Image mapImage;
    private int   hoveredRegion = -1;

    // Прямоугольные области районов (x, y, ширина, высота)
    private int[][] regions = {
        {20,  30, 80, 60},   // Алмалинский район
        {110, 30, 80, 60},   // Бостандыкский район
        {200, 30, 80, 60},   // Медеуский район
    };

    private String[] regionNames = {
        "Алмалинский", "Бостандыкский", "Медеуский"
    };

    private String[] regionURLs = {
        "almaly.html", "bostandyk.html", "medeu.html"
    };

    @Override
    public void init() {
        mapImage = getImage(getCodeBase(), getParameter("map"));
        addMouseListener(this);
        addMouseMotionListener(this);
        setBackground(Color.white);
    }

    @Override
    public void paint(Graphics g) {
        if (mapImage != null) {
            g.drawImage(mapImage, 0, 0, this);
        }

        for (int i = 0; i < regions.length; i++) {
            if (i == hoveredRegion) {
                // Полупрозрачная подсветка через XOR
                g.setXORMode(new Color(255, 255, 0));
                g.fillRect(regions[i][0], regions[i][1],
                           regions[i][2], regions[i][3]);
                g.setPaintMode();

                // Название региона
                g.setColor(Color.black);
                g.setFont(new Font("SansSerif", Font.BOLD, 11));
                g.drawString(regionNames[i],
                             regions[i][0] + 4, regions[i][1] + 14);
            }
        }
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        int clicked = getRegionAt(e.getX(), e.getY());
        if (clicked >= 0) {
            try {
                getAppletContext().showDocument(
                    new URL(getDocumentBase(), regionURLs[clicked]),
                    "_self"
                );
            } catch (MalformedURLException ex) {
                showStatus("Ошибка перехода: " + ex.getMessage());
            }
        }
    }

    @Override
    public void mouseMoved(MouseEvent e) {
        int region = getRegionAt(e.getX(), e.getY());
        if (region != hoveredRegion) {
            hoveredRegion = region;
            repaint();
            if (region >= 0) {
                showStatus("Район: " + regionNames[region]);
            } else {
                showStatus("");
            }
        }
    }

    private int getRegionAt(int x, int y) {
        for (int i = 0; i < regions.length; i++) {
            if (x >= regions[i][0] && x <= regions[i][0] + regions[i][2] &&
                y >= regions[i][1] && y <= regions[i][1] + regions[i][3]) {
                return i;
            }
        }
        return -1;
    }

    @Override public void mousePressed(MouseEvent e)  {}
    @Override public void mouseReleased(MouseEvent e) {}
    @Override public void mouseEntered(MouseEvent e)  {}
    @Override public void mouseExited(MouseEvent e)   { hoveredRegion = -1; repaint(); }
    @Override public void mouseDragged(MouseEvent e)  {}
}

Реальность: загрузка и совместимость в казнете

В 1999 году типичный пользователь в Алматы работал с:

Параметр Значение
Соединение Dial-up 28-33 кбит/с
Браузер IE 4/5 или Netscape 4
RAM 32-64 МБ
JVM Microsoft JVM (в IE) или Sun JVM (в Netscape)

Проблема с двумя JVM была реальной:

// Microsoft JVM (IE4/5) и Sun JVM (Netscape) отличались:
// - Microsoft JVM не поддерживал полный RMI
// - Поведение java.net.URL различалось
// - Thread.sleep() иногда давала неверные результаты в MS JVM
// Решение: тестировать в обоих браузерах, избегать продвинутых API

// Детект JVM в JavaScript для выбора фолбэка:
var isIE = (navigator.appName === "Microsoft Internet Explorer");
// Если IE - убедиться что Microsoft JVM установлен
// Если Netscape - проверить наличие плагина Sun JVM

Размер JAR-файла напрямую влиял на конверсию в казнете:

  • 50 КБ JAR - 12-15 секунд загрузки @ 33 кбит/с - приемлемо
  • 200 КБ JAR - 50-60 секунд - пользователи уходили
  • 500 КБ JAR - 2 минуты+ - никто не ждал

Мы оптимизировали агрессивно: убирали все неиспользуемые классы, сжимали изображения максимально, разбивали апплет на несколько JAR с ленивой загрузкой второстепенных.


Flash выиграл: почему это было неизбежно

К 2000 году Macromedia Flash 4 стал доминировать в нише «интерактивный веб» по нескольким причинам, критично важным именно для казнета:

Меньше размер файлов. Flash-ролик в 20 КБ против JAR в 100 КБ при одинаковом визуальном результате. На slow dial-up это было решающим.

Плагин шёл вместе с браузером. Netscape 4 и IE 5 поставлялись с Flash-плагином предустановленным. JVM нужно было скачивать и устанавливать отдельно - 10 МБ по dial-up, несколько часов.

Инструменты для дизайнеров. Флеш-анимацию мог создать дизайнер без знания Java. В Алматы 1999 года программистов, знавших Java, было очень мало. Дизайнеров со знанием Flash - существенно больше.

Java-апплеты в казнете ушли к 2001-2002 году, не успев стать массовой технологией. Но те, кто писал апплеты в 1999-м, получил бесценный опыт - событийное программирование, работа с потоками, двойная буферизация. Этот опыт напрямую конвертировался в Android-разработку, начавшуюся в 2008 году.

Читайте также

Казнет в 2002: первые корпоративные сайты Казахстана - IE5, Netscape и dial-up реалииaunimeda
Технологии

Казнет в 2002: первые корпоративные сайты Казахстана - IE5, Netscape и dial-up реалии

В 2002 году казахстанский интернет насчитывал около 200 тысяч пользователей. Иметь корпоративный сайт - было признаком солидности. Сделать его - означало работать с IE5, Netscape 4, кодировкой windows-1251 и картинками не тяжелее 15 КБ. Вот как это было.

DHTML-меню в казнете 2001 года: выпадающая навигация без перезагрузкиaunimeda
Технологии

DHTML-меню в казнете 2001 года: выпадающая навигация без перезагрузки

В 2001 году выпадающее DHTML-меню было признаком профессионального сайта. Казахстанские веб-студии Алматы осваивали JavaScript + CSS для создания навигации без Flash и без перезагрузки страницы. Полный код, решение проблемы z-index в IE5, и почему 300 мс - магическое число.

Classic ASP и первые системы авторизации в казнете (2000)aunimeda
Технологии

Classic ASP и первые системы авторизации в казнете (2000)

В 2000 году корпоративные сайты Казахстана переходили от статического HTML к динамическим приложениям. Компании, работавшие с Windows-серверами, выбирали ASP. Первая задача - система входа с сессиями и SQL Server. Полный код и реалии разработки в Алматы 2000 года.

Нужна IT-разработка для вашего бизнеса?

Разрабатываем сайты, мобильные приложения и AI-решения для бизнеса в Казахстане. Бесплатная консультация.

Получить консультацию Все статьи