All Projects → KeithHenry → Chromeextensionasync

KeithHenry / Chromeextensionasync

Licence: mit
Promise wrapper for the Chrome extension API so that it can be used with async/await rather than callbacks

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to Chromeextensionasync

Floccus
☁️ Sync your bookmarks privately across browsers
Stars: ✭ 2,630 (+1313.98%)
Mutual labels:  chrome-extension, chrome
Headless Recorder
Chrome extension that records your browser interactions and generates a Playwright or Puppeteer script.
Stars: ✭ 13,786 (+7311.83%)
Mutual labels:  chrome-extension, chrome
My Notes
Simple and fast note-taking in Chrome with Google Drive support.
Stars: ✭ 155 (-16.67%)
Mutual labels:  chrome-extension, chrome
Awesome Chrome Extension Boilerplate
Use react + typescript + webpack to enhance your chrome extension development experience
Stars: ✭ 146 (-21.51%)
Mutual labels:  chrome-extension, chrome
Nim
Streamline Your Node.js Debugging Workflow with Chromium (Chrome, Edge, More) DevTools.
Stars: ✭ 168 (-9.68%)
Mutual labels:  chrome-extension, chrome
Disable Javascript
Adds the ability to disable JavaScript on specific sites.
Stars: ✭ 151 (-18.82%)
Mutual labels:  chrome-extension, chrome
Replacegooglecdn
♋ 一个 Chrome 插件:将 Google CDN 替换为国内的。
Stars: ✭ 2,400 (+1190.32%)
Mutual labels:  chrome-extension, chrome
Synology Download Manager
An open source browser extension for adding/managing download tasks to your Synology DiskStation.
Stars: ✭ 138 (-25.81%)
Mutual labels:  chrome-extension, chrome
Anna
Virtual Assistant on Google Chrome 🐘
Stars: ✭ 165 (-11.29%)
Mutual labels:  chrome-extension, chrome
Buttercup Browser Extension
🌏 Buttercup browser extension
Stars: ✭ 164 (-11.83%)
Mutual labels:  chrome-extension, chrome
Chromium Vim
Vim bindings for Google Chrome.
Stars: ✭ 2,150 (+1055.91%)
Mutual labels:  chrome-extension, chrome
Github Mermaid Extension
A browser extension for Chrome, Opera & Firefox that adds Mermaid language support to Github
Stars: ✭ 170 (-8.6%)
Mutual labels:  chrome-extension, chrome
Notes
📔 Linux、MySQL、Nginx、PHP、Git、Shell 等笔记
Stars: ✭ 1,835 (+886.56%)
Mutual labels:  chrome-extension, chrome
Chrome Extensions Reloader
A chrome extension for reloading unpacked extensions
Stars: ✭ 154 (-17.2%)
Mutual labels:  chrome-extension, chrome
Timecat
A Magical Web Recorder & Player 🖥
Stars: ✭ 1,955 (+951.08%)
Mutual labels:  chrome-extension, chrome
React Rewind
Time Travel Debugger for React useReducer
Stars: ✭ 159 (-14.52%)
Mutual labels:  chrome-extension, chrome
Whatsapp Bulk Sender
Send bulk messages right from your WhatsApp Android Client or WhatsApp Web
Stars: ✭ 135 (-27.42%)
Mutual labels:  chrome-extension, chrome
Surfingkeys Conf
A SurfingKeys configuration which adds 130+ key mappings for 20+ sites & OmniBar search suggestions for 50+ sites
Stars: ✭ 137 (-26.34%)
Mutual labels:  chrome-extension, chrome
Sponsorblock
Skip YouTube video sponsors (browser extension)
Stars: ✭ 3,627 (+1850%)
Mutual labels:  chrome-extension, chrome
Vue Chrome Extension Boilerplate
Boilerplate for Chrome extension using Vue.js and Webpack with auto-reload enabled.
Stars: ✭ 171 (-8.06%)
Mutual labels:  chrome-extension, chrome

Chrome Extension Async

npm version bower version

Promise wrapper for the Chrome extension API so that it can be used with async/await rather than callbacks

The Extension API provided by Chrome uses callbacks. However, Chrome now supports async and await keywords.

This library wraps Chrome extension API callback methods in promises, so that they can be called with async and await.

Once activated against the Chrome API each callback function gets a Promise version.

Chrome supports ES2017 syntax, so in extensions we can take full advantage of it.

Installation

Use bower

bower install chrome-extension-async

Or npm

npm i chrome-extension-async

Or download chrome-extension-async.js file and include it directly:

<script type="text/javascript" src="chrome-extension-async.js"></script>

TypeScript definitions for the altered API are in chrome-extension-async.d.ts

You must reference chrome-extension-async.js before your code attempts to use the features of this, as it needs to run across the Chrome API before you call it. <script async> is not currently supported, but you can use <script defer> so long as the scripts that use this are also defer and after it.

Examples

Using the basic Chrome API, let's:

  • Get the current active tab
  • Execute a script in that tab
  • Do something with the first result of the script
function startDoSomething(script, callback) {
    // Fire off the tabs query and continue in the callback
    chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {

        // Check API for any errors thrown
        if (chrome.runtime.lastError) {
            // Handle errors from chrome.tabs.query
        }
        else {
            var activeTab = tabs[0];

            // Fire off the injected script and continue in the callback
            chrome.tabs.executeScript(activeTab.id, { code: script }, function(results) {

                // Check API for any errors thrown, again
                if (chrome.runtime.lastError) {
                    // Handle errors from chrome.tabs.executeScript
                }
                else {
                    var firstScriptResult = results[0];
                    callback(firstScriptResult);
                }
            });
        }
    });
}

This works, but the nested callbacks are painful to debug and maintain, and they can quickly lead to 'callback hell'.

Instead, with this library, we can use await:

async function doSomething(script) {
    try {
        // Query the tabs and continue once we have the result
        const tabs = await chrome.tabs.query({ active: true, currentWindow: true });
        const activeTab = tabs[0];

        // Execute the injected script and continue once we have the result
        const results = await chrome.tabs.executeScript(activeTab.id, { code: script });
        const firstScriptResult = results[0];
        return firstScriptResult;
    }
    catch(err) {
        // Handle errors from chrome.tabs.query, chrome.tabs.executeScript or my code
    }
}

// If you want to use the same callback you can use Promise syntax too:
doSomething(script).then(callback);

Some callbacks take multiple parameters - in these cases the Promise will be a combined object:

async function checkUpdate() {
    try {
        // API is chrome.runtime.requestUpdateCheck(function (status, details) { ... });
        // Instead we use deconstruction-assignment and await
        const { status, details } = await chrome.runtime.requestUpdateCheck();
        alert(`Status: ${status}\nDetails: ${JSON.stringify(details)}`);
    }
    catch(err) {
        // Handle errors from chrome.runtime.requestUpdateCheck or my code
    }
}

This also includes a check against chrome.runtime.lastError, so that you can use try-catch to get exceptions thrown from the Chrome API.

Event Listener API

These are not included. For instance chrome.browserAction.onClicked.addListener takes a callback function, but executes it every time the event fires. It is not suitable for a Promise or async call.

Execute Injected Scripts Asynchronously With chrome.tabs.executeAsyncFunction

New in v3.2 is chrome.tabs.executeAsyncFunction, an enhancement to the tabs API that allows a popup or browser/page action to easily execute asynchronous code in a page. This:

  • Adds chrome.runtime.sendMessage to the injected script to return the result.
  • Uses chrome.runtime.onMessage.addListener to listen for the injected event.
  • Fires the script with chrome.tabs.executeScript.
  • Wraps the whole thing in a promise that resolves with the final result.
  • Adds all the relevant error handling by rejecting the promise.
const scriptToExecute = async function() {
    // await promises in the tab
}

try {
    // The await returns the complete result of the function
    const results = await chrome.tabs.executeAsyncFunction(
        activeTab.id,       // If null this will be the current tab
        scriptToExecute,    // Will be .toString and applied to the {code:} property
        123, 'foo');        // Additional parameters will be passed to scriptToExecute

    // results now holds the output of the asynchronous code run in the page
}
catch(err) {
    // Any error either setting up or executing the script
    // Note that errors from the page will be re-thrown copies
}

chrome.tabs.executeAsyncFunction can take a function, string, or executeScript details with the code property set. The script must be async or return a Promise. Details with a file property are not supported. Scripts that output multiple values are not supported.

Unlike chrome.tabs.executeScript this can take a function, but note that it just converts the function to a string to pass it. This means that it must be self contained (it cannot call other user defined functions) and it cannot be native (as many serialise to function foobar() { [native code] }).

This is held in its own file: execute-async-function.js:

<script type="text/javascript" src="execute-async-function.js"></script>

This relies on a chrome.runtime.onMessage.addListener subscription, so it will fail if called from within a listener event.

Create and Reload Tabs with chrome.tabs.createAndWait and chrome.tabs.reloadAndWait

New in v3.4 is chrome.tabs.createAndWait and chrome.tabs.reloadAndWait. The normal chrome.tabs.create and chrome.tabs.reload functions execute their callbacks as soon as the tab is created, before the tab has finished loading. This makes it difficult to create or reload a tab, and then execute a content script on the page. chrome.tabs.createAndWait and chrome.tabs.reloadAndWait are an enhancement to the tabs API that waits until the tab has finished loading the url, and is ready to execute scripts. They pair great with chrome.tabs.executeAsyncFunction.

They:

  • Call chrome.tabs.create or chrome.tabs.reload, await the results, and grab the tab's id.
  • Use chrome.tabs.onUpdated.addListener to listen for the 'completed' status for the tab's id.
  • Wrap the whole thing in a promise that resolves with the final result.
  • Use chrome.tabs.onRemoved.addListener and chrome.tabs.onReplaced.addListener to detect if the tab is removed or replaced before the loading finishes, and rejects the promise with an Error.
  • Use an auto-timeout feature. If the page doesn't load in the specified milliseconds, or one of the three listeners is never called, the promise will be rejected with an Error. The value of the timeout is configurable with an optional parameter. The default value is 12e4 milliseconds (2 minutes).

chrome.tabs.createAndWait takes in the same parameters as chrome.tabs.create except for the callback, and returns an object containing the same properties as the parameters passed to the callback for the chrome.tabs.onUpdated event.

try {
    // Create a new tab and wait for it to finish loading.  The url will take 5 seconds to finish loading.
    // Try closing the tab before it finishes loading, and you will see the error.
    const {tabId, changeInfo, tab} = await chrome.tabs.createAndWait({ url: "http://www.mocky.io/v2/5d59a32e3000006c2ed84c7a?mocky-delay=5000ms", active:true });
    // Now that it is finished loading, it is ready to execute content scripts.
    const scriptResults = await chrome.tabs.executeAsyncFunction(tab.id, () => { alert('The tab finished loading.');} );
    // Voila!  In two lines you've created a new tab, and executed a content script on it!
}
catch (err) {
    alert(err);
}

chrome.tabs.reloadAndWait takes in the same parameters as chrome.tabs.reload except for the callback, and returns an object containing the same properties as the parameters passed to the callback for the chrome.tabs.onUpdated event.

try {
  // Get the current tab.
  const tabs = await chrome.tabs.query({active: true, currentWindow: true});
  const currentTab = tabs[0];
  // The second parameter, reloadProperties is optional, and here it is omitted.
  const {tabId, changeInfo, tab} = await chrome.tabs.reloadAndWait(currentTab.id);
  const scriptResults = await chrome.tabs.executeAsyncFunction(tab.id, () => { alert('The tab finished reloading.');} );
}
catch (err) {
  alert(err);
}

These functions are held in: execute-async-function.js

Supported APIs

This only 'promisifies' API functions that use callbacks and are not marked as deprecated. No backwards compatibility is attempted.

Each API is added manually as JS can't spot deprecated or functions with no callbacks itself.

Supported API:

Pull requests with additional API gratefully received.

ES5 Build

Note that you can use an ES5 build version of "Chrome Extension Async".

execute-async-function.es5.js

Sometimes your application has a build process that requires you to use 3rd party libraries that published with ES5 code.
For example, create-react-app will break the build and minification process if one of your dependencies is not published as standard ES5 code.

Release Notes

v3.4

v3.4 adds chrome.tabs.createAndWait and chrome.tabs.reloadAndWait; this is backwards compatible and opt-in functionality.

v3.4.1

Fixes an issue with the timeout message.

v3.3

v3.3 adds execute-async-function.es5.js transpiled ES5 version for toolchains that depend on the older JS syntax.

v3.3.1

This addresses a breaking change in chrome.storage and fixes TypeError: Illegal invocation: Function must be called on an object of type StorageArea exceptions.

v3.3.2

Fixed bug calling chrome.identity.getRedirectURL

v3.2

v3.2 adds chrome.tabs.executeAsyncFunction; this is backwards compatible and opt-in functionality.

v3 Changes

v3 introduces a breaking change from v1 and v2: now the original Chrome API is wrapped by an identical method that can be called with either old or new syntax. Callbacks can still be used on the same methods, and will fire before the promise resolves. Any error thrown inside the callback function will cause the promise to reject.

You can use both a callback and await if you want to work with existing API code, but also want the try-catch support:

async function startDoSomethingHybrid(callback) {
    try{
        // Using await means any exception is passed to the catch, even from the callback
        await chrome.tabs.query({ active: true, currentWindow: true }, tabs => callback(tabs[0]));
    }
    catch(err) {
        // Handle errors thrown by the API or by the callback
    }
}

Older versions added a ...Async suffix to either the function (2.0.0) or the API class (1.0.0). These are still available on bower (but not npm) and are not maintained.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].