2014년 12월 13일 토요일

yet another sync/async question

I've been following async to sync discussions for years but I have one fundamental question.  Is it possible to wrap an async function in a library such that it can be called from code that is written expecting a sync function?  In other words could I make a library containing a readFileSync function that uses fs.readFile?

Using something like generators inside the library is legal as long as the caller isn't aware of this.  Requiring the caller code to do a transpile is not legal.

I should mention that this is for a node environment emulation that places calls over the network using proxies.  The readFileSync code obviously can't go in a busy-wait loop waiting for the result from the net.




I've been following async to sync discussions for years but I have one fundamental question.  Is it possible to wrap an async function in a library such that it can be called from code that is written expecting a sync function?  In other words could I make a library containing a readFileSync function that uses fs.readFile?
Using something like generators inside the library is legal as long as the caller isn't aware of this.  Requiring the caller code to do a transpile is not legal.

I should mention that this is for a node environment emulation that places calls over the network using proxies.  The readFileSync code obviously can't go in a busy-wait loop waiting for the result from the net.
There is not. Generators are close, but require the caller to also be function *, all the way down.



I imagine you could do this with child_process.execSync in v0.12. But please don't!






All current multi-sync-flow-logic stuff are actually all explicitly designed in the way so you cannot do this. That is yield a caller, without it knowing about this​ possibility and making it part of the "call contract". Every one has a highlight to say "attention this call might yield and even cause reentry", be it the "yield" keyword with generators, or the '_' streamline in Brunos stuff.

In vanilla fibers it is actually possible to yied a fiber without the caller knowing about it in the call contract, for which it has been critized. However, the caller needs to running in a fiber the first place.

Brunos streamline transpiler always has been async to the bone. It just looks like sync code to the coder. So if you need to use a library that has an readFileSync included, you should easily be able to modify it only slightly to be able to through it through the transpiler to be async friendly. As long the now possible reentries don't bite it due to blowszy use of globals or upvalues. 



> explicitly designed in the way so you cannot do this

I understand.  I am unfortunately facing a pragmatic problem that could be solved if a library could simulate a sync call with an async over-the-net call.

Maybe I should restate the immense task I'd like to tackle.  I'd like to implement node fs calls in the browser using the net to proxy to the server's file system.  This includes sync fs calls.




> > explicitly designed in the way so you cannot do this
>
> I understand.  I am unfortunately facing a pragmatic problem that could be solved if a library could simulate a sync call with an async over-the-net call.
>
> Maybe I should restate the immense task I'd like to tackle.  I'd like to implement node fs calls in the browser using the net to proxy to the server's file system.  This includes sync fs calls.
That's rough: you've only synchronous XHR to do that, and it's pretty restricted since all the new features of XHR aren't allowed in sync mode.

What're you dealing with that uses sync calls?



What're you dealing with that uses sync calls?

OK, I wasn't going to admit how crazy I am, but I'm considering running the Atom editor in the browser by providing all the node calls it needs.  What this really means is porting atom-shell to the browser.

I'm not afraid of all the work involved, I just want to make sure it is possible.  Atom-shell and therefore Atom editor use almost all async fs calls.  This makes sense since it is a desktop app and two things aren't running at once anyway.

Browserify is already porting part of node to the browser.  The missing part is fs.  I have used simulated file systems in the browser before with emscripten and I'm pretty confident performance will be ok.  I want to add fs to browserify.



 you've only synchronous XHR to do that,

You've made me think about this.  I rejected sync XHR out-of-hand because the user interface would be blocked which of course is a horrible idea.  But the Atom editor only hits the disk to load/save source files and sometimes to load/save options.  And of course it hits it a lot when the app is loading.  When editing a source file the disk it silent.  So maybe sync XHR is worth considering.

 it's pretty restricted since all the new features of XHR aren't allowed in sync mode.

What features would I be missing?  I can't imagine anything other than making normal http requests.




 you've only synchronous XHR to do that,

You've made me think about this.  I rejected sync XHR out-of-hand because the user interface would be blocked which of course is a horrible idea.  But the Atom editor only hits the disk to load/save source files and sometimes to load/save options.  And of course it hits it a lot when the app is loading.  When editing a source file the disk it silent.  So maybe sync XHR is worth considering.
Makes sense!

So Atom pinwheels when the disk is slow?

 it's pretty restricted since all the new features of XHR aren't allowed in sync mode.

What features would I be missing?  I can't imagine anything other than making normal http requests.
Binary data handling and some of the XHR2 features, I believe.



So Atom pinwheels when the disk is slow?

No.  The disk is fast enough to not notice.  It is node itself that slows down atom, at least compared to an editor written in C++.




sync XHR may be a bandaid solution but I think that it should really be a last resort.

For info, vim has been ported to the browser by Lu Wang. The challenge was similar to yours because the implementation uses blocking calls to read from the terminal. The challenge was even higher because the source was in C, not JS.

The vim port was done by first transpiling the C to JS with , then hacking the JS to add an _ parameters to all async calls, and then transpiling with streamline.js. A special C header was used to rename all the async calls so that they could be hacked automatically. The result is here: http://coolwanglu.github.io/vim.js/web/vim.html

Later on, Lu Wang created his own fork of emscripten with an async extension. This allowed him to eliminate the streamline.js pass.

So maybe you should not completely rule out the transpiler route.



 hacking the JS to add an _ parameters to all async calls

Unfortunately I need to support arbitrary unknown code calling my lib functions.



댓글 없음:

댓글 쓰기