简体   繁体   中英

error creating a bluebird promise with requirejs for chrome extension

I am developing a chrome extension that makes use of 'chrome.storage.local' and am trying to create a promise out of the chrome.storage.local.get() async function, which I would like to be able to throw exceptions from as well as reject/resolve. I've tried testing this with the below implementation, but am seeing an error which from the console logs seems to be from the " readLocalStorageObj("prefs").then(function(item) { " line (the error is shown below after the code).

require([
    "libs/bluebird"
],
function(Promise) {
    function readLocalStorageObj(itemName) {
        var localReadResult = Promise.method(function(item) {
            console.log("localReadResult():", item);
            // if (chrome.runtime.lastError) {
            //  throw new Error(chrome.runtime.lastError);
            // }

            if (Object.getOwnPropertyNames(item).length > 0) {
                console.log('in if part');
                return item;
            }
            else {
                console.log('in else part');
                // throw new Error("my test exception");
                return undefined;
            }
        });

        chrome.storage.local.get(itemName, localReadResult);
        return localReadResult;
    };

    readLocalStorageObj("prefs").then(function(item) {
        console.log('success', item);
    }, function(e) {
        console.log('fail', e);
    }).error(function(e) {
        console.log('error', e);
    }).catch(ChromeRuntimeError, function(e) {
        console.log('catch', e);
    }).finally(function(a) {
        console.log('finally', a);
    });
});

Error:

Uncaught TypeError: Object function Promise$_method() { var value; switch(arguments.length) { case 0: value = tryCatch1(fn, this, void 0); break; case 1: value = tryCatch1(fn, this, arguments[0]); break; case......n'

I can't quite seem to figure out what the cause for this is ,and would really appreciate any help with this.

TIA

Try creating the promise like this:

require([
    "libs/bluebird"
],
function(Promise) {
    function readLocalStorageObj(itemName) {
        return new Promise(function(resolve, reject) {
            chrome.storage.local.get(itemName, function(item) {
                if (chrome.runtime.lastError) {
                    return reject(chrome.runtime.lastError);
                }

                if (Object.getOwnPropertyNames(item).length > 0) {
                    return resolve(item);
                }
                reject(new Error("empty item"));
            });
        });
    }

    readLocalStorageObj("prefs").then(function(item) {
        console.log('success', item);
    }, function(e) {
        console.log('fail', e);
    }).error(function(e) {
        console.log('error', e);
    }).catch(ChromeRuntimeError, function(e) {
        console.log('catch', e);
    }).finally(function(a) {
        console.log('finally', a);
    });
});

However if you need to use promises with extension callback conventions a lot this will result in a lot of boilerplate.

To avoid boilerplate, you can define a generic promisification function for this convention:

function promisfyChrome(fn, ctx) {
    return function() {
        var args = [].slice.call(arguments);
        var self = ctx || this;
        return new Promise(function(resolve, reject) {
            args.push(function(value) {
                if (chrome.runtime.lastError)
                    return reject(chrome.runtime.lastError);
                resolve(value);
            });
            fn.apply(self, args);
        })
    };
}

Usage:

require([
    "libs/bluebird"
],
function(Promise) {
    var chromeLocalStorageGet = promisifyChrome(chrome.storage.local.get, chrome.storage.local);
    function readLocalStorageObj(itemName) {
        return chromeLocalStorageGet(itemName).then(function(item) {
            if (Object.getOwnPropertyNames(item).length > 0) {
                return item;
            }
            throw new Error("empty item");
        });
    }

    readLocalStorageObj("prefs").then(function(item) {
        console.log('success', item);
    }, function(e) {
        console.log('fail', e);
    }).error(function(e) {
        console.log('error', e);
    }).catch(ChromeRuntimeError, function(e) {
        console.log('catch', e);
    }).finally(function(a) {
        console.log('finally', a);
    });
});

Btw:

    readLocalStorageObj("prefs").then(function(item) {
        console.log('success', item);
    }, function(e) {
        console.log('fail', e);
    }).error(function(e) {
        console.log('error', e);
    }).catch(ChromeRuntimeError, function(e) {
        console.log('catch', e);
    }).finally(function(a) {
        console.log('finally', a);
    });

Is in this case equivalent to:

    readLocalStorageObj("prefs").then(function(item) {
        console.log('success', item);
    }).catch(Error, function(e) {
        console.log('fail', e);
    }).error(function(e) {
        console.log('error', e);
    }).catch(ChromeRuntimeError, function(e) {
        console.log('catch', e);
    }).finally(function(a) {
        console.log('finally', a);
    });

As you can see the first catch already catches any kind of error so the other catches are never triggered. You will want to do it in the opposite way - more specific catch handlers first and more general ones last.

Also, using .then with 2 functions is really hard to read so it's not recommended. Prefer .then(fn).catch(fn2) over .then(fn, fn2)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM