Excel in Javascript

35
Excel на JavaScript! Viktor Turskyi CTO at WebbyLab Kyiv.js 2013

description

General concepts of building spreadsheet engine

Transcript of Excel in Javascript

Page 1: Excel in Javascript

Excel на JavaScript!Viktor Turskyi

CTO at WebbyLab

Kyiv.js 2013

Page 2: Excel in Javascript

Бизнес задача

Запускать XLS файлы со сложными математическими моделями в браузере и чтобы без сервера

Page 3: Excel in Javascript
Page 4: Excel in Javascript

Требования к производительности:

1. Возможность запуска крупных моделей(до 2-х миллионов ячеек, 400тыс формул, 1млн Excel функций, 50 листов)

2. Поддержка цепей вычисления на сотни тысяч ячеек

3. Высокая производительность4. Небольшой размер файла

Page 5: Excel in Javascript
Page 6: Excel in Javascript

Требования к окружению

● Офлайн работа в браузере● Работа на сервере● Работа на планшетах(iOS, Android)

Page 7: Excel in Javascript
Page 8: Excel in Javascript

=IF($F$36 + $AF128 <= 101; SUMPRODUCT( ($S128:OFFSET($S128;$F$36-1;0)) * ($AG$55:OFFSET($AG$55;$F$36-1;0)) * ('Sheet25'!BY84:OFFSET('Sheet25'!BY84;$F$36-1;0) + 'Sheet25'!BY194:OFFSET('Sheet25'!BY194; $F$36-1; 0) ) ); SUMPRODUCT( ($S128:$S$155) * ($AG$55:OFFSET($AG$55;100-$AF128;0)) * ('Sheet25'!BY84:BY$111 + 'Sheet25'!BY194:BY$221) ) )

1. Дизайн интерфейса2. 12 мб xls файл c формулами вида:

От заказчика получили

Page 9: Excel in Javascript

Почему не Google Docs API:

1. Работает только в онлайн2. Очень медленный3. Проблемы при конвертации некоторых

xls 4. Максимум 40 тыс формул в файле

Page 10: Excel in Javascript

Вопрос №0: это возможно? :)

С помощью JavaScript все возможно ;)

Page 11: Excel in Javascript

Вопрос №1: Достаточно ли у JS производительности?

1. Определяем целевые платформы(движки)a. Браузеры и их версииb. iOS устройстваc. Android устройства

2. Пишем синтетический мини бенчмаркa. Математический вычисленияb. Длинные цепи вычислений

Page 12: Excel in Javascript
Page 13: Excel in Javascript

Вопрос №2: Как вычитать данные с XLS файла?

● Необходимо вычитать значения● Необходимо вычитать формулы● Необходимо вычитать называние

листов● Необходимо вычитать имена

диапазонов и ячеек

Page 14: Excel in Javascript

Варианты:

● Nodejs модули - не способны даже вычитать значения, сваливаются на огромных файлах.

● Ruby/Python/Perl/PHP - нет возможности получить формулы или имена ячеек

Page 15: Excel in Javascript

Что сработало?

Perl (100 строк) + Windows + Win32::OLE + Excel + документация VBA = тупой дамп в JSON сырых данных.

Page 16: Excel in Javascript

Вопрос №3: Вычитали и что?

1. Нужно разобрать гору сырых данных2. Нужно проанализировать все формулы3. Нужно отслеживать завимости между

формулами4. Нужно это как-то хранить5. Нужно реализовать множество функций

c Excel6. Нужен движок, который все выполнит

Page 17: Excel in Javascript
Page 18: Excel in Javascript

Вопрос №4: Как разобрать формулу в JS?

1. Учет приоритета операторов2. Инфиксные/префиксные операторы3. Функции4. Ссылки на ячейки5. Ссылки на диапазоны6. Именованные адреса

Page 19: Excel in Javascript

Неправильное решение

Самописный лексер и парсер:1. Сложно2. Долго3. Дорого

Отказались с первыми существенными проблемами приоритета операторов.

Page 20: Excel in Javascript

Правильное решение - ANTLR

1. Генератор парсеров (включая JS)2. Лексический и синтаксический анализ3. На выходе AST (Abstract Syntax Tree) 4. Лучшее из всего, что есть под JS (и не

только)Мы используем версию 3.3 (в версии 3.4 баг в JS генераторе)

http://www.antlr.org/

Page 21: Excel in Javascript

Примеры формул

Formula: '=1+2*3'JS AST: [ '+', 1, [ '*', 2, 3] ]

Formula: '=A1+B1'JS AST: [‘+’, ['=', 0, 0, 0], ['=', 0, 1, 0] ]

Formula: ‘=SUM(B5:B100, 42)'JS AST: [ 'SUM', [ 'RANGE', 0, 1, 4, 1, 99 ], 42 ]

Page 22: Excel in Javascript

Компоненты движка

● LocalRunner - работает с файлом и определяет порядок вычислений

● Formula Evaluator - вычисляет формулу● Address Parser - парсит адреса

введенные пользователем● Functions - реализация Excel функций

Page 23: Excel in Javascript

Реализация EXCEL функций

● Одна функция - один класс● Все функции без побочных эффектов ● Используется принцип внедрения

завимостей для подключения● node-qunit для тестирования

Пример вызова: SQRT([ 9 ]) вернет 3SUM([2, [5, 6, 7, 9], 1 ]) вернет 30

Page 24: Excel in Javascript

Вопрос №5: зависимости ячеек

A1=1A2=A1+1A3=A1+A2

Ячейка А1 влияет на A2 и A3 Ячейка A2 влияет на А3

Page 25: Excel in Javascript

Что представляют собой зависимости?

По сути, мы имеемнаправленныйациклическийграф

(храним в JSONвместе с AST)

Page 26: Excel in Javascript

При изменении ячейки пересчитывать зависимые

На тестовых файлах работает, а в реальной жизни - нет.

Причина - множественные пересчеты однихи тех же ячеек.

Page 27: Excel in Javascript

Топологическая сортировка

Позволяет нам вычислять ячейку один раз.

На тестовых файлах работает, в реальной жизни - нет.

Причина - переполнение стека вызовов.

Page 28: Excel in Javascript

Что делать?

Не используйте рекурсию, сами управляйте стеком и обходите граф.

Результат на реальной модели:Без сортировки - 1часС сортировкой - 6 секунд

Page 29: Excel in Javascript

Как работать с диапазонами ячеек?

SUM( [ [ 21, 22, 23, 31, 32, 33 ] ] );SUM( [ new ArrayRange([21, 22, 23, 31, 32, 33]) ] );SUM( [ new ModelRange(model, ‘B2:C4’ ) ] );

Page 30: Excel in Javascript

Оптимизация

Обращайте внимание на:1. Рекурсивные алгоритмы2. Большие JSON файлы(40мб повалит

ваш браузер)3. Лимиты по помяти в NodeJS (иногда

невозможно обойти)4. Копирования данных в памяти

Page 31: Excel in Javascript

Инструменты

1. ANTLR для синтаксического анализа2. Web Workers для повышения

отзывчивости интерфейса3. Browserify для использования

CommonJS модулей в браузере4. Qunit для тестирования

Page 32: Excel in Javascript

Поддержка разных окружений

Для сервера - nodejsДля браузера - browserifyДля планшетов - phonegap

Page 33: Excel in Javascript

Живая демонстрация

Page 34: Excel in Javascript

Viktor [email protected]

http://koorchik.blogspot.comhttp://search.cpan.org/~koorchik/

https://github.com/koorchik

WebbyLabhttp://webbylab.com

Page 35: Excel in Javascript

WebbyLabищет

Junior Frontend Developer

http://www.work.ua/jobs/1433919/