我使用的是Babel 7的RN 0.57.1。但这只是一个“ javascript”问题。
我还无法繁殖(即使与另一个开关块处于同一循环中)也已经整天工作了。我将继续通过调查已转译的代码来解决这个问题。但是出于某些奇怪的原因,break
中的switch
语句中断了父while
循环。我不得不用break PUSH_KIND_SWITCH
代替它们。如果我使用常规的break
会导致问题。我只是在这里发布,如果有人在我继续调查的过程中发现任何错误:
未翻译的代码:
function* pushWorker(message: PushMessage, accountId: AccountId, calendarId: CalendarId): Generator<*, void, *> {
// if no channel for this id, create a channel for it
const accCalId = buildAccCalId(accountId, calendarId);
// console.log('in pushWorker, message:', message);
const { id } = message;
let buf, chan;
{
const { id } = message;
if (pushChanById.hasOwnProperty(id)) {
console.log('channel already in pushChanById, will put to it, id:', id);
pushChanById[id].put(message);
return;
} else {
console.log('creating channel');
buf = buffers.expanding(1)
pushChanById[id] = yield call(channel, buf);
// pushChanById[id].put(message);
}
chan = pushChanById[id];
}
// console.log('material for id:', id, 'buf:', buf, 'chan:', chan);
PUSH_MESSAGE_LOOP:
while (true) {
console.log('at top of while-loop for saga for event id:', id);
console.log('got message in chan, message:', message, 'will check newerMessages (which are newer then this current message) to see if this newer should cancel & ovveride this message');
console.log('will delay 5s to allow user to batch actions - for instance undo is allowed for 4sec, so that would cancel the create');
yield call(delay, 5000);
console.log('done delay');
// remove all newer messages in channel, and boil it down to one message to act on
const newerMessages = yield flush(chan);
console.log('newerMessages in chan:', newerMessages, 'recall that current message is:', message);
message = newerMessages.last || message;
console.log('checked newerMessages, and decided message to act on is:', message);
// act on message
let { kind } = message;
let event = yield select(selectEvent, id);
if (!event) {
console.warn('EVENT NO LONGER EXISTS, so disccarding, and skipping switch block and skip to kill the channel this SHOULD NEVER HAPPEN');
} else {
const meta = getPushMeta(event, accountId, calendarId);
const isRemoteExisting = meta.sid !== undefined;
if (kind === PK.create && isRemoteExisting) {
console.log('kind was create, but isRemoteExisting, so change this to update!');
kind = PK.update;
} else if (kind === PK.update && !isRemoteExisting) {
console.log('kind was update, but isRemoteExisting is false!!, so change this to create!');
kind = PK.create;
}
PUSH_KIND_SWITCH:
switch (kind) {
case PK.delete: {
const calendar = (yield select(selectActiveCalendar)) || { id:'primary' };
const calendarId = calendar.id;
const remoteEventId = meta.sid; // if !isRemoteExisting then this will be undefined
let status;
if (isRemoteExisting) {
({ status } = yield call(
fetch,
`https://www.googleapis.com/calendar/v3/calendars/${calendarId}/events/${remoteEventId}`,
{
method: 'delete'
}
));
}
if (!isRemoteExisting || status === 204 || status === 410) {
// 410 - P error:{ code:410, errors:[...], message:'Resource has been delete' }
yield put(patchEvent(id, {
pushMetaByAccCalId: {
[accCalId]: {
accCalId,
accountId,
calendarId,
sid: undefined,
version: event.version
}
}
}));
// TODO: think about also making sure there are no more messages, probably with a buf.isEmpty(), cuz what if another came in to undo it?
// check if deleted from all other accounts, if so then _deleteEvent
const otherMetas = Object.values(event.pushMetaByAccCalId || {}).filter(meta => meta.accCalId !== accCalId); // remove this account, as we know for sure it was pushed. no need to do a `yield select()`
const isLatestRemoteExistOnAllAccounts = otherMetas.every(otherMeta => [undefined, event.version].includes(otherMeta.version)); // undefined because latest remote is a deleted, so if others are undefined great it never got anything
event = yield select(selectEvent, id);
if (isLatestRemoteExistOnAllAccounts && !testIfRecording(event)) yield put(_deleteEvent(id));
} else {
console.warn('failed to delete, i should keep retrying this, until another message comes in to chan canceling this one?');
}
break;
}
case PK.create: {
const calendar = (yield select(selectActiveCalendar)) || { id:'primary' };
const calendarId = calendar.id;
const { title, summary } = extractTitleAndSummary(event.memo);
const { reply, status } = yield call(
fetch,
`https://www.googleapis.com/calendar/v3/calendars/${calendarId}/events`,
{
method: 'post',
body: {
summary: title,
description: summary,
start: {
dateTime: moment(event.start).toISOString()
},
end: {
dateTime: moment(event.end).toISOString()
},
location: event.location
}
}
);
if (status === 200) {
yield put(patchEvent(id, {
pushMetaByAccCalId: {
[accCalId]: {
accCalId,
accountId,
calendarId,
sid: reply.id,
version: event.version
}
}
}));
} else {
console.warn('failed to insert event, i should keep retrying this, until another message comes in to chan canceling this one?');
}
break;
}
case PK.update: {
const calendarId = get(yield select(), ['prefs', 'calendar', 'id'], 'primary');
const remoteEventId = meta.sid;
const { title, summary } = extractTitleAndSummary(event.memo);
const { reply, status } = yield call(
fetch,
`https://www.googleapis.com/calendar/v3/calendars/${calendarId}/events/${remoteEventId}`,
{
method: 'put',
body: {
summary: title,
description: summary,
start: {
dateTime: moment(event.start).toISOString()
},
end: {
dateTime: moment(event.end).toISOString()
},
location: event.location
}
}
);
if (status === 200) {
yield put(patchEvent(id, {
pushMetaByAccCalId: {
[accCalId]: {
accCalId,
accountId,
calendarId,
sid: reply.id,
version: event.version
}
}
}));
} else {
console.warn('failed to update event, i should keep retrying this, until another message comes in to chan canceling this one?');
}
break;
}
}
// console.log('out of switch MUST SEE');
}
// console.log('out of if-else MUST SEE');
// destroy channel if channel is empty, else continue the while loop to process next message
if (buf.isEmpty()) {
console.log('buf is empty for event id:', id, 'so destroying channel and quiting pushSaga for it');
chan.close();
delete pushChanById[id];
yield put(patchEvent(id, { status:undefined })); // set status to undefined, as push is complete. if event is deleted, it just wont do anything
break PUSH_MESSAGE_LOOP;
} else {
console.log('at bottom of while-loop, and there are more messages so immediately take next message, for saga for event id:', id);
message = yield take(chan);
console.log('got another message from chan while at bottom, message:', message);
}
}
// console.log('out of while if did not see 2x "MUST SEE" this is a bug');
}
function pushWorker(message, accountId, calendarId) {
var accCalId, _message, id, buf, chan, _message2, _id, _loop, _ret;
return _regenerator.default.wrap(function pushWorker$(_context14) {
while (1) {
switch (_context14.prev = _context14.next) {
case 0:
accCalId = (0, _utils2.buildAccCalId)(accountId, calendarId);
_message = message, id = _message.id;
_message2 = message, _id = _message2.id;
if (!pushChanById.hasOwnProperty(_id)) {
_context14.next = 9;
break;
}
console.log('channel already in pushChanById, will put to it, id:', _id);
pushChanById[_id].put(message);
return _context14.abrupt("return");
case 9:
console.log('creating channel');
buf = _reduxSaga.buffers.expanding(1);
_context14.next = 13;
return (0, _effects.call)(_reduxSaga.channel, buf);
case 13:
pushChanById[_id] = _context14.sent;
case 14:
chan = pushChanById[_id];
_loop = _regenerator.default.mark(function _loop() {
var newerMessages, _message3, kind, event, meta, isRemoteExisting, calendar, _calendarId, remoteEventId, status, _ref10, otherMetas, isLatestRemoteExistOnAllAccounts, _calendar, _calendarId2, _extractTitleAndSumma, title, summary, _ref11, reply, _status, _calendarId3, _remoteEventId, _extractTitleAndSumma2, _title, _summary, _ref12, _reply, _status2;
return _regenerator.default.wrap(function _loop$(_context13) {
while (1) {
switch (_context13.prev = _context13.next) {
case 0:
console.log('at top of while-loop for saga for event id:', id);
console.log('got message in chan, message:', message, 'will check newerMessages (which are newer then this current message) to see if this newer should cancel & ovveride this message');
console.log('will delay 5s to allow user to batch actions - for instance undo is allowed for 4sec, so that would cancel the create');
_context13.next = 5;
return (0, _effects.call)(_reduxSaga.delay, 5000);
case 5:
console.log('done delay');
_context13.next = 8;
return (0, _effects.flush)(chan);
case 8:
newerMessages = _context13.sent;
console.log('newerMessages in chan:', newerMessages, 'recall that current message is:', message);
message = newerMessages.last || message;
console.log('checked newerMessages, and decided message to act on is:', message);
_message3 = message, kind = _message3.kind;
_context13.next = 15;
return (0, _effects.select)(_selectors.selectEvent, id);
case 15:
event = _context13.sent;
if (event) {
_context13.next = 20;
break;
}
console.warn('EVENT NO LONGER EXISTS, so disccarding, and skipping switch block and skip to kill the channel this SHOULD NEVER HAPPEN');
_context13.next = 94;
break;
case 20:
meta = (0, _utils2.getPushMeta)(event, accountId, calendarId);
isRemoteExisting = meta.sid !== undefined;
if (kind === PK.create && isRemoteExisting) {
console.log('kind was create, but isRemoteExisting, so change this to update!');
kind = PK.update;
} else if (kind === PK.update && !isRemoteExisting) {
console.log('kind was update, but isRemoteExisting is false!!, so change this to create!');
kind = PK.create;
}
_context13.t0 = kind;
_context13.next = _context13.t0 === PK.delete ? 26 : _context13.t0 === PK.create ? 54 : _context13.t0 === PK.update ? 74 : 94;
break;
case 26:
_context13.next = 28;
return (0, _effects.select)(_selectors2.selectActiveCalendar);
case 28:
_context13.t1 = _context13.sent;
if (_context13.t1) {
_context13.next = 31;
break;
}
_context13.t1 = {
id: 'primary'
};
case 31:
calendar = _context13.t1;
_calendarId = calendar.id;
remoteEventId = meta.sid;
if (!isRemoteExisting) {
_context13.next = 39;
break;
}
_context13.next = 37;
return (0, _effects.call)(_fetch.default, "https://www.googleapis.com/calendar/v3/calendars/" + _calendarId + "/events/" + remoteEventId, {
method: 'delete'
});
case 37:
_ref10 = _context13.sent;
status = _ref10.status;
case 39:
if (!(!isRemoteExisting || status === 204 || status === 410)) {
_context13.next = 52;
break;
}
_context13.next = 42;
return (0, _effects.put)(patchEvent(id, {
pushMetaByAccCalId: (0, _defineProperty2.default)({}, accCalId, {
accCalId: accCalId,
accountId: accountId,
calendarId: _calendarId,
sid: undefined,
version: event.version
})
}));
case 42:
otherMetas = Object.values(event.pushMetaByAccCalId || {}).filter(function (meta) {
return meta.accCalId !== accCalId;
});
isLatestRemoteExistOnAllAccounts = otherMetas.every(function (otherMeta) {
return [undefined, event.version].includes(otherMeta.version);
});
_context13.next = 46;
return (0, _effects.select)(_selectors.selectEvent, id);
case 46:
event = _context13.sent;
if (!(isLatestRemoteExistOnAllAccounts && !(0, _utils2.testIfRecording)(event))) {
_context13.next = 50;
break;
}
_context13.next = 50;
return (0, _effects.put)(_deleteEvent(id));
case 50:
_context13.next = 53;
break;
case 52:
console.warn('failed to delete, i should keep retrying this, until another message comes in to chan canceling this one?');
case 53:
return _context13.abrupt("return", "break");
case 54:
_context13.next = 56;
return (0, _effects.select)(_selectors2.selectActiveCalendar);
case 56:
_context13.t2 = _context13.sent;
if (_context13.t2) {
_context13.next = 59;
break;
}
_context13.t2 = {
id: 'primary'
};
case 59:
_calendar = _context13.t2;
_calendarId2 = _calendar.id;
_extractTitleAndSumma = (0, _utils2.extractTitleAndSummary)(event.memo), title = _extractTitleAndSumma.title, summary = _extractTitleAndSumma.summary;
_context13.next = 64;
return (0, _effects.call)(_fetch.default, "https://www.googleapis.com/calendar/v3/calendars/" + _calendarId2 + "/events", {
method: 'post',
body: {
summary: title,
description: summary,
start: {
dateTime: (0, _moment.default)(event.start).toISOString()
},
end: {
dateTime: (0, _moment.default)(event.end).toISOString()
},
location: event.location
}
});
case 64:
_ref11 = _context13.sent;
reply = _ref11.reply;
_status = _ref11.status;
if (!(_status === 200)) {
_context13.next = 72;
break;
}
_context13.next = 70;
return (0, _effects.put)(patchEvent(id, {
pushMetaByAccCalId: (0, _defineProperty2.default)({}, accCalId, {
accCalId: accCalId,
accountId: accountId,
calendarId: _calendarId2,
sid: reply.id,
version: event.version
})
}));
case 70:
_context13.next = 73;
break;
case 72:
console.warn('failed to insert event, i should keep retrying this, until another message comes in to chan canceling this one?');
case 73:
return _context13.abrupt("return", "break");
case 74:
_context13.t3 = _lodash.get;
_context13.next = 77;
return (0, _effects.select)();
case 77:
_context13.t4 = _context13.sent;
_context13.t5 = ['prefs', 'calendar', 'id'];
_calendarId3 = (0, _context13.t3)(_context13.t4, _context13.t5, 'primary');
_remoteEventId = meta.sid;
_extractTitleAndSumma2 = (0, _utils2.extractTitleAndSummary)(event.memo), _title = _extractTitleAndSumma2.title, _summary = _extractTitleAndSumma2.summary;
_context13.next = 84;
return (0, _effects.call)(_fetch.default, "https://www.googleapis.com/calendar/v3/calendars/" + _calendarId3 + "/events/" + _remoteEventId, {
method: 'put',
body: {
summary: _title,
description: _summary,
start: {
dateTime: (0, _moment.default)(event.start).toISOString()
},
end: {
dateTime: (0, _moment.default)(event.end).toISOString()
},
location: event.location
}
});
case 84:
_ref12 = _context13.sent;
_reply = _ref12.reply;
_status2 = _ref12.status;
if (!(_status2 === 200)) {
_context13.next = 92;
break;
}
_context13.next = 90;
return (0, _effects.put)(patchEvent(id, {
pushMetaByAccCalId: (0, _defineProperty2.default)({}, accCalId, {
accCalId: accCalId,
accountId: accountId,
calendarId: _calendarId3,
sid: _reply.id,
version: event.version
})
}));
case 90:
_context13.next = 93;
break;
case 92:
console.warn('failed to update event, i should keep retrying this, until another message comes in to chan canceling this one?');
case 93:
return _context13.abrupt("return", "break");
case 94:
if (!buf.isEmpty()) {
_context13.next = 103;
break;
}
console.log('buf is empty for event id:', id, 'so destroying channel and quiting pushSaga for it');
chan.close();
delete pushChanById[id];
_context13.next = 100;
return (0, _effects.put)(patchEvent(id, {
status: undefined
}));
case 100:
return _context13.abrupt("return", "break|PUSH_MESSAGE_LOOP");
case 103:
console.log('at bottom of while-loop, and there are more messages so immediately take next message, for saga for event id:', id);
_context13.next = 106;
return (0, _effects.take)(chan);
case 106:
message = _context13.sent;
console.log('got another message from chan while at bottom, message:', message);
case 108:
case "end":
return _context13.stop();
}
}
}, _loop, this);
});
case 16:
if (!true) {
_context14.next = 26;
break;
}
return _context14.delegateYield(_loop(), "t0", 18);
case 18:
_ret = _context14.t0;
_context14.t1 = _ret;
_context14.next = _context14.t1 === "break" ? 22 : _context14.t1 === "break|PUSH_MESSAGE_LOOP" ? 23 : 24;
break;
case 22:
return _context14.abrupt("break", 26);
case 23:
return _context14.abrupt("break", 26);
case 24:
_context14.next = 16;
break;
case 26:
case "end":
return _context14.stop();
}
}
}, _marked13, this);
}