OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 library _js_helper; | 5 library _js_helper; |
6 | 6 |
7 import 'dart:collection'; | 7 import 'dart:collection'; |
8 import 'dart:_isolate_helper' show | 8 import 'dart:_isolate_helper' show |
9 IsolateNatives, | 9 IsolateNatives, |
10 leaveJsAsync, | 10 leaveJsAsync, |
(...skipping 3205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3216 * DOM isolates. This happens when multiple programs are loaded in the same | 3216 * DOM isolates. This happens when multiple programs are loaded in the same |
3217 * JavaScript context (i.e. page). The name is based on [name] but with an | 3217 * JavaScript context (i.e. page). The name is based on [name] but with an |
3218 * additional part that is unique for each isolate. | 3218 * additional part that is unique for each isolate. |
3219 * | 3219 * |
3220 * The form of the name is '___dart_$name_$id'. | 3220 * The form of the name is '___dart_$name_$id'. |
3221 */ | 3221 */ |
3222 String getIsolateAffinityTag(String name) { | 3222 String getIsolateAffinityTag(String name) { |
3223 return JS('String', 'init.getIsolateTag(#)', name); | 3223 return JS('String', 'init.getIsolateTag(#)', name); |
3224 } | 3224 } |
3225 | 3225 |
3226 typedef Future<bool> LoadLibraryFunctionType(); | 3226 typedef Future<Null> LoadLibraryFunctionType(); |
3227 | 3227 |
3228 LoadLibraryFunctionType _loadLibraryWrapper(String loadId) { | 3228 LoadLibraryFunctionType _loadLibraryWrapper(String loadId) { |
3229 return () => loadDeferredLibrary(loadId); | 3229 return () => loadDeferredLibrary(loadId); |
3230 } | 3230 } |
3231 | 3231 |
3232 final Map<String, Future<bool>> _loadedLibraries = <String, Future<bool>>{}; | 3232 final Map<String, Future<Null>> _loadedLibraries = <String, Future<Null>>{}; |
3233 | 3233 |
3234 Future<bool> loadDeferredLibrary(String loadId, [String uri]) { | 3234 Future<bool> loadDeferredLibrary(String loadId, [String uri]) { |
3235 List hunkNames = new List(); | 3235 |
3236 if (JS('bool', '\$.libraries_to_load[#] === undefined', loadId)) { | 3236 List<List<String>> hunkLists = JS('JSExtendableArray|Null', |
3237 return new Future(() => false); | 3237 '\$.libraries_to_load[#]', loadId); |
3238 } | 3238 if (hunkLists == null) return new Future.value(null); |
3239 for (int index = 0; | 3239 |
3240 index < JS('int', '\$.libraries_to_load[#].length', loadId); | 3240 return Future.forEach(hunkLists, (hunkNames) { |
3241 ++index) { | 3241 Iterable<Future<Null>> allLoads = |
3242 hunkNames.add(JS('String', '\$.libraries_to_load[#][#]', | 3242 hunkNames.map((hunkName) => _loadHunk(hunkName, uri)); |
3243 loadId, index)); | 3243 return Future.wait(allLoads).then((_) => null); |
3244 } | |
3245 Iterable<Future<bool>> allLoads = | |
3246 hunkNames.map((hunkName) => _loadHunk(hunkName, uri)); | |
3247 return Future.wait(allLoads).then((results) { | |
3248 return results.any((x) => x); | |
3249 }); | 3244 }); |
3250 } | 3245 } |
3251 | 3246 |
3252 Future<bool> _loadHunk(String hunkName, String uri) { | 3247 Future<Null> _loadHunk(String hunkName, String uri) { |
3253 // TODO(ahe): Validate libraryName. Kasper points out that you want | 3248 // TODO(ahe): Validate libraryName. Kasper points out that you want |
3254 // to be able to experiment with the effect of toggling @DeferLoad, | 3249 // to be able to experiment with the effect of toggling @DeferLoad, |
3255 // so perhaps we should silently ignore "bad" library names. | 3250 // so perhaps we should silently ignore "bad" library names. |
3256 Future<bool> future = _loadedLibraries[hunkName]; | 3251 Future<Null> future = _loadedLibraries[hunkName]; |
3257 if (future != null) { | 3252 if (future != null) { |
3258 return future.then((_) => false); | 3253 return future.then((_) => null); |
3259 } | 3254 } |
3260 | 3255 |
3261 if (uri == null) { | 3256 if (uri == null) { |
3262 uri = IsolateNatives.thisScript; | 3257 uri = IsolateNatives.thisScript; |
3263 } | 3258 } |
3264 int index = uri.lastIndexOf('/'); | 3259 int index = uri.lastIndexOf('/'); |
3265 uri = '${uri.substring(0, index + 1)}$hunkName'; | 3260 uri = '${uri.substring(0, index + 1)}$hunkName'; |
3266 | 3261 |
3267 if (Primitives.isJsshell || Primitives.isD8) { | 3262 if (Primitives.isJsshell || Primitives.isD8) { |
3268 // TODO(ahe): Move this code to a JavaScript command helper script that is | 3263 // TODO(ahe): Move this code to a JavaScript command helper script that is |
3269 // not included in generated output. | 3264 // not included in generated output. |
3270 return _loadedLibraries[hunkName] = new Future<bool>(() { | 3265 return _loadedLibraries[hunkName] = new Future<Null>(() { |
3271 try { | 3266 try { |
3272 // Create a new function to avoid getting access to current function | 3267 // Create a new function to avoid getting access to current function |
3273 // context. | 3268 // context. |
3274 JS('void', '(new Function(#))()', 'load("$uri")'); | 3269 JS('void', '(new Function(#))()', 'load("$uri")'); |
3275 } catch (error, stackTrace) { | 3270 } catch (error, stackTrace) { |
3276 throw new DeferredLoadException("Loading $uri failed."); | 3271 throw new DeferredLoadException("Loading $uri failed."); |
3277 } | 3272 } |
3278 return true; | 3273 return null; |
3279 }); | 3274 }); |
3280 } else if (isWorker()) { | 3275 } else if (isWorker()) { |
3281 // We are in a web worker. Load the code with an XMLHttpRequest. | 3276 // We are in a web worker. Load the code with an XMLHttpRequest. |
3282 return _loadedLibraries[hunkName] = new Future<bool>(() { | 3277 return _loadedLibraries[hunkName] = new Future<Null>(() { |
3283 Completer completer = new Completer<bool>(); | 3278 Completer completer = new Completer<Null>(); |
3284 enterJsAsync(); | 3279 enterJsAsync(); |
3285 Future<bool> leavingFuture = completer.future.whenComplete(() { | 3280 Future<Null> leavingFuture = completer.future.whenComplete(() { |
3286 leaveJsAsync(); | 3281 leaveJsAsync(); |
3287 }); | 3282 }); |
3288 | 3283 |
3289 int index = uri.lastIndexOf('/'); | 3284 int index = uri.lastIndexOf('/'); |
3290 uri = '${uri.substring(0, index + 1)}$hunkName'; | 3285 uri = '${uri.substring(0, index + 1)}$hunkName'; |
3291 var xhr = JS('dynamic', 'new XMLHttpRequest()'); | 3286 var xhr = JS('dynamic', 'new XMLHttpRequest()'); |
3292 JS('void', '#.open("GET", #)', xhr, uri); | 3287 JS('void', '#.open("GET", #)', xhr, uri); |
3293 JS('void', '#.addEventListener("load", #, false)', | 3288 JS('void', '#.addEventListener("load", #, false)', |
3294 xhr, convertDartClosureToJS((event) { | 3289 xhr, convertDartClosureToJS((event) { |
3295 if (JS('int', '#.status', xhr) != 200) { | 3290 if (JS('int', '#.status', xhr) != 200) { |
3296 completer.completeError( | 3291 completer.completeError( |
3297 new DeferredLoadException("Loading $uri failed.")); | 3292 new DeferredLoadException("Loading $uri failed.")); |
3298 return; | 3293 return; |
3299 } | 3294 } |
3300 String code = JS('String', '#.responseText', xhr); | 3295 String code = JS('String', '#.responseText', xhr); |
3301 try { | 3296 try { |
3302 // Create a new function to avoid getting access to current function | 3297 // Create a new function to avoid getting access to current function |
3303 // context. | 3298 // context. |
3304 JS('void', '(new Function(#))()', code); | 3299 JS('void', '(new Function(#))()', code); |
3305 } catch (error, stackTrace) { | 3300 } catch (error, stackTrace) { |
3306 completer.completeError( | 3301 completer.completeError( |
3307 new DeferredLoadException("Evaluating $uri failed.")); | 3302 new DeferredLoadException("Evaluating $uri failed.")); |
3308 return; | 3303 return; |
3309 } | 3304 } |
3310 completer.complete(true); | 3305 completer.complete(null); |
3311 }, 1)); | 3306 }, 1)); |
3312 | 3307 |
3313 var fail = convertDartClosureToJS((event) { | 3308 var fail = convertDartClosureToJS((event) { |
3314 new DeferredLoadException("Loading $uri failed."); | 3309 new DeferredLoadException("Loading $uri failed."); |
3315 }, 1); | 3310 }, 1); |
3316 JS('void', '#.addEventListener("error", #, false)', xhr, fail); | 3311 JS('void', '#.addEventListener("error", #, false)', xhr, fail); |
3317 JS('void', '#.addEventListener("abort", #, false)', xhr, fail); | 3312 JS('void', '#.addEventListener("abort", #, false)', xhr, fail); |
3318 | 3313 |
3319 JS('void', '#.send()', xhr); | 3314 JS('void', '#.send()', xhr); |
3320 return leavingFuture; | 3315 return leavingFuture; |
3321 }); | 3316 }); |
3322 } | 3317 } |
3323 // We are in a dom-context. | 3318 // We are in a dom-context. |
3324 return _loadedLibraries[hunkName] = new Future<bool>(() { | 3319 return _loadedLibraries[hunkName] = new Future<Null>(() { |
3325 Completer completer = new Completer<bool>(); | 3320 Completer completer = new Completer<Null>(); |
3326 // Inject a script tag. | 3321 // Inject a script tag. |
3327 var script = JS('', 'document.createElement("script")'); | 3322 var script = JS('', 'document.createElement("script")'); |
3328 JS('', '#.type = "text/javascript"', script); | 3323 JS('', '#.type = "text/javascript"', script); |
3329 JS('', '#.src = #', script, uri); | 3324 JS('', '#.src = #', script, uri); |
3330 JS('', '#.addEventListener("load", #, false)', | 3325 JS('', '#.addEventListener("load", #, false)', |
3331 script, convertDartClosureToJS((event) { | 3326 script, convertDartClosureToJS((event) { |
3332 completer.complete(true); | 3327 completer.complete(null); |
3333 }, 1)); | 3328 }, 1)); |
3334 JS('', '#.addEventListener("error", #, false)', | 3329 JS('', '#.addEventListener("error", #, false)', |
3335 script, convertDartClosureToJS((event) { | 3330 script, convertDartClosureToJS((event) { |
3336 completer.completeError( | 3331 completer.completeError( |
3337 new DeferredLoadException("Loading $uri failed.")); | 3332 new DeferredLoadException("Loading $uri failed.")); |
3338 }, 1)); | 3333 }, 1)); |
3339 JS('', 'document.body.appendChild(#)', script); | 3334 JS('', 'document.body.appendChild(#)', script); |
3340 | 3335 |
3341 return completer.future; | 3336 return completer.future; |
3342 }); | 3337 }); |
3343 } | 3338 } |
OLD | NEW |