简体   繁体   English

JavaScript Promise:在链式函数中捕获错误

[英]JavaScript Promise : Catching errors within chained functions

I have a function that is used to add a record to the IndexDb database:我有一个 function 用于向 IndexDb 数据库添加记录:

async function addAsync(storeName, object) {
    return new Promise((res, rej) => {
        // openDatabaseAsync() is another reusable method to open the db.  That works fine.
        openDatabaseAsync().then(db => {
            var store = openObjectStore(db, storeName, 'readwrite');
            var addResult = store.add(JSON.parse(object));
            addResult.onsuccess = res;
            addResult.onerror = (e) => {
                console.log("addResult Error");
                throw e;
            };
        }).catch(e => {
            // Error from "throw e;" above NOT GETTING CAUGHT HERE!
            console.error("addAsync ERROR > ", e, storeName, object);
            rej(e);
        });
    })
}

If I try to add a duplicate key, then I expect:如果我尝试添加重复键,那么我期望:

addResult.onerror = (e) => {
    console.log("addResult Error");
    throw e;
}

to capture that.捕捉它。 It does.确实如此。

But then, I also expect my但是,我也期待我的

.catch(e => {
    // Error from "throw e;" above NOT GETTING CAUGHT HERE!
    console.error("addAsync ERROR > ", e, storeName, object);
    rej(e);
})

to catch that error.捕捉那个错误。 But instead I get an "uncaught" log.但相反,我得到了一个“未捕获”的日志。

Console output:控制台 output:

addResult Error
Uncaught Event {isTrusted: true, type: "error", target: IDBRequest, currentTarget: IDBRequest, eventPhase: 2, …}

Does that final .catch only handle exceptions from the openDatabaseAsync call?最后的.catch是否只处理来自openDatabaseAsync调用的异常? I would have thought now as it is chained to the .then .我现在会想到,因为它被链接到.then

In summary, here's what I would expect from the above code:总之,这是我对上述代码的期望:

  • If openDatabaseAsync() fails then I'm not catching that so the error would be sent to the caller of addAsync() .如果openDatabaseAsync()失败,那么我没有发现它,因此错误将被发送给addAsync()的调用者。
  • If .then fails then I expect the .catch to catch it, log the error and then reject the promise meaning that the called of addAsync() would need to handle that.如果.then失败,那么我希望.catch捕获它,记录错误,然后拒绝 promise 这意味着调用addAsync()需要处理它。

However, I would have thought that I should get the log from the line:但是,我原以为我应该从以下行获取日志:

console.error("addAsync ERROR > ", e, storeName, object);

before the reject is sent back to the caller of addAsync() , which may be unhandled at that point.在拒绝被发送回addAsync()的调用者之前,此时可能未处理。

Your approach would benefit form a larger overhaul.您的方法将受益于更大的检修。

  • Generally, don't write a function as async when it's not also using await .通常,当 function 不使用await时,不要将其编写为async
  • Don't use new Promise() for an operation that returns a promise, such as openDatabaseAsync() does.不要将new Promise()用于返回 promise 的操作,例如 openDatabaseAsync openDatabaseAsync() Return that promise, or switch to async/await .返回 promise,或切换到async/await
  • It would be useful to wrap IndexedDB operations so that they follow promise semantics.包装 IndexedDB 操作以便它们遵循 promise 语义会很有用。

On the example of IDBRequest :IDBRequest的例子中:

function promisifyIDBRequest(idbr) {
    return new Promise( (resolve, reject) => {
        idbr.onsuccess = () => resolve(idbr.result);
        idbr.onerror = (e) => reject(e.target.error);
    });
}

Now you can do this:现在你可以这样做:

async function addAsync(storeName, object) {
    const db = await openDatabaseAsync();
    const store = openObjectStore(db, storeName, 'readwrite');
    return promisifyIDBRequest(store.add(JSON.parse(object)));
}

Add a try/catch block if you want to handle errors inside of addAsync() .如果要处理addAsync()内部的错误,请添加 try/catch 块。

It's worth checking out existing solutions that wrap the entire IndexedDB interface with promise semantics, such as https://github.com/jakearchibald/idb .有必要检查一下现有的解决方案,这些解决方案使用 promise 语义来包装整个 IndexedDB 接口,例如https://github.com/jakearchibald/idb


FWIW, the promise-chain variant of the above function would look like this: FWIW,上述 function 的承诺链变体如下所示:

function addAsync(storeName, object) {
    return openDatabaseAsync().then( (db) => {
        const store = openObjectStore(db, storeName, 'readwrite');
        return promisifyIDBRequest(store.add(JSON.parse(object)));
    });
}

both variants return a promise for an IDBRequest result.两种变体都为 IDBRequest 结果返回 promise。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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