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.7k
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
『実践MLOps』から学ぶ DevOps for ML
nsakki55
2
470
How Software Deployment tools have changed in the past 20 years
geshan
0
9.6k
Flutterアプリ運用の現場で役立った監視Tips 5選
ostk0069
1
520
手軽に積ん読を増やすには?/読みたい本と付き合うには?
o0h
PRO
1
110
分散DBって何者なんだ... Spannerから学ぶRDBとの違い
iwashi623
0
110
乱雑なコードの整理から学ぶ設計の初歩
masuda220
PRO
32
15k
AIの弱点、やっぱりプログラミングは人間が(も)勉強しよう / YAPC AI and Programming
kishida
13
5.4k
2025 컴포즈 마법사
jisungbin
0
150
Evolving NEWT’s TypeScript Backend for the AI-Driven Era
xpromx
0
190
高単価案件で働くための心構え
nullnull
0
160
ゼロダウンタイムでミドルウェアの バージョンアップを実現した手法と課題
wind111
0
220
イベントストーミングのはじめかた / Getting Started with Event Storming
nrslib
1
730
Featured
See All Featured
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
132
19k
Docker and Python
trallard
46
3.7k
How to train your dragon (web standard)
notwaldorf
97
6.4k
Side Projects
sachag
455
43k
The World Runs on Bad Software
bkeepers
PRO
72
12k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
140
34k
Making the Leap to Tech Lead
cromwellryan
135
9.6k
For a Future-Friendly Web
brad_frost
180
10k
We Have a Design System, Now What?
morganepeng
54
7.9k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.6k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
34
2.3k
Why Our Code Smells
bkeepers
PRO
340
57k
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>