@@ -22,24 +22,102 @@ import { setOptions, importLibrary } from "@googlemaps/js-api-loader";
22
22
const { Map } = await importLibrary (" maps" );
23
23
```
24
24
25
- Since wrapping all code working with the maps API into async functions can be
26
- problematic, we also provide an API that can be used in a synchronous context:
25
+ ## Synchronous API (TBD)
27
26
28
- ``` ts
29
- import {
30
- getImportedLibrary ,
31
- isLibraryImported ,
32
- } from " @googlemaps/js-api-loader" ;
33
-
34
- try {
35
- // getImportedLibrary throws an Error when the library hasn't been loaded yet
36
- // (otherwise the destructuring of the result wouldn't work)
37
- const { Map } = getImportedLibrary (" maps" );
38
- } catch (err ) {}
39
-
40
- // when guarded by isLibraryImported, it's guaranteed to not throw
41
- if (isLibraryImported (" maps" )) {
42
- const { Map } = getImportedLibrary (" maps" );
27
+ ### Motivation
28
+
29
+ There are a lot of situations where the ` importLibrary ` function doesn't
30
+ work well, since using an async function or promises isn't always a viable
31
+ option.
32
+
33
+ Currently, the only alternative to ` importLibrary ` is to use the global
34
+ ` google.maps ` namespaces. An additional synchronous API is intended to
35
+ provide an alternative way to using the global namespaces while solving some
36
+ of the problems that come with using them.
37
+
38
+ Any synchronous access to the libraries requires developers to make sure the
39
+ libraries have already been loaded when the corresponding code is executed.
40
+ In practice, this is rarely a big issue.
41
+
42
+ The exact shape of the synchronous API is to be determined, it could be a
43
+ simple Map instance ` libraries ` or a pair of has/get functions to check for and
44
+ retrieve loaded libraries.
45
+
46
+ ### Example 1: helper classes
47
+
48
+ Imagine some service class that uses the ` places ` library and the
49
+ ` PlacesService ` to do it's thing.
50
+
51
+ #### global namespace
52
+
53
+ This is how it would be written with the global ` google.maps ` namespace:
54
+
55
+ ``` tsx
56
+ class PlacesHelper {
57
+ private service: google .maps .places .PlacesService ;
58
+
59
+ constructor () {
60
+ if (! google .maps .places .PlacesService )
61
+ throw new Error (" maps api or places library missing" );
62
+
63
+ this .service = new google .maps .places .PlacesService ();
64
+ }
65
+
66
+ // ...
67
+ }
68
+ ```
69
+
70
+ This has two drawbacks:
71
+
72
+ - having to write out ` google.maps.places ` for all classes (and
73
+ types, but that's a seperate issue) adds a lot of "noise" to the code
74
+ - references to the global namespace can't really be minified, and
75
+ due to the late loading of the API, a global assignment to a shorthand
76
+ name isn't really possible.
77
+
78
+ #### importLibrary
79
+
80
+ Since in a constructor, we can't ` await ` the result of ` importLibrary ` , the
81
+ only way to do this is using the ` .then() ` function, which drastically
82
+ changes the semantics of the code:
83
+
84
+ ``` tsx
85
+ class PlacesHelper {
86
+ private service: google .maps .places .PlacesService | null = null ;
87
+
88
+ constructor () {
89
+ importLibrary (" places" ).then (
90
+ ({ PlacesService }) => (this .service = new PlacesService ())
91
+ );
92
+ }
93
+ }
94
+ ```
95
+
96
+ Here, the service has to be declared as optional (` | null ` ) in typescript,
97
+ and every other method of the class has to somehow deal with the fact that
98
+ the service might not yet have been initialized. Even if the library is
99
+ already loaded, it won't be returned until the queued mircotasks and the
100
+ handlers for the awaited Promise are executed.
101
+ This can even have cascading effects on all classes calling methods of this
102
+ class.
103
+
104
+ #### proposed sync API
105
+
106
+ A synchronous API would allow us to write the same code we used for
107
+ global namespaces, but without the readability problems and without global
108
+ namespaces:
109
+
110
+ ``` tsx
111
+ class PlacesHelper {
112
+ private service: google .maps .places .PlacesService = null ;
113
+
114
+ constructor () {
115
+ if (! isLibraryImported (" places" ))
116
+ throw new Error (" maps api or places library missing" );
117
+
118
+ const { PlacesService } = getImportedLibrary (" places" );
119
+ this .service = new PlacesService ();
120
+ }
43
121
}
44
122
```
45
123
0 commit comments