【问题标题】:error creating a bluebird promise with requirejs for chrome extension使用 requirejs 为 chrome 扩展创建蓝鸟承诺时出错
【发布时间】:2014-03-20 15:39:55
【问题描述】:

我正在开发一个使用 'chrome.storage.local' 的 chrome 扩展程序,并试图从 chrome.storage.local.get() 异步函数中创建一个承诺,我希望能够做到抛出异常以及拒绝/解决。我已尝试使用以下实现对此进行测试,但我看到控制台日志中出现的错误似乎来自“readLocalStorageObj("prefs").then(function(item) {”行(错误显示在代码后面)。

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);
    });
});

错误:

未捕获的类型错误:对象函数 Promise$_method() { 变量值; 开关(参数。长度){ 案例 0:值 = tryCatch1(fn, this, void 0);休息; 案例 1: value = tryCatch1(fn, this, arguments[0]);休息; 案例......n'

我似乎无法弄清楚这是什么原因,并且非常感谢任何帮助。

TIA

【问题讨论】:

  • 你想做什么?在这种情况下使用 Promise.method 没有意义。
  • 我基本上是在尝试从异步读取 chrome.storage API 中获取 Promise。关于在这种情况下如何获得 Promise 的任何其他建议?

标签: javascript google-chrome-extension requirejs bluebird


【解决方案1】:

尝试像这样创建承诺:

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);
    });
});

但是,如果您需要大量使用带有扩展回调约定的 Promise,这将导致大量样板文件。

为了避免样板,您可以为此约定定义一个通用的 Promisification 函数:

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);
        })
    };
}

用法:

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);
    });
});

顺便说一句:

    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);
    });

在这种情况下等同于:

    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);
    });

如您所见,第一个 catch 已经捕获任何类型的错误,因此其他捕获永远不会触发。您将希望以相反的方式执行此操作 - 首先是更具体的捕获处理程序,最后是更通用的捕获处理程序。

另外,将.then 与两个函数一起使用确实很难阅读,因此不推荐。更喜欢.then(fn).catch(fn2) 而不是.then(fn, fn2)

【讨论】:

  • 我最初使用的是类似的东西,但是 catch() 块似乎从未被调用(正如我提到的,我想区分异常和显式失败)。例如当我抛出一个新的 TypeError("empty item") 时,它有点默默地失败了。只有拒绝和解决似乎有效。知道为什么吗?
  • @source.rar .error().catch([ExplicitRejection], function(e){ 相同,因此它已经有资格捕获显式 reject(chrome.runtime) 调用。如果您不希望它被视为隐式,请执行throw chrome.runtime
  • @source.rar 没关系,我只是注意到你在第一个 .then 中有一个包罗万象的处理程序。这真的很难注意到 - 我建议您在使用 .then 时不要同时使用 2 个处理程序,而只使用单独的 .catch。无论如何 - 捕获所有处理程序正在处理所有异常,因此永远不会触发 .error().catch(ChromeRuntimeError)
  • 总之,您指的是拒绝处理程序吗?如果是这样,那不就是拒绝处理程序而不是包罗万象吗?如果我理解正确,catch(function(e){}) 将是一个链接到上述内容的 catch(function(e){})?
  • @source.rar 是的,我还在底部编辑了我的答案希望它有帮助
猜你喜欢
  • 2015-08-28
  • 1970-01-01
  • 2015-09-06
  • 1970-01-01
  • 1970-01-01
  • 2018-01-10
  • 2014-11-08
  • 1970-01-01
相关资源
最近更新 更多