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