@@ -22,24 +22,102 @@ import { setOptions, importLibrary } from "@googlemaps/js-api-loader";
2222const { Map } = await importLibrary (" maps" );
2323```
2424
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)
2726
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+ }
43121}
44122```
45123
0 commit comments