Merge pull request #7533 from electron/async-executeJavaScript
Allow web frame methods to return async promises
This commit is contained in:
commit
7e90bb47a5
5 changed files with 77 additions and 9 deletions
|
@ -620,12 +620,26 @@ Injects CSS into the current web page.
|
||||||
* `callback` Function (optional) - Called after script has been executed.
|
* `callback` Function (optional) - Called after script has been executed.
|
||||||
* `result` Any
|
* `result` Any
|
||||||
|
|
||||||
|
Returns `Promise` - A promise that resolves with the result of the executed code
|
||||||
|
or is rejected if the result of the code is a rejected promise.
|
||||||
|
|
||||||
Evaluates `code` in page.
|
Evaluates `code` in page.
|
||||||
|
|
||||||
In the browser window some HTML APIs like `requestFullScreen` can only be
|
In the browser window some HTML APIs like `requestFullScreen` can only be
|
||||||
invoked by a gesture from the user. Setting `userGesture` to `true` will remove
|
invoked by a gesture from the user. Setting `userGesture` to `true` will remove
|
||||||
this limitation.
|
this limitation.
|
||||||
|
|
||||||
|
If the result of the executed code is a promise the callback result will be the
|
||||||
|
resolved value of the promise. We recommend that you use the returned Promise
|
||||||
|
to handle code that results in a Promise.
|
||||||
|
|
||||||
|
```js
|
||||||
|
contents.executeJavaScript('fetch("https://jsonplaceholder.typicode.com/users/1").then(resp => resp.json())', true)
|
||||||
|
.then((result) => {
|
||||||
|
console.log(result) // Will be the JSON object from the fetch call
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
#### `contents.setAudioMuted(muted)`
|
#### `contents.setAudioMuted(muted)`
|
||||||
|
|
||||||
* `muted` Boolean
|
* `muted` Boolean
|
||||||
|
|
|
@ -110,9 +110,16 @@ const webFrameMethodsWithResult = [
|
||||||
]
|
]
|
||||||
|
|
||||||
const asyncWebFrameMethods = function (requestId, method, callback, ...args) {
|
const asyncWebFrameMethods = function (requestId, method, callback, ...args) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
this.send('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', requestId, method, args)
|
this.send('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', requestId, method, args)
|
||||||
ipcMain.once(`ELECTRON_INTERNAL_BROWSER_ASYNC_WEB_FRAME_RESPONSE_${requestId}`, function (event, result) {
|
ipcMain.once(`ELECTRON_INTERNAL_BROWSER_ASYNC_WEB_FRAME_RESPONSE_${requestId}`, function (event, error, result) {
|
||||||
if (callback) callback(result)
|
if (error == null) {
|
||||||
|
if (callback != null) callback(result)
|
||||||
|
resolve(result)
|
||||||
|
} else {
|
||||||
|
reject(error)
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,10 +153,12 @@ WebContents.prototype.executeJavaScript = function (code, hasUserGesture, callba
|
||||||
hasUserGesture = false
|
hasUserGesture = false
|
||||||
}
|
}
|
||||||
if (this.getURL() && !this.isLoadingMainFrame()) {
|
if (this.getURL() && !this.isLoadingMainFrame()) {
|
||||||
asyncWebFrameMethods.call(this, requestId, 'executeJavaScript', callback, code, hasUserGesture)
|
return asyncWebFrameMethods.call(this, requestId, 'executeJavaScript', callback, code, hasUserGesture)
|
||||||
} else {
|
} else {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
this.once('did-finish-load', () => {
|
this.once('did-finish-load', () => {
|
||||||
asyncWebFrameMethods.call(this, requestId, 'executeJavaScript', callback, code, hasUserGesture)
|
asyncWebFrameMethods.call(this, requestId, 'executeJavaScript', callback, code, hasUserGesture).then(resolve).catch(reject)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,10 +39,16 @@ electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_SYNC_WEB_FRAME_METHOD', (eve
|
||||||
|
|
||||||
electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', (event, requestId, method, args) => {
|
electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', (event, requestId, method, args) => {
|
||||||
const responseCallback = function (result) {
|
const responseCallback = function (result) {
|
||||||
event.sender.send(`ELECTRON_INTERNAL_BROWSER_ASYNC_WEB_FRAME_RESPONSE_${requestId}`, result)
|
Promise.resolve(result)
|
||||||
|
.then((resolvedResult) => {
|
||||||
|
event.sender.send(`ELECTRON_INTERNAL_BROWSER_ASYNC_WEB_FRAME_RESPONSE_${requestId}`, null, resolvedResult)
|
||||||
|
})
|
||||||
|
.catch((resolvedError) => {
|
||||||
|
event.sender.send(`ELECTRON_INTERNAL_BROWSER_ASYNC_WEB_FRAME_RESPONSE_${requestId}`, resolvedError)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
args.push(responseCallback)
|
args.push(responseCallback)
|
||||||
electron.webFrame[method].apply(electron.webFrame, args)
|
electron.webFrame[method](...args)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Process command line arguments.
|
// Process command line arguments.
|
||||||
|
|
|
@ -1462,7 +1462,10 @@ describe('browser-window module', function () {
|
||||||
|
|
||||||
describe('window.webContents.executeJavaScript', function () {
|
describe('window.webContents.executeJavaScript', function () {
|
||||||
var expected = 'hello, world!'
|
var expected = 'hello, world!'
|
||||||
var code = '(() => "' + expected + '")()'
|
var expectedErrorMsg = 'woops!'
|
||||||
|
var code = `(() => "${expected}")()`
|
||||||
|
var asyncCode = `(() => new Promise(r => setTimeout(() => r("${expected}"), 500)))()`
|
||||||
|
var badAsyncCode = `(() => new Promise((r, e) => setTimeout(() => e("${expectedErrorMsg}"), 500)))()`
|
||||||
|
|
||||||
it('doesnt throw when no calback is provided', function () {
|
it('doesnt throw when no calback is provided', function () {
|
||||||
const result = ipcRenderer.sendSync('executeJavaScript', code, false)
|
const result = ipcRenderer.sendSync('executeJavaScript', code, false)
|
||||||
|
@ -1477,6 +1480,38 @@ describe('browser-window module', function () {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('returns result if the code returns an asyncronous promise', function (done) {
|
||||||
|
ipcRenderer.send('executeJavaScript', asyncCode, true)
|
||||||
|
ipcRenderer.once('executeJavaScript-response', function (event, result) {
|
||||||
|
assert.equal(result, expected)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('resolves the returned promise with the result', function (done) {
|
||||||
|
ipcRenderer.send('executeJavaScript', code, true)
|
||||||
|
ipcRenderer.once('executeJavaScript-promise-response', function (event, result) {
|
||||||
|
assert.equal(result, expected)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('resolves the returned promise with the result if the code returns an asyncronous promise', function (done) {
|
||||||
|
ipcRenderer.send('executeJavaScript', asyncCode, true)
|
||||||
|
ipcRenderer.once('executeJavaScript-promise-response', function (event, result) {
|
||||||
|
assert.equal(result, expected)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('rejects the returned promise if an async error is thrown', function (done) {
|
||||||
|
ipcRenderer.send('executeJavaScript', badAsyncCode, true)
|
||||||
|
ipcRenderer.once('executeJavaScript-promise-error', function (event, error) {
|
||||||
|
assert.equal(error, expectedErrorMsg)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
it('works after page load and during subframe load', function (done) {
|
it('works after page load and during subframe load', function (done) {
|
||||||
w.webContents.once('did-finish-load', function () {
|
w.webContents.once('did-finish-load', function () {
|
||||||
// initiate a sub-frame load, then try and execute script during it
|
// initiate a sub-frame load, then try and execute script during it
|
||||||
|
|
|
@ -173,6 +173,10 @@ app.on('ready', function () {
|
||||||
if (hasCallback) {
|
if (hasCallback) {
|
||||||
window.webContents.executeJavaScript(code, (result) => {
|
window.webContents.executeJavaScript(code, (result) => {
|
||||||
window.webContents.send('executeJavaScript-response', result)
|
window.webContents.send('executeJavaScript-response', result)
|
||||||
|
}).then((result) => {
|
||||||
|
window.webContents.send('executeJavaScript-promise-response', result)
|
||||||
|
}).catch((err) => {
|
||||||
|
window.webContents.send('executeJavaScript-promise-error', err)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
window.webContents.executeJavaScript(code)
|
window.webContents.executeJavaScript(code)
|
||||||
|
|
Loading…
Reference in a new issue