いちにち
いちにち

Reputation: 417

Synchronous call using wrapAsync

I wrote a piece of code to get CSS contents from a file and I want to get that data inside my helper function.

Server-side:

Meteor.methods({

    'getCSS': function(filename) {
        return '<style>' + Assets.getText('css/' + filename) + '</style>';
    }

});

The css folder is located inside a private folder and consists of CSS files required for several pages. To my knowledge, the server-side code works correctly.

Client-side:

Template.home.helpers({

    'css': function() {

        var asyncFn = function(fn, cb) {
            Meteor.call('getCSS', fn, function(err, res) {
                console.log(res);   // prints data correctly
                cb && cb(null, res);
            });
        }
        var syncFn = Meteor.wrapAsync(asyncFn);
        var result = syncFn('home.css');
        console.log(result);    // undefined
        return result;

    }

});

After researching about how to use Meteor.wrapAsync this is the best solution that I could come up with. Not sure what I missed. I followed instructions from this blog.

Upvotes: 0

Views: 77

Answers (3)

いちにち
いちにち

Reputation: 417

Instead of storing the return value in a local variable, I used a Session. Now it works!

Template.home.helpers({

    'css': function() {

        Meteor.call('getCSS', 'home.css', function(err, res) {
            Session.set('css', res);
        });
        return Session.get('css');

    }

});

Upvotes: 0

JVercout
JVercout

Reputation: 130

I don't exactly understand what you are trying to achieve here.

From my point of view, cas should be load and compile from the first loading. Don't think it is a good idea to load CSS on the fly... You'll not be able to unload.

If you're inside a tracker computation (i.e. into router for example, on rendered events) you could use ReactiveMethod package to have something like synchronous call. It use the tracker dependency to wait response.

Another thing, you could finally setup a server side route to served CSS files from private folder...

Here if you need it,

Cheers

Upvotes: 0

Andrew Mao
Andrew Mao

Reputation: 36940

You can't use Meteor.wrapAsync on the client, because on the server the illusion of synchronicity depends on Fibers and there is no such parallel on the client.

Fibers effectively inlines asynchronous functions so that other code can run while waiting for the callback. Among other things, it helps eliminate the callback pyramid of doom anti-pattern. However, it does make it harder to reason about your code since if Javascript objects are shared between fibers, you'll have to explicitly think about when your code might be yielding (voluntarily pre-empted, such as by making a database call).

In any case, it will probably be a while before something similar becomes available on the client - as you can see, Fibers is implemented as a C++ package for node and can't be done simply with Javascript, since it actually makes asynchronous function calls look synchronous.

In your case, the proper way of doing lazy loading of CSS (as opposed to just including it in the rest of the Meteor bundle) is to just put it in the public/ folder (or include from a package with {isAsset: true}) and use a <head> tag to load when you need it.

Upvotes: 2

Related Questions