- Electron version: 0.37.5
- Operating system: Mac OS X 10.11.4

It’s not stated in the documentation, but Electron generally seems to guarantee that the `did-fail-load` event happens before the `did-finish-load` event on `WebContents`. However, if the failure is in _provisional_ loading, there is a race condition where `did-fail-load` can come after `did-finish-load`.

Test following Electron program will intermittently cause the problem, though I can’t find a way to reliably reproduce every time:

``` js
const electron = require('electron');
var mainWindow = null;
electron.app.on('ready', function() {
  function logEvent(eventName) {
    mainWindow.webContents.on(eventName, function() {
      console.log(eventName, [].slice.call(arguments, 1));
    });
  }
  mainWindow = new electron.BrowserWindow({width: 1000, height: 800});
  logEvent('did-start-loading');
  logEvent('did-fail-provisional-load');
  logEvent('did-fail-load');
  logEvent('did-finish-load');
  mainWindow.loadURL('http://somewhere-that-does-not.exist');
});
```

Which _should_ give you output like:

```
did-start-loading []
did-fail-provisional-load [ -105, '', 'http://somewhere-that-does-not.exist/' ]
did-fail-load [ -105, '', 'http://somewhere-that-does-not.exist/' ]
did-finish-load []
```

But occasionally gives:

```
did-start-loading []
did-fail-provisional-load [ -105, '', 'http://somewhere-that-does-not.exist/' ]
did-finish-load []
did-fail-load [ -105, '', 'http://somewhere-that-does-not.exist/' ]
```

---

The issue seems to be caused by the fact that when there is a provisional loading error, `did-fail-provisional-load` simulates the `did-fail-load` event, but does so _later:_ https://github.com/electron/electron/blob/master/lib/browser/api/web-contents.js#L153, which appears to have been introduced in https://github.com/electron/electron/commit/1b3eb1cc5df74ed2dac3f8e7e0fea17497ddda28

Most of the time, the delay causes no problems, but occasionally the function that triggers `did-fail-load` gets scheduled after the `did-finish-load` event gets emitted. I ran across this issue while working on a change to Nightmare (an automated browser based on Electron) to better handle URL loading (https://github.com/segmentio/nightmare/pull/553). The tests would fail intermittently as a result.

There is an easy workaround (listen for both `did-fail-load` and `did-fail-provisional-load`; take action on the first one that occurs), but non-obvious—you’d have to do some spelunking in Electron’s code to understand what’s happening. Further, I don’t think users should really have to do this kind of extra effort if they don’t have a use-case that requires differentiating between provisional and normal loading failures. And, of course, `did-fail-provisional-load` is not even documented. (should it be?)

I can think of a few ways to address this:
1. Delay `loadURL` calls to the next tick (there are a few sites, but not too many, that would have to be addressed). This would be fairly easy on the JS side, not sure how simple on the C++ side.
2. Internally on the C++ side of `loadURL`, check whether it’s safe to take action or wait until it is. I have _no_ idea whether the relevant information to do this is even really available, let alone what the right calls to get it would be.
3. Delay emitting `did-finish-frame-load` and `did-finish-load` by a tick. I _think_ this would have to happen on the JS side to really ensure that the events can’t get queued before the synthetic `did-fail-load`, but I’m extremely sketchy on the particulars there.
4. Track the fact that `content::WebContentsObserver::DidFailProvisionalLoad` was received on the C++ side, but don’t emit a JS event until some later time just before `content::WebContentsObserver::DidFinishLoad` is received. Not sure on the ideal point in time there.

atom/browser/api/atom_api_web_contents.cc
web_contents()->Undo();
}
void WebContents::Redo() {
  web_contents()->Redo();
}
void WebContents::Cut() {
  web_contents()->Cut();
}
void WebContents::Copy() {
  web_contents()->Copy();
}
void WebContents::Paste() {
  web_contents()->Paste();
}
void WebContents::PasteAndMatchStyle() {
  web_contents()->PasteAndMatchStyle();
}
void WebContents::Delete() {
  web_contents()->Delete();
}
void WebContents::SelectAll() {
  web_contents()->SelectAll();
}
void WebContents::Unselect() {