Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use nocall on my tal:condition?

I know that for performance it's good practice to use nocall on a <tal:condition> in order to avoid calling an object. Would appreciate (links to) a bit of background as this sounds a little vague to me :-)

So when do you use nocall? Can it hurt to put it on all my conditions?

Thanks !

like image 479
dimboo Avatar asked Apr 01 '11 14:04

dimboo


3 Answers

I tend to use tal:condition="python: variable" instead. That way I can always write normal proper Python expressions, without having to fear magic behavior from the default path expressions.

Path expressions will do a number of things, for example call the variable in the expression if it is callable. Often you deal with tools or content items in TAL, which are all callable.

The most common mistake is to use a tal:condition="content_object". The content object might come from a number of API's, for example calling any kind of reference field will return content objects. Catalog searches will return "brains" but in listings you often need to access more attributes of these, so you have a tal:define="obj brain/getObject".

Calling a content object causes the object to be rendered as if a browser would have requested it. As rendering pages usually takes between 500ms and 2 seconds, you make rendering your page slower by that amount of time. If you do this in a loop over 25 items, I'd expect the page to take 30 seconds or more to render.

like image 194
Hanno Schlichting Avatar answered Oct 22 '22 00:10

Hanno Schlichting


nocall lets you get a "handler" to an object's attribute or method. If you want to know if the object has that attribute or method you should use:

<div tal:condition="nocall:context/method|nothing">
  ...
</div>

The |nothing works similar as an except block in python code: if context/method fails (is undefined), return nothing. (This might not be exactly the real explanation but works like this).

Another reason to use nocall is to get a handler of method that you know is defined and you'll use later:

<div tal:define="method nocall:context/method">
    <span tal:content="python:method(3)" />
    <span tal:content="python:method('hello')" />
    <span tal:content="python:method('whatever')" />
</div>
like image 44
marcosfromero Avatar answered Oct 22 '22 01:10

marcosfromero


I'm presuming that you would only add nocall: to conditions that already test on items that are not callable in the first place, and that perhaps avoiding the python builtin callable test might be give you a performance boost.

The short answer to that question is no, that would not help you. On my Macbook Pro laptop, running callable(True) a 1000 times clocks in at 119ns per loop, vs. 71ns per loop for the plain True statement. So for simple python objects, the callable test takes a mere 48ns. Adding the nocall: to a TALES statement on the other hand, requires extra processing that almost certainly will exceed the 48ns overhead of the callable test you just saved.

Thus, adding nocall: for the sake of improving performance would backfire. You'd be better off implementing proper caching (look at plone.app.caching in combination with Varnish), or take a look if Chameleon could work for your use-case.

like image 42
Martijn Pieters Avatar answered Oct 22 '22 00:10

Martijn Pieters