Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Next Mobile WebApplication
Search
uupaa
December 02, 2013
Programming
13
6.4k
Next Mobile WebApplication
このスライドは
2013-11-30 に開催された HTML5 Conference 2013 で
地下鉄・サクサク・これからのWebゲームアプリが備えるべき8つの機能
としてお話したものです
uupaa
December 02, 2013
Tweet
Share
Other Decks in Programming
See All in Programming
The future of development – Are our jobs getting harder or easier?
hollycummins
1
240
WEBエンジニア向けAI活用入門
sutetotanuki
0
270
Amazon Neptuneで始めてみるグラフDB-OpenSearchによるグラフの全文検索-
satoshi256kbyte
4
290
生成 AI を活用した toitta 切片分類機能の裏側 / Inside toitta's AI-Based Factoid Clustering
pokutuna
0
510
詳細解説! ArrayListの仕組みと実装
yujisoftware
0
400
Kubernetes for Data Engineers: Building Scalable, Reliable Data Pipelines
sucitw
1
170
Go言語でターミナルフレンドリーなAIコマンド、afaを作った/fukuokago20_afa
monochromegane
2
130
シールドクラスをはじめよう / Getting Started with Sealed Classes
mackey0225
2
320
Kotlinの好きなところ
kobaken0029
0
170
Nuxt UI Pro、NuxtHub、Nuxt Scripts、Nuxtエコシステムをふんだんに利用して開発するコーポレートサイト@Vue Fes Japan 2024
shingangan
3
810
Synchronizationを支える技術
s_shimotori
1
140
レガシーな Android アプリのリアーキテクチャ戦略
oidy
1
160
Featured
See All Featured
Build The Right Thing And Hit Your Dates
maggiecrowley
32
2.4k
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
Fontdeck: Realign not Redesign
paulrobertlloyd
81
5.2k
Building Better People: How to give real-time feedback that sticks.
wjessup
363
19k
Art, The Web, and Tiny UX
lynnandtonic
296
20k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
225
22k
Git: the NoSQL Database
bkeepers
PRO
425
64k
Product Roadmaps are Hard
iamctodd
PRO
48
10k
Why You Should Never Use an ORM
jnunemaker
PRO
53
9k
Making Projects Easy
brettharned
115
5.9k
Testing 201, or: Great Expectations
jmmastey
38
7k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
167
49k
Transcript
Next Mobile WebApplication uupaa 2013-11-30
Me @uupaa - 2012 join R&D App
2013-11-30 HTML5 Conference 2013 Web 8
WebApp ? WebApp WebApp, Browser Game, SinglePageApplication, ES6, Storage, Cache,
Audio, Canvas, WebWorker
NativeApp vs WebApp NativeApp WebApp ? 3D
WebApp
Single Page Application (SPA) SPA ? 1 WebApp
SPA (BGM) WebApp 800ms -> 200ms
SPA
Audio/WebAudio Audio <audio> BGM BGM SE Android <audio>
WebAudio WebAudio m4a(AAC) WebAudio <audio> SoundSprite
WebAudio ( ) (input) ( ) ( ) (JavaScript )
+-------+ +-------+ +-------+ +-------+ +-------+ | SE[0] | | SE[1]
| | SE[n] | | BGM-A | | BGM-B | BufferSource <<AudioBuffer>> +---+---+ +---+---+ +---+---+ +---+---+ +---+---+ | | | | | | | | +----+---+ +---+----+ | | | | FADE-A | | FADE-B | BGM CrossFade <<Gain>> | | | +----+---+ +---+----+ +---------+---------+ +----+----+ | | +----+---+ +--+---+ | EFFECT | | LOOP | Effect/Loop Volume <<Gain>> +----+---+ +--+---+ +-------------+------------+ +---+---+ | MUTE | Mute <<Gain>> +---+---+ +------+------+ | Compressor | <<DynamicsCompressor>> +------+------+ +------+------+ | Distination | AudioContext.Distination +-------------+
var ctx = new global.AudioContext(); var node = { compressor:
null, fade: [null,null], // CrossFade volume master: null, // master volume effect: null, // effect volume loop: null, // loop volume mute: null // mute }; node.compressor = ctx.createDynamicsCompressor(); node.mute = ctx.createGainNode(); node.master = ctx.createGainNode(); node.effect = ctx.createGainNode(); node.loop = ctx.createGainNode(); node.fade[0] = ctx.createGainNode(); node.fade[1] = ctx.createGainNode(); node.fade[0].connect(node.loop); node.fade[1].connect(node.loop); node.effect.connect(node.master); node.loop.connect(node.master); node.master.connect(node.mute); node.mute.connect(node.compressor); node.compressor.connect(ctx.destination);
( MIDI)
WebAudio Web SE BGM OFF ON/OFF Android DualCore, 1GB RAM
iOS iOS 7, iPhone 4S (iOS 6 ) Chrome for Android 31 http://hello.uupaa.net/issues/2/ HE-AAC
( )
Canvas 65 70% 200dpi (in Google Play) $179 (Moto G)
326dpi
Canvas CanvasRenderingContext2D#toDataURL 96dpi (ImageData) High Definition toDataURLHD toBlobHD createImageDataHD getImageDataHD
putImageDataHD
2013 ImageData Width x Height Canvas ImageData Device 480 x
320 600 KB iPhone (2007) 960 x 640 2.3 MB iPhone Retina (2010) 2048 x 1536 12 MB iPad Retina (2012) ImageData Pixel x 4byte(RGBA)
2015 ImageData 2015 4K Width x Height Canvas ImageData Device
960 x 640 2.3 MB iPhone Retina (2010) 2048 x 1536 12 MB iPad Retina (2012) 2560 x 1440 14 MB 2K Android (maybe 2014) 3840 x 2160 31.6 MB 4K Android (maybe 2015)
ImageData ImageData MB 16ms … for
? WebWorker
WebWorker Canvas ? ? Canvas canvas.transferControlToProxy canvasProxy.setContext context.commit
CanvasProxy (1 ) <canvas></canvas> // index.js var canvas = document.querySelector("canvas");
var canvasProxy = canvas.transferControlToProxy(); // CanvasProxy を取得 var canvasWorker = new Worker("BackgroundCanvasRender.js"); canvasWorker.postMessage(canvasProxy, [canvasProxy]); // Worker に渡す // BackgroundCanvasRender.js onmessage = function(event) { var context = new CanvasRenderingContext2D(); var canvasProxy = event.data; canvasProxy.setContext(context); // bind setInterval(function() { context.clearRect(0, 0, context.width, context.height); context.fillText(new Date() + "", 0, 100); context.commit(); // render }, 1000); };
? 100 150MB GC window.gc() <img> <video> <svg> Worker Canvas
drawImage …
High Definition CanvasProxy + WebWorker
Command Pattern ( )
Canvas API // before ctx.fillStyle = "#fff"; ctx.fillRect(0, 0, 100,
100); // after var canvasCommands = [ ["fillStyle", "#fff"], ["fillRect", 0, 0, 100, 100] ]; for (var i = 0, iz = canvasCommands.length; i < iz; ++i) { switch (canvasCommands[i]) { case "fillStyle": ... break; case "fillRect": ... break; } });
: Android ( ) , ,
( ) Android Browser, Chrome for Android ( )
DrawCall ( ) Canvas API DrawCall DrawCall // before function
drawCall1() { ctx.fillRect(...); } function drawCall2() { ctx.fillRect(...); } drawCall1(); heavyRoutine(); drawCall2(); Chrome Canvas profiler DrawCall CanvasAPI
+ SnapShot, Movie
+ Remote Play DOM, CSS, Audio, Canvas App
+ WebWorker WebWorker postMessage // index.js var worker = new
Worker("Worker.js"); var request = []; worker.onmessage = function(event) { var response = event.data.response; : }; worker.postMessage({ request: request }); // Worker.js onmessage = function(event) { var request = event.data.request; postMessage({ response: ["ok"], error: null }); };
( )
WebWorker
WebApp WebWorker ? , , , ,
WebWorker JavaScript ?
WebWorker ( )
importScripts navigator.userAgent, onLine JSON, BLOB, FileReader, FileReaderSync Timer - setTimeout(),
setInterval() encodeURIComponent/decodeURIComponent TypedArray MessageChannel WebSQL, WebSQLSync WebSocket, XMLHttpRequest
navigator.webkitPersistentStorage navigator.webkitTemporaryStorage HighPerformanceTimer - performance.now() TextEncoder/TextDecoder Crypto, Base64(atob, btoa) ImageBitmap
IndexedDB WorkerConsole - console.log() RequestFileSystem, RequestFileSystemSync ES6( Symbol, Set, Map, WeakMap, WeakSet, Promise )
postMessage ? Nexus 7(2012) Chrome 0.6ms, Mac Chrome 0.02ms var
worker = new Worker("worker.js"); var score = 0; worker.onmessage = function(event) { worker.postMessage(++score); }; setTimeout(function() { worker.postMessage("stop"); }, 10 * 1000); // worker.js var payload = []; var timerID = setInterval(function() { postMessage(payload); }, 1); onmessage = function(event) { event.data === "stop" && clearInterval(timerID); };
postMessage Structured Cloning var payload = new Array(big number); postMessage(payload);
1MB (payload) 32MB payload 25% var MB = 1024 * 1024; var payload = new Uint8ClampedArray( 1 * MB); // 無負荷時の 98% の速度で動作 var payload = new Uint8ClampedArray( 8 * MB); // 無負荷時の 90% の速度で動作 var payload = new Uint8ClampedArray(32 * MB); // 無負荷時の 25% の速度で動作 Structured Cloning
Transferable Objects postMessage (zero-copy) Transferable Objects var payload = new
Array(big number); postMessage(payload, [payload]); Transferable Objects
WebWorker importScript JavaScript Prototype WebWorker
+ Module Node.js, Browser, WebWorker (function(global) { // --- define
---------------------------------------------- // --- variable -------------------------------------------- // --- interface ------------------------------------------- function Class() { } // --- implement ------------------------------------------- // --- export ---------------------------------------------- if (global.process) { module.exports = Class; } global.Class = Class; })(this.self || global); : Typical JavaScript Module Pattern
WebWorker ? iframe
WebWorker
Storage, Cache, Offline Storage LocalStorage 5MB … WebSQL 50MB ApplicationCache
LocalStorage + WebSQL Base64 DataURI <img>
Asset Manifest 304 Not Modified HTTP 1 (SPDY ) 5MB
+ 5MB
Asset Manifes Sample ID URL MimeType Hash (MD5, SHA1 )
, { "HelloAssetManifest": { "url": "asset/scene/Hello.js", "hash": "fd2b04", "mime": "scene/class", "size": 1425, "prime": 1 } }
Storage Indexed DB + Disk Quota Management API 10% ServiceWorker
URL …
… デモ 1 30MB (140kB jpg x 210 ) Base64
1 40 50MB 13 (600 800MB)
SinglePageApplication WebSQL LocalStorage Asset Manifest iframe Base64 Doubler 1 (Bulk
Download)
Doubler Base64 ASCII SQLite(LocalStorage WebSQL ) UTF16 Doubler NULL, BOM,
UTF16 Base64 200 250%
Doubler Code Point // Doubler.js: UTF16 Safe packer // Mobile
Browser unavailable UTF16 words: // Safari: NULL, BOM // Chrome: NULL, BOM, SurrogatePairs // Android: NULL // // Desktop Browser unavailable UTF16 words: // Safari: NULL, BOM // Chrome: NULL, BOM, SurrogatePairs // // +- UINT16 -+- Doubler.pack() -+- unpack -+ // | 0x0000 | 0x0020, 0x8000 | -0x8000 | encode NULL // +----------+------------------+----------+ // | 0x0020 | 0x0020, 0x8020 | -0x8000 | encode 0x20 // +----------+------------------+----------+ // | 0xd800 | 0x0020, 0x5800 | +0x8000 | encode SurrogatePairs // | : | : | | // | 0xdfff | 0x0020, 0x5fff | | // +----------+------------------+----------+ // | 0xfffe | 0x0020, 0x7ffe | +0x8000 | encode BOM // | 0xffff | 0x0020, 0x7fff | | // +-- Tail --+- Doubler.pack() -+----------+ // | 0x00 | 0x0020, 0x9000 | -0x9000 | encode Tail byte // | : | : | | // | 0xff | 0x0020, 0x90ff | | // +----------+------------------+----------+
Bulk Download GIF AssetSprite 1 ? (SPDY )
</thank-you>