when.map() and context

28 views
Skip to first unread message

Paul Tiseo

unread,
Jul 22, 2013, 9:33:35 PM7/22/13
to cuj...@googlegroups.com
Many libraries with a map() function allow passing in an optional context such that the iterating function can access it. What's the best way to modify when's map() to allow this too?

Example using with Underscore.js:
var someOtherArrayOrObject = ["name":"patrick","type":"d","other":"w"];
_
.each(['item1', 'item2'], function(item){ alert(item + this[name]); }, someOtherArrayOrObject );



Brian Cavalier

unread,
Jul 22, 2013, 10:17:00 PM7/22/13
to cuj...@googlegroups.com
You can use ES5's Function.prototype.bind.  It's designed specifically to do this, and I tend to recommend it over the optional context arguments.  For example, the following are equivalent:

array.map(doStuff, someContext);

array.map(doStuff.bind(someContext));

So, if you want to set the context to a function you pass to when.map, you can do:

var promiseForMappedArray = when.map(arrayOfPromises, doStuff.bind(someContext));

Note that if you need to use bind() in non-ES5 environments, such as older IE, you can use an ES5 polyfill, such as cujoJS's poly or es5-shim

Scott Andrews

unread,
Jul 22, 2013, 10:24:35 PM7/22/13
to cuj...@googlegroups.com
when.js doesn't support a context argument directly, but that's ok.  You can bind the callback function's context.  For example:

when.map([item1, item2], (function (item) { return <transformed item>; }).bind(this));

-Scott



--
You received this message because you are subscribed to the Google Groups "cujojs" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cujojs+un...@googlegroups.com.
To post to this group, send email to cuj...@googlegroups.com.
Visit this group at http://groups.google.com/group/cujojs.
To view this discussion on the web visit https://groups.google.com/d/msgid/cujojs/799ed499-cc35-4646-83f9-f539a2c196fe%40googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Paul Tiseo

unread,
Jul 27, 2013, 10:51:15 AM7/27/13
to cuj...@googlegroups.com
So, when I do mergeTemplates() as a step in pipline, where the function is:

function mergeTemplates(data) {
 
return when.map(data.bodies, compileTemplate.bind(data) )
   
.then(
     
function(values) {
        data
.bodies = values;
       
return data;
     
}
   
);
};

function compileTemplate(item, data) {
  _
.templateSettings = {
    interpolate
: /\{\{(.+?)\}\}/g
 
};
 
var template = _.template(item);
 
return template(data);
}

When I put a breakpoint on the first line inside compileTemplate(), at _.templateSettings, data is undefined. Why?

Brian Cavalier

unread,
Jul 29, 2013, 11:43:08 AM7/29/13
to cuj...@googlegroups.com
Paul,

Function bind is used to bind both the thisArg (i.e. the value of `this` inside a function), and its positional parameters (partial application).  The way you've used bind() in your example, it will bind the value of `data` to `this` inside compileTemplate's, but compileTemplate expects `data` as its second parameter.


Since compileTemplate appears not to need a `thisArg`, one possible way you could refactor is:

// Note parameter order
function compileTemplate(data, value) {
   // code as before
}

function mergeTemplates(data) {
    // Since compileTemplate doesn't need a thisArg, can use undefined (or anything, really)
    return when.map(data.bodies, compileTemplate.bind(undefined, data))
        .then(...);
}

That will pass as the mapper function a version of compileTemplate that has its first formal parameter fixed to `data`.
Reply all
Reply to author
Forward
0 new messages