| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 // Patch file for the dart:async library. | 5 // Patch file for the dart:async library. |
| 6 | 6 |
| 7 import 'dart:_js_helper' show Primitives, convertDartClosureToJS; | 7 import 'dart:_js_helper' show |
| 8 import 'dart:_isolate_helper' show | 8 Primitives, |
| 9 IsolateNatives, | 9 convertDartClosureToJS, |
| 10 TimerImpl, | 10 loadDeferredLibrary; |
| 11 leaveJsAsync, | 11 import 'dart:_isolate_helper' show TimerImpl; |
| 12 enterJsAsync, | |
| 13 isWorker; | |
| 14 | 12 |
| 15 import 'dart:_foreign_helper' show JS; | 13 import 'dart:_foreign_helper' show JS; |
| 16 | 14 |
| 17 patch Timer _createTimer(Duration duration, void callback()) { | 15 patch Timer _createTimer(Duration duration, void callback()) { |
| 18 int milliseconds = duration.inMilliseconds; | 16 int milliseconds = duration.inMilliseconds; |
| 19 if (milliseconds < 0) milliseconds = 0; | 17 if (milliseconds < 0) milliseconds = 0; |
| 20 return new TimerImpl(milliseconds, callback); | 18 return new TimerImpl(milliseconds, callback); |
| 21 } | 19 } |
| 22 | 20 |
| 23 patch Timer _createPeriodicTimer(Duration duration, | 21 patch Timer _createPeriodicTimer(Duration duration, |
| 24 void callback(Timer timer)) { | 22 void callback(Timer timer)) { |
| 25 int milliseconds = duration.inMilliseconds; | 23 int milliseconds = duration.inMilliseconds; |
| 26 if (milliseconds < 0) milliseconds = 0; | 24 if (milliseconds < 0) milliseconds = 0; |
| 27 return new TimerImpl.periodic(milliseconds, callback); | 25 return new TimerImpl.periodic(milliseconds, callback); |
| 28 } | 26 } |
| 29 | 27 |
| 30 patch class _AsyncRun { | 28 patch class _AsyncRun { |
| 31 patch static void _scheduleImmediate(void callback()) { | 29 patch static void _scheduleImmediate(void callback()) { |
| 32 // TODO(9002): don't use the Timer to enqueue the immediate callback. | 30 // TODO(9002): don't use the Timer to enqueue the immediate callback. |
| 33 _createTimer(Duration.ZERO, callback); | 31 _createTimer(Duration.ZERO, callback); |
| 34 } | 32 } |
| 35 } | 33 } |
| 36 | 34 |
| 37 patch class DeferredLibrary { | 35 patch class DeferredLibrary { |
| 38 patch Future<bool> load() { | 36 patch Future<bool> load() { |
| 39 List hunkNames = new List(); | 37 return loadDeferredLibrary(libraryName, uri); |
| 40 if (JS('bool', '\$.libraries_to_load[#] === undefined', libraryName)) { | |
| 41 return new Future(() => false); | |
| 42 } | |
| 43 for (int index = 0; | |
| 44 index < JS('int', '\$.libraries_to_load[#].length', libraryName); | |
| 45 ++index) { | |
| 46 hunkNames.add(JS('String', '\$.libraries_to_load[#][#]', | |
| 47 libraryName, index)); | |
| 48 } | |
| 49 Iterable<Future<bool>> allLoads = | |
| 50 hunkNames.map((hunkName) => _load(hunkName, uri)); | |
| 51 return Future.wait(allLoads).then((results) { | |
| 52 return results.any((x) => x); | |
| 53 }); | |
| 54 } | 38 } |
| 55 } | 39 } |
| 56 | 40 |
| 57 // TODO(ahe): This should not only apply to this isolate. | |
| 58 final Map<String, Future<bool>> _loadedLibraries = <String, Future<bool>>{}; | |
| 59 | |
| 60 Future<bool> _load(String hunkName, String uri) { | |
| 61 // TODO(ahe): Validate libraryName. Kasper points out that you want | |
| 62 // to be able to experiment with the effect of toggling @DeferLoad, | |
| 63 // so perhaps we should silently ignore "bad" library names. | |
| 64 Future<bool> future = _loadedLibraries[hunkName]; | |
| 65 if (future != null) { | |
| 66 return future.then((_) => false); | |
| 67 } | |
| 68 | |
| 69 if (uri == null) { | |
| 70 uri = IsolateNatives.thisScript; | |
| 71 } | |
| 72 int index = uri.lastIndexOf('/'); | |
| 73 uri = '${uri.substring(0, index + 1)}$hunkName'; | |
| 74 | |
| 75 if (Primitives.isJsshell || Primitives.isD8) { | |
| 76 // TODO(ahe): Move this code to a JavaScript command helper script that is | |
| 77 // not included in generated output. | |
| 78 return _loadedLibraries[hunkName] = new Future<bool>(() { | |
| 79 try { | |
| 80 // Create a new function to avoid getting access to current function | |
| 81 // context. | |
| 82 JS('void', '(new Function(#))()', 'load("$uri")'); | |
| 83 } catch (error, stackTrace) { | |
| 84 throw new DeferredLoadException("Loading $uri failed."); | |
| 85 } | |
| 86 return true; | |
| 87 }); | |
| 88 } else if (isWorker()) { | |
| 89 // We are in a web worker. Load the code with an XMLHttpRequest. | |
| 90 return _loadedLibraries[hunkName] = new Future<bool>(() { | |
| 91 Completer completer = new Completer<bool>(); | |
| 92 enterJsAsync(); | |
| 93 Future<bool> leavingFuture = completer.future.whenComplete(() { | |
| 94 leaveJsAsync(); | |
| 95 }); | |
| 96 | |
| 97 int index = uri.lastIndexOf('/'); | |
| 98 uri = '${uri.substring(0, index + 1)}$hunkName'; | |
| 99 var xhr = JS('dynamic', 'new XMLHttpRequest()'); | |
| 100 JS('void', '#.open("GET", #)', xhr, uri); | |
| 101 JS('void', '#.addEventListener("load", #, false)', | |
| 102 xhr, convertDartClosureToJS((event) { | |
| 103 if (JS('int', '#.status', xhr) != 200) { | |
| 104 completer.completeError( | |
| 105 new DeferredLoadException("Loading $uri failed.")); | |
| 106 return; | |
| 107 } | |
| 108 String code = JS('String', '#.responseText', xhr); | |
| 109 try { | |
| 110 // Create a new function to avoid getting access to current function | |
| 111 // context. | |
| 112 JS('void', '(new Function(#))()', code); | |
| 113 } catch (error, stackTrace) { | |
| 114 completer.completeError( | |
| 115 new DeferredLoadException("Evaluating $uri failed.")); | |
| 116 return; | |
| 117 } | |
| 118 completer.complete(true); | |
| 119 }, 1)); | |
| 120 | |
| 121 var fail = convertDartClosureToJS((event) { | |
| 122 new DeferredLoadException("Loading $uri failed."); | |
| 123 }, 1); | |
| 124 JS('void', '#.addEventListener("error", #, false)', xhr, fail); | |
| 125 JS('void', '#.addEventListener("abort", #, false)', xhr, fail); | |
| 126 | |
| 127 JS('void', '#.send()', xhr); | |
| 128 return leavingFuture; | |
| 129 }); | |
| 130 } | |
| 131 // We are in a dom-context. | |
| 132 return _loadedLibraries[hunkName] = new Future<bool>(() { | |
| 133 Completer completer = new Completer<bool>(); | |
| 134 // Inject a script tag. | |
| 135 var script = JS('', 'document.createElement("script")'); | |
| 136 JS('', '#.type = "text/javascript"', script); | |
| 137 JS('', '#.src = #', script, uri); | |
| 138 JS('', '#.addEventListener("load", #, false)', | |
| 139 script, convertDartClosureToJS((event) { | |
| 140 completer.complete(true); | |
| 141 }, 1)); | |
| 142 JS('', '#.addEventListener("error", #, false)', | |
| 143 script, convertDartClosureToJS((event) { | |
| 144 completer.completeError( | |
| 145 new DeferredLoadException("Loading $uri failed.")); | |
| 146 }, 1)); | |
| 147 JS('', 'document.body.appendChild(#)', script); | |
| 148 | |
| 149 return completer.future; | |
| 150 }); | |
| 151 } | |
| 152 | |
| 153 bool get _hasDocument => JS('String', 'typeof document') == 'object'; | 41 bool get _hasDocument => JS('String', 'typeof document') == 'object'; |
| OLD | NEW |