node-continuation-local-storage
node-continuation-local-storage copied to clipboard
Alternative for browser and browserify
We are using continuation-local-storage in LoopBack to provide a "current context" object preserved across async calls. We would like to provide the same functionality when LoopBack is running in a browser via browserify.
Is there any alternative to node-continuation-local-storage that works in browsers?
I have been using a client side shim for CLS (worked on technique with @timbeyer - who might have an opinion), which is effectively a global (just set/get on a plain object) - however it does mean you can keep the behaviour consistent for isomorphic apps. Webpack/browserify is aliasing to the shim when creating the build.
It works for purposes of abstracting stuff which is global in a browser (cookies / browser state, whatever) and isolating those values on the server across async calls (as you guys know, 'cause you're using it ;) ) - however it does not provide 'real' cls functionality in the browser. @bajtos would that fake global work for you, or do you need the full-fat CLS..? Sounds like you may need the full thing.
To get to the point - I was just wondering as well, if CLS could provide a client side version of the library for browserify-alike purposes via the browser key in the package file...? As @othiym23 has mentioned in the past, there are libraries which provide similar functionality in the browser (think this one? https://github.com/angular/zone.js/ ) - so guess it's possible.
Benefits - canonical version of CLS for the browser, and everything in one place, isomorphism. Disadvantages - more stuff in CLS which isn't really for just node, much, much larger surface area of runtimes to support, don't always need the full fat experience.
I would be happy to bless a solution put together by others, or accept a patch to add a browser-side solution that either gets full CLS running or creates enough of a CLS-like experience to support apps that share code between the server and the browser. Since I don't do a lot of browser-side development, I'm not going to be super useful in actually developing the code, but I know enough people are interested in using something like CLS in the browser that I'd be happy to include that as part of the package's scope.
A basic client side shim has almost nothing to it.. like..
"use strict";
module.exports = {
createNamespace: function(name){
var ns = {};
return {
get: function(key){
if (ns.hasOwnProperty(key)) {
return ns[key];
}
},
set: function(key, value){
ns[key] = value;
}
}
}
}
..or whatever. Clearly, this does in no way give anything like the real cls functionality in the browser, but it's enough to abstract the usage, with a bit of care. I treat CLS values as if they were globals, so the only thing I needed was an abstraction. This is blatantly not going to work unless conventions are triple underlined and red flagged about what it is doing, but.. with those provisos, it does work.
I left out all the bind / run stuff from that, but you get the idea - if CLS is being treated as a global, then could be argued that shimming that functionality when it doesn't actually do anything would hide bugs.
The CLS bits are easy. It's creating an async-listener-like substrate for the browser that's tricky.
There are two use cases I suppose - and this thread highlights both. Sometimes you need the full on CLS inside a browser, and sometimes you don't. Any shim should really cover both.
Would it be useful to document these here as part of a roadmap? Any async-listener-like layer in a browser would be incredibly invasive, so makes sense to have that only if you really need it...?
As far as LoopBack's "current context" is concerned, we need a full async-listener-like implementation.
Perhaps the simplified version described by @dazld, which implements a global namespace only, can be provided as a temporary solution and exposed in a different way, so that users have to explicitly ask for it, for example require('continuation-local-storage/browser-global') and in package.json:
"browser": {
"continuation-local-storage": "continuation-local-storage/browser-global"
}
The benefit of keeping this implementation inside CLS, as opposed to publishing a new module, is that a single module makes it easier to keep the APIs the same in the future and also to reuse code.
I still don't have a good solution for this from within CLS, but I'd point out that Angular's Zones are apparently in the early stages of TC39 standardization. Hope you like TypeScript!
Here's the proposal as put together for January's TC39 meeting.
Browser support is highly appreciated.