Service methods in Lightning Components

Realistically, you'll probably want to create a Static Resource, and use this as a shared resource, also outlined in Modularizing Code in Lightning Components. In your JavaScript file, you'll want to define all your methods.

window._myMethod = function(...) { ... }

Then, in your Lightning component markup:

<ltng:require scripts="{!$Resource.myJsUtils}"
              afterScriptsLoaded="{! ... }"/>

Note that "window" in this code actually ends up being the SecureWindow, not the global "window" provided by the browser, and this is automatically grafted into your code, so you can write:

({ // This is my controller
    someMethod: function(component, event, helper) {
        _myMethod( ... );
    }
})

The service component method (the last one mentioned in your question) is also possible. What you need to do though, is to provide a callback (mentioned in Modularizing Code in Lightning Components). The example for this looks like the following:


Service Component

<aura:component controller="AccountController">

    <aura:method name="findAll" action="{!c.findAll}">
        <aura:attribute name="callback" type="function"/>
    </aura:method>

</aura:component>

Service Component Controller

({
    findAll : function(component, event, helper) {
        var params = event.getParam("arguments");
        var action = component.get("c.getAccounts");
        action.setCallback(this, function(response) {
            if (response.getState() === "SUCCESS") {
                params.callback(null, response.getReturnValue());
            } else {
                params.callback(response.getError());
            }
        });
        $A.enqueueAction(action);
    }
})

Which you reference in your other components:

<aura:component>

    <aura:attribute name="accounts" type="Account[]"/>

    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>

    <c:AccountService aura:id="service"/>

    <ul>
    <aura:iteration items="{!v.accounts}" var="account">
        <li>{!account.Name}</li>
    </aura:iteration>
    </ul>        

</aura:component>

And is then called in the following manner:

({
    doInit : function(component, event, helper) {
        var service = component.find("service");
        service.findAll($A.getCallback(function(error, data) {
            // TODO: Add error handling
            component.set("v.accounts", data);
        }));
    }
})

In Winter 18, you can create a utility class and use it to directly return results without using a callback.

Quote:

We made it easier to return a result from aura:method, which is used to communicate from a parent component to a child component that it contains. Use the return statement to return a value from synchronous JavaScript code.

Ref here.

So you'd define your utility component:

<aura:component >
  <aura:method name="addNums" action="{!c.addNumbers}">
    <aura:attribute name="numbers" type="Integer[]"/>
  </aura:method>
</aura:component>

Controller or Helper:

({
  addNumbers : function(component, event, helper) {
      var params = event.getParam("arguments");
      var total = 0;
      params.numbers.forEach(function(num){
        total += num;
      });
      return total;
  }
})

And you'd call this method like so:

<aura:component>
  <c:mathUtils aura:id="mathUtils"/>
  <button onclick="{!c.getTotal}">Get Total!!</button>
</aura:component>

Controller/Helper:

getTotal : function(component, event, helper) {
  var numbers = [1,2,3];
  var total = component.find("mathUtils").addNums(numbers);
  alert(total);
}

NOTE THIS IS WINTER 18... So not available for use quite yet :)