I've had a chance to play with some failing async API calls and have to
admit I don't really like the chrome.extension.lastError pattern.  The basic
issue is that after an async call completes either successfully or with an
error the same callback is invoked.  However if there was an error then the
parameters on the callback are invalid and the callback has to use the
'lastError' variable as the logical parameter.  In other words, the start of
every callback has to look something like this:
function fooCallback(param1, param2, param3) {
  if (chrome.extension.lastError) {
    // Don't use param1, param2, param3, instead use
chrome.extension.lastError to try to recover
  } else {
    // Now we can use param1, param2, param3
  }
}

This boils down to the original proposal of having a 'success' flag be the
first parameter except that it's a rather awkward way to go about it.
 Invariably when writing my own code I forget to check
chrome.extension.lastError in my callback and die horribly at the first
attempt to reference a parameter on the callback.  If they do something like
store a reference to the callback parameters in a container for later
processing then the undefined reference might not show up until much much
later and be impossible to track down.  In cases where the callback is
parameterless (for example chrome.tabs.update()) an extensions developer
will typically forget to check lastError and proceed with their application
logic regardless of if the call succeeded.  This seems less than ideal :(

The second issue with the chrome.extension.lastError approach is that
typically by the time my callback was invoked it was too late to handle the
error in any reasonable way.  In my case the underlying source of the API
failures was http://crbug.com/13284 and the workaround was to retry the call
a bit later.  In order to retry the call I had to keep all the parameters to
the original call around somewhere and have them available in the success
callback.  The pattern looked something like this:

  var createParam = { ... };
  chrome.tabs.create(createParams, function(tab) {
    if (chrome.extension.lastError) {
      handleTabCreatedError(chrome.extension.lastError, createParams);
    } else {
      realTabCreatedCallback(tab);
    }
  });

This gets a little verbose to have on every asynchronous API call.

I would suggest having explicit successCallback / errorCallback callbacks
set on an object sent in to each async call.  This way the extension writer
can keep their error handling code separate from their normal application
logic, avoid accidentally treating an error callback as a success callback,
and be able to use only the parameters to the callbacks rather than globals
sitting on chrome.extension.  chrome.tabs.create's signature would then look
like:

void create([{[string url], [int windowId], [int index], [bool selected]}],
                [{[void successCallback(Tab)], [void
errorCallback(Error)]}]);

successCallback() would only be invoked on a successful completion of the
call and the Tab parameter would always be a valid chrome.tabs.Tab object.
 errorCallback() would be invoked if the call failed with an Error parameter
which would replace the chrome.extension.lastError object.

- James

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Chromium-extensions" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/chromium-extensions?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to