@@ -859,6 +859,293 @@ for (let i = 0; i < 10; i++) {
859
859
}
860
860
```
861
861
862
+ ## Class: ` AsyncLocalStorage `
863
+ <!-- YAML
864
+ added: REPLACEME
865
+ -->
866
+
867
+ This class is used to create asynchronous state within callbacks and promise
868
+ chains. It allows storing data throughout the lifetime of a web request
869
+ or any other asynchronous duration. It is similar to thread-local storage
870
+ in other languages.
871
+
872
+ The following example builds a logger that will always know the current HTTP
873
+ request and uses it to display enhanced logs without needing to explicitly
874
+ provide the current HTTP request to it.
875
+
876
+ ``` js
877
+ const { AsyncLocalStorage } = require (' async_hooks' );
878
+ const http = require (' http' );
879
+
880
+ const kReq = ' CURRENT_REQUEST' ;
881
+ const asyncLocalStorage = new AsyncLocalStorage ();
882
+
883
+ function log (... args ) {
884
+ const store = asyncLocalStorage .getStore ();
885
+ // Make sure the store exists and it contains a request.
886
+ if (store && store .has (kReq)) {
887
+ const req = store .get (kReq);
888
+ // Prints `GET /items ERR could not do something
889
+ console .log (req .method , req .url , ... args);
890
+ } else {
891
+ console .log (... args);
892
+ }
893
+ }
894
+
895
+ http .createServer ((request , response ) => {
896
+ asyncLocalStorage .run (() => {
897
+ const store = asyncLocalStorage .getStore ();
898
+ store .set (kReq, request);
899
+ someAsyncOperation ((err , result ) => {
900
+ if (err) {
901
+ log (' ERR' , err .message );
902
+ }
903
+ });
904
+ });
905
+ })
906
+ .listen (8080 );
907
+ ```
908
+
909
+ When having multiple instances of ` AsyncLocalStorage ` , they are independent
910
+ from each other. It is safe to instantiate this class multiple times.
911
+
912
+ ### ` new AsyncLocalStorage() `
913
+ <!-- YAML
914
+ added: REPLACEME
915
+ -->
916
+
917
+ Creates a new instance of ` AsyncLocalStorage ` . Store is only provided within a
918
+ ` run ` or a ` runSyncAndReturn ` method call.
919
+
920
+ ### ` asyncLocalStorage.disable() `
921
+ <!-- YAML
922
+ added: REPLACEME
923
+ -->
924
+
925
+ This method disables the instance of ` AsyncLocalStorage ` . All subsequent calls
926
+ to ` asyncLocalStorage.getStore() ` will return ` undefined ` until
927
+ ` asyncLocalStorage.run() ` or ` asyncLocalStorage.runSyncAndReturn() `
928
+ is called again.
929
+
930
+ When calling ` asyncLocalStorage.disable() ` , all current contexts linked to the
931
+ instance will be exited.
932
+
933
+ Calling ` asyncLocalStorage.disable() ` is required before the
934
+ ` asyncLocalStorage ` can be garbage collected. This does not apply to stores
935
+ provided by the ` asyncLocalStorage ` , as those objects are garbage collected
936
+ along with the corresponding async resources.
937
+
938
+ This method is to be used when the ` asyncLocalStorage ` is not in use anymore
939
+ in the current process.
940
+
941
+ ### ` asyncLocalStorage.getStore() `
942
+ <!-- YAML
943
+ added: REPLACEME
944
+ -->
945
+
946
+ * Returns: {Map}
947
+
948
+ This method returns the current store.
949
+ If this method is called outside of an asynchronous context initialized by
950
+ calling ` asyncLocalStorage.run ` or ` asyncLocalStorage.runAndReturn ` , it will
951
+ return ` undefined ` .
952
+
953
+ ### ` asyncLocalStorage.run(callback[, ...args]) `
954
+ <!-- YAML
955
+ added: REPLACEME
956
+ -->
957
+
958
+ * ` callback ` {Function}
959
+ * ` ...args ` {any}
960
+
961
+ Calling ` asyncLocalStorage.run(callback) ` will create a new asynchronous
962
+ context.
963
+ Within the callback function and the asynchronous operations from the callback,
964
+ ` asyncLocalStorage.getStore() ` will return an instance of ` Map ` known as
965
+ "the store". This store will be persistent through the following
966
+ asynchronous calls.
967
+
968
+ The callback will be ran asynchronously. Optionally, arguments can be passed
969
+ to the function. They will be passed to the callback function.
970
+
971
+ If an error is thrown by the callback function, it will not be caught by
972
+ a ` try/catch ` block as the callback is ran in a new asynchronous resource.
973
+ Also, the stacktrace will be impacted by the asynchronous call.
974
+
975
+ Example:
976
+
977
+ ``` js
978
+ asyncLocalStorage .run (() => {
979
+ asyncLocalStorage .getStore (); // Returns a Map
980
+ someAsyncOperation (() => {
981
+ asyncLocalStorage .getStore (); // Returns the same Map
982
+ });
983
+ });
984
+ asyncLocalStorage .getStore (); // Returns undefined
985
+ ```
986
+
987
+ ### ` asyncLocalStorage.exit(callback[, ...args]) `
988
+ <!-- YAML
989
+ added: REPLACEME
990
+ -->
991
+
992
+ * ` callback ` {Function}
993
+ * ` ...args ` {any}
994
+
995
+ Calling ` asyncLocalStorage.exit(callback) ` will create a new asynchronous
996
+ context.
997
+ Within the callback function and the asynchronous operations from the callback,
998
+ ` asyncLocalStorage.getStore() ` will return ` undefined ` .
999
+
1000
+ The callback will be ran asynchronously. Optionally, arguments can be passed
1001
+ to the function. They will be passed to the callback function.
1002
+
1003
+ If an error is thrown by the callback function, it will not be caught by
1004
+ a ` try/catch ` block as the callback is ran in a new asynchronous resource.
1005
+ Also, the stacktrace will be impacted by the asynchronous call.
1006
+
1007
+ Example:
1008
+
1009
+ ``` js
1010
+ asyncLocalStorage .run (() => {
1011
+ asyncLocalStorage .getStore (); // Returns a Map
1012
+ asyncLocalStorage .exit (() => {
1013
+ asyncLocalStorage .getStore (); // Returns undefined
1014
+ });
1015
+ asyncLocalStorage .getStore (); // Returns the same Map
1016
+ });
1017
+ ```
1018
+
1019
+ ### ` asyncLocalStorage.runSyncAndReturn(callback[, ...args]) `
1020
+ <!-- YAML
1021
+ added: REPLACEME
1022
+ -->
1023
+
1024
+ * ` callback ` {Function}
1025
+ * ` ...args ` {any}
1026
+
1027
+ This methods runs a function synchronously within a context and return its
1028
+ return value. The store is not accessible outside of the callback function or
1029
+ the asynchronous operations created within the callback.
1030
+
1031
+ Optionally, arguments can be passed to the function. They will be passed to
1032
+ the callback function.
1033
+
1034
+ If the callback function throws an error, it will be thrown by
1035
+ ` runSyncAndReturn ` too. The stacktrace will not be impacted by this call and
1036
+ the context will be exited.
1037
+
1038
+ Example:
1039
+
1040
+ ``` js
1041
+ try {
1042
+ asyncLocalStorage .runSyncAndReturn (() => {
1043
+ asyncLocalStorage .getStore (); // Returns a Map
1044
+ throw new Error ();
1045
+ });
1046
+ } catch (e) {
1047
+ asyncLocalStorage .getStore (); // Returns undefined
1048
+ // The error will be caught here
1049
+ }
1050
+ ```
1051
+
1052
+ ### ` asyncLocalStorage.exitSyncAndReturn(callback[, ...args]) `
1053
+ <!-- YAML
1054
+ added: REPLACEME
1055
+ -->
1056
+
1057
+ * ` callback ` {Function}
1058
+ * ` ...args ` {any}
1059
+
1060
+ This methods runs a function synchronously outside of a context and return its
1061
+ return value. The store is not accessible within the callback function or
1062
+ the asynchronous operations created within the callback.
1063
+
1064
+ Optionally, arguments can be passed to the function. They will be passed to
1065
+ the callback function.
1066
+
1067
+ If the callback function throws an error, it will be thrown by
1068
+ ` exitSyncAndReturn ` too. The stacktrace will not be impacted by this call and
1069
+ the context will be re-entered.
1070
+
1071
+ Example:
1072
+
1073
+ ``` js
1074
+ // Within a call to run or runSyncAndReturn
1075
+ try {
1076
+ asyncLocalStorage .getStore (); // Returns a Map
1077
+ asyncLocalStorage .exitSyncAndReturn (() => {
1078
+ asyncLocalStorage .getStore (); // Returns undefined
1079
+ throw new Error ();
1080
+ });
1081
+ } catch (e) {
1082
+ asyncLocalStorage .getStore (); // Returns the same Map
1083
+ // The error will be caught here
1084
+ }
1085
+ ```
1086
+
1087
+ ### Choosing between ` run ` and ` runSyncAndReturn `
1088
+
1089
+ #### When to choose ` run `
1090
+
1091
+ ` run ` is asynchronous. It is called with a callback function that
1092
+ runs within a new asynchronous call. This is the most explicit behavior as
1093
+ everything that is executed within the callback of ` run ` (including further
1094
+ asynchronous operations) will have access to the store.
1095
+
1096
+ If an instance of ` AsyncLocalStorage ` is used for error management (for
1097
+ instance, with ` process.setUncaughtExceptionCaptureCallback ` ), only
1098
+ exceptions thrown in the scope of the callback function will be associated
1099
+ with the context.
1100
+
1101
+ This method is the safest as it provides strong scoping and consistent
1102
+ behavior.
1103
+
1104
+ It cannot be promisified using ` util.promisify ` . If needed, the ` Promise `
1105
+ constructor can be used:
1106
+
1107
+ ``` js
1108
+ new Promise ((resolve , reject ) => {
1109
+ asyncLocalStorage .run (() => {
1110
+ someFunction ((err , result ) => {
1111
+ if (err) {
1112
+ return reject (err);
1113
+ }
1114
+ return resolve (result);
1115
+ });
1116
+ });
1117
+ });
1118
+ ```
1119
+
1120
+ #### When to choose ` runSyncAndReturn `
1121
+
1122
+ ` runSyncAndReturn ` is synchronous. The callback function will be executed
1123
+ synchronously and its return value will be returned by ` runSyncAndReturn ` .
1124
+ The store will only be accessible from within the callback
1125
+ function and the asynchronous operations created within this scope.
1126
+ If the callback throws an error, ` runSyncAndReturn ` will throw it and it will
1127
+ not be associated with the context.
1128
+
1129
+ This method provides good scoping while being synchronous.
1130
+
1131
+ #### Usage with ` async/await `
1132
+
1133
+ If, within an async function, only one ` await ` call is to run within a context,
1134
+ the following pattern should be used:
1135
+
1136
+ ``` js
1137
+ async function fn () {
1138
+ await asyncLocalStorage .runSyncAndReturn (() => {
1139
+ asyncLocalStorage .getStore ().set (' key' , value);
1140
+ return foo (); // The return value of foo will be awaited
1141
+ });
1142
+ }
1143
+ ```
1144
+
1145
+ In this example, the store is only available in the callback function and the
1146
+ functions called by ` foo ` . Outside of ` runSyncAndReturn ` , calling ` getStore `
1147
+ will return ` undefined ` .
1148
+
862
1149
[ `after` callback ] : #async_hooks_after_asyncid
863
1150
[ `before` callback ] : #async_hooks_before_asyncid
864
1151
[ `destroy` callback ] : #async_hooks_destroy_asyncid
0 commit comments