无法使用 redux-saga 捕获错误? (同时通过 react-native-firestore 调用 firestore)
Unable to catch error using redux-saga? (while making a firestore call via react-native-firestore)
下面的代码是否是使用 call 或 fork 解决 redux-saga 中 "catch" 错误的正确方法?那就是当我有 "createItem" 函数时,这里不捕获任何错误是否正确,并假设这会将任何异常返回给生成器函数 "createItemSaga" 以捕获?
这里的第二个问题是我注意到我收到了返回的 firestore 错误(我使用的是 react-native-firebase),但是我没有用这段代码捕捉到它。请参阅下面的控制台输出。我创建了一个安全规则来拒绝在 firestore 后端创建一个项目来测试这个的尝试。
function createItem(item) {
firebase.firestore().collection('todos').add(item);
}
export function* createItemSaga() {
while (true) {
const action = yield take(ActionTypes.AddListItem_UIRequest);
console.log('createItemSaga: received AddListItem_UIRequest');
const { item } = action;
yield put({ type: ActionTypes.AddListItemRequested });
try {
console.log('createItemSaga: createItem Start');
yield fork(createItem, item);
console.log('createItemSaga: createItem Ended'); // <-- This is reached! But why.
} catch (e) {
console.log('createItemSaga: error caught. Error='); <-- Why isn't this point reached
console.log(pf(e));
yield put({ type: ActionTypes.AddListItemRejected });
}
}
}
控制台输出为:
createItemSaga: recived AddListItem_UIRequest
createItemSaga: createItem Start
createItemSaga: createItem Ended
Possible Unhandled Promise Rejection (id: 0):
Error: Firestore: The caller does not have permission to execute the specified operation. (firestore/permission-denied).
Error: Firestore: The caller does not have permission to execute the specified operation. (firestore/permission-denied).
at createErrorFromErrorData (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1822:15)
at /Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1775:25
at MessageQueue.__invokeCallback (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:2133:16)
at /Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1950:16
at MessageQueue.__guard (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:2068:9)
at MessageQueue.invokeCallbackAndReturnFlushedQueue (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1949:12)
at /Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/debuggerWorker.js:126:58
at process.<anonymous> (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/debuggerWorker.js:35:9)
at emitTwo (events.js:125:13)
at process.emit (events.js:213:7)
注意:这里是否提出了与此库相关的潜在问题:https://github.com/invertase/react-native-firebase/issues/727
补充说明:
- 如果我在 "yield fork(createItem, item);"
行中使用 "call" 而不是 "fork",我会得到相同的结果
- 如果我像下面这样在生成中合并更新尝试,我也会得到相同的结果:
代码:
export function* createItemSaga() {
while (true) {
const action = yield take(ActionTypes.AddListItem_UIRequest);
const { item } = action;
yield put({ type: ActionTypes.AddListItemRequested });
try {
console.log('createItemSaga: createItem Start');
firebase.firestore().collection('todos').add(item);
console.log('createItemSaga: createItem Ended');
} catch (e) {
console.log('createItemSaga: error caught. Error=');
console.log(pf(e));
yield put({ type: ActionTypes.AddListItemRejected });
}
}
}
补充说明 2:
- 将 "createItem" 函数转换为生成器时得到相同的结果:
代码:
export function* createItem(item) {
try {
console.log('createItem: Start');
firebase.firestore().collection('todos').add(item);
console.log('createItem: End');
} catch (e) {
console.log('createItem: error');
console.log(pf(e));
}
}
export function* createItemSaga() {
while (true) {
const action = yield take(ActionTypes.AddListItem_UIRequest);
const { item } = action;
yield put({ type: ActionTypes.AddListItemRequested });
try {
console.log('createItemSaga: createItem Start');
yield call(createItem, item);
console.log('createItemSaga: createItem Ended');
} catch (e) {
console.log('createItemSaga: error caught. Error=');
console.log(pf(e));
yield put({ type: ActionTypes.AddListItemRejected });
}
}
}
控制台:
createItemSaga: createItem Start
createItem: Start
createItem: End
createItemSaga: createItem Ended
Possible Unhandled Promise Rejection (id: 0):
Error: Firestore: The caller does not have permission to execute the specified operation. (firestore/permission-denied).
Error: Firestore: The caller does not have permission to execute the specified operation. (firestore/permission-denied).
at createErrorFromErrorData (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1822:15)
at /Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1775:25
at MessageQueue.__invokeCallback (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:2133:16)
at /Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1950:16
at MessageQueue.__guard (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:2068:9)
at MessageQueue.invokeCallbackAndReturnFlushedQueue (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1949:12)
at /Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/debuggerWorker.js:126:58
at process.<anonymous> (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/debuggerWorker.js:35:9)
at emitTwo (events.js:125:13)
at process.emit (events.js:213:7)
首先我认为createItem
应该是一个生成器(或者换句话说是一个saga)。然后你不需要 fork
但 call
。那是因为 fork
没有阻塞而 call
是。这就是您获取控制台日志的原因。我想如果 createItem
是一个生成器,你的 try-catch
块就会工作。
使用 createItem 作为一个单独的函数没有得到它的工作,但是现在我通过按照以下将所有内容收缩到一个生成器中来捕获错误:
export function* createItemSaga() {
while (true) {
const action = yield take(ActionTypes.AddListItem_UIRequest);
const { item } = action;
yield put({ type: ActionTypes.AddListItemRequested });
try {
const ref = firebase.firestore().collection('todos');
yield call([ref, ref.add], item);
yield put({ type: ActionTypes.AddListItemFulfilled });
} catch (e) {
console.log('createItemSaga: error caught. Error=');
console.log(pf(e));
yield put({ type: ActionTypes.AddListItemRejected });
}
}
}
下面的代码是否是使用 call 或 fork 解决 redux-saga 中 "catch" 错误的正确方法?那就是当我有 "createItem" 函数时,这里不捕获任何错误是否正确,并假设这会将任何异常返回给生成器函数 "createItemSaga" 以捕获?
这里的第二个问题是我注意到我收到了返回的 firestore 错误(我使用的是 react-native-firebase),但是我没有用这段代码捕捉到它。请参阅下面的控制台输出。我创建了一个安全规则来拒绝在 firestore 后端创建一个项目来测试这个的尝试。
function createItem(item) {
firebase.firestore().collection('todos').add(item);
}
export function* createItemSaga() {
while (true) {
const action = yield take(ActionTypes.AddListItem_UIRequest);
console.log('createItemSaga: received AddListItem_UIRequest');
const { item } = action;
yield put({ type: ActionTypes.AddListItemRequested });
try {
console.log('createItemSaga: createItem Start');
yield fork(createItem, item);
console.log('createItemSaga: createItem Ended'); // <-- This is reached! But why.
} catch (e) {
console.log('createItemSaga: error caught. Error='); <-- Why isn't this point reached
console.log(pf(e));
yield put({ type: ActionTypes.AddListItemRejected });
}
}
}
控制台输出为:
createItemSaga: recived AddListItem_UIRequest
createItemSaga: createItem Start
createItemSaga: createItem Ended
Possible Unhandled Promise Rejection (id: 0):
Error: Firestore: The caller does not have permission to execute the specified operation. (firestore/permission-denied).
Error: Firestore: The caller does not have permission to execute the specified operation. (firestore/permission-denied).
at createErrorFromErrorData (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1822:15)
at /Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1775:25
at MessageQueue.__invokeCallback (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:2133:16)
at /Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1950:16
at MessageQueue.__guard (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:2068:9)
at MessageQueue.invokeCallbackAndReturnFlushedQueue (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1949:12)
at /Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/debuggerWorker.js:126:58
at process.<anonymous> (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/debuggerWorker.js:35:9)
at emitTwo (events.js:125:13)
at process.emit (events.js:213:7)
注意:这里是否提出了与此库相关的潜在问题:https://github.com/invertase/react-native-firebase/issues/727
补充说明:
- 如果我在 "yield fork(createItem, item);" 行中使用 "call" 而不是 "fork",我会得到相同的结果
- 如果我像下面这样在生成中合并更新尝试,我也会得到相同的结果:
代码:
export function* createItemSaga() {
while (true) {
const action = yield take(ActionTypes.AddListItem_UIRequest);
const { item } = action;
yield put({ type: ActionTypes.AddListItemRequested });
try {
console.log('createItemSaga: createItem Start');
firebase.firestore().collection('todos').add(item);
console.log('createItemSaga: createItem Ended');
} catch (e) {
console.log('createItemSaga: error caught. Error=');
console.log(pf(e));
yield put({ type: ActionTypes.AddListItemRejected });
}
}
}
补充说明 2:
- 将 "createItem" 函数转换为生成器时得到相同的结果:
代码:
export function* createItem(item) {
try {
console.log('createItem: Start');
firebase.firestore().collection('todos').add(item);
console.log('createItem: End');
} catch (e) {
console.log('createItem: error');
console.log(pf(e));
}
}
export function* createItemSaga() {
while (true) {
const action = yield take(ActionTypes.AddListItem_UIRequest);
const { item } = action;
yield put({ type: ActionTypes.AddListItemRequested });
try {
console.log('createItemSaga: createItem Start');
yield call(createItem, item);
console.log('createItemSaga: createItem Ended');
} catch (e) {
console.log('createItemSaga: error caught. Error=');
console.log(pf(e));
yield put({ type: ActionTypes.AddListItemRejected });
}
}
}
控制台:
createItemSaga: createItem Start
createItem: Start
createItem: End
createItemSaga: createItem Ended
Possible Unhandled Promise Rejection (id: 0):
Error: Firestore: The caller does not have permission to execute the specified operation. (firestore/permission-denied).
Error: Firestore: The caller does not have permission to execute the specified operation. (firestore/permission-denied).
at createErrorFromErrorData (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1822:15)
at /Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1775:25
at MessageQueue.__invokeCallback (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:2133:16)
at /Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1950:16
at MessageQueue.__guard (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:2068:9)
at MessageQueue.invokeCallbackAndReturnFlushedQueue (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/index.bundle:1949:12)
at /Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/debuggerWorker.js:126:58
at process.<anonymous> (/Users/Greg/Dropbox/source_reactnative/gcTodo/.vscode/.react/debuggerWorker.js:35:9)
at emitTwo (events.js:125:13)
at process.emit (events.js:213:7)
首先我认为createItem
应该是一个生成器(或者换句话说是一个saga)。然后你不需要 fork
但 call
。那是因为 fork
没有阻塞而 call
是。这就是您获取控制台日志的原因。我想如果 createItem
是一个生成器,你的 try-catch
块就会工作。
使用 createItem 作为一个单独的函数没有得到它的工作,但是现在我通过按照以下将所有内容收缩到一个生成器中来捕获错误:
export function* createItemSaga() {
while (true) {
const action = yield take(ActionTypes.AddListItem_UIRequest);
const { item } = action;
yield put({ type: ActionTypes.AddListItemRequested });
try {
const ref = firebase.firestore().collection('todos');
yield call([ref, ref.add], item);
yield put({ type: ActionTypes.AddListItemFulfilled });
} catch (e) {
console.log('createItemSaga: error caught. Error=');
console.log(pf(e));
yield put({ type: ActionTypes.AddListItemRejected });
}
}
}