无论结果如何,在承诺之后运行次要操作?



我找到了以前的线程(无论承诺是否履行,如何执行相同的操作?(,但它已经有 5 年的历史了,引用 winjs 是一个笨蛋。

我想做的是加载数据元素列表。 我有列表的本地副本和元素的本地副本 - 但它们可能在服务器端发生了变化。

该过程应如下所示:将 LIST 从数据库加载到本地存储中(与本地比较(-->然后从数据库中加载 LIST 中列出的(多个(数据元素。

因此,如果"loadList"异步函数成功...我想运行"加载元素"异步函数。 如果 loadList 函数拒绝...我仍然想运行"loadElements"函数(它会触发多个获取请求 - 每个元素一个(。

"使用'终于'"我听到你说... 但我想将"loadList"解析/拒绝和"loadElements"解析/拒绝函数的结果传递给调用函数。 据我所知,"最后"不会接收或传递属性。

我想将结果传递给调用函数的原因是查看拒绝原因是否是可接受的原因,并且我可以信任本地副本作为权威副本(例如,如果数据库不包含 LIST,我可以信任本地列表是权威版本(......所以我需要一种方法来分析调用函数中的"失败"。

这是我所拥有的:

export function syncLinkTablesAndElementsWithDB(username) { 
return (dispatch, getState) => {
return new Promise((resolve, reject) => {
dispatch(loadLinkTableAndElementsFromDB(STATIONS_LINK_TABLE_TYPE, username))
.then((msg) => {
console.log("loadLinkTableAndElementsFromDB RESOLVED: ", msg);
resolve(msg)
})
.then(() => {
dispatch(pushLinkTableToDB(STATIONS_LINK_TABLE_TYPE, username))
dispatch(pushAllUserStationsToDB(username))
})
.catch((allPromReasons) => {
console.log("loadLinkTableAndElementsFromDB REJECTED: ", allPromReasons);
allReasonsAcceptable = true;
allPromReasons.forEach(reason => {
if (!isAcceptableLoadFailureReasonToOverwrite(reason)) {
allReasonsAcceptable = false;
}
});
if (allReasonsAcceptable) {
//TODO:   DO push of local to DB
// eventually return results of the push to DB...
} else {
reject(allPromReasons)
}
})
});
}
}

export function loadLinkTableAndElementsFromDB(tableType, username) {
return (dispatch, getState) => {
return new Promise((resolve, reject) => {
dispatch(loadLinkTableFromDB(tableType, username))
.then(successMsg => {
resolve(Promise.all([successMsg, dispatch(loadAllUsersStationsFromDB(username)).catch(err=>err)]))
})
.catch(err => {
reject(Promise.all([err, dispatch(loadAllUsersStationsFromDB(username)).catch(err=>err)]))
})
});
}
}
export function loadAllUsersStationsFromDB(username) {
return (dispatch, getState) => {
return new Promise((resolve, reject) => {
let linkTable = getStationsLinkTable(username); // get the local link table
if (linkTable && Array.isArray(linkTable.stations)) { // if there is a local station list
let loadPromises = linkTable.stations.map(stationID => dispatch(loadStationFromDB(stationID)).catch((err) => err));
Promise.all(loadPromises)
.then((allReasons) => {
let allSuccesses = true;
allReasons.forEach(reason => {
if (!reason.startsWith(SUCCESS_RESPONSE)) {
allSuccesses = false;
}
});
if (allSuccesses) {
resolve(SUCCESS_RESPONSE + ": " + username);
} else {
reject(allReasons);
}
})
} else {
return reject(NO_LINK_TABLE_AVAILABLE + ": " + username);
}
});
};
}

loadStationFromDB 和 loadLinkTableFromDB 做你所期望的...尝试从数据库加载这些内容。 如果您认为值得,我可以包含他们的代码。

-----------编辑----------- 为了澄清我想要完成的任务:

我正在尝试将本地存储与数据库同步。 我想通过从数据库中提取数据来做到这一点,比较时间/日期戳。 这将使本地存储版本成为所有数据的权威副本。 从数据库加载后,我想将本地存储版本推送到数据库。

我需要注意这样一个事实,即数据库通常根本没有数据,因此可能会在拉取时"拒绝"......即使在同步实例中,这种拒绝是可以接受的,并且不应停止同步过程。

根据下面的建议,我修改了我的代码:

export function loadLinkTableAndElementsFromDB(tableType, username) {
console.log("loadLinkTableAndElementsFromDB(", tableType, username, ")");
return (dispatch, getState) => {
return new Promise((resolve, reject) => {
dispatch(loadLinkTableFromDB(tableType, username))
.then(successMsg => {
console.log("loadLinkTableFromDB RESOLVED: ", successMsg)
resolve(Promise.all([successMsg, dispatch(loadAllUsersStationsFromDB(username)).catch(err => err)]))
})
.catch(err => {
console.log("loadLinkTableFromDB REJECTED: ", err)
reject(Promise.all([err, dispatch(loadAllUsersStationsFromDB(username)).catch(err => err)]))
})
});
}
}
export function syncLinkTablesAndElementsWithDB(username) {
console.log("syncLinkTablesAndElementsWithDB(", username, ")");
return (dispatch, getState) => {
dispatch(loadLinkTableFromDB(STATIONS_LINK_TABLE_TYPE, username))
.then((successLoadLinkTableMsg) => {
console.log('Successfully loaded link table: ', successLoadLinkTableMsg)
return dispatch(pushLinkTableToDB(STATIONS_LINK_TABLE_TYPE, username))
})
.catch((rejectLoadLinkTableReason) => {
console.log("Failed to load link table from DB: " + rejectLoadLinkTableReason);
if (allReasonsAcceptableForOverwrite(rejectLoadLinkTableReason)) {  // some rejection reasons are accectable... so if failed reason is okay.... 
console.log("Failure to load link table reasons were acceptable... pushing local link table anyway");
return dispatch(pushLinkTableToDB(STATIONS_LINK_TABLE_TYPE, username))
} else {
console.log("Throwing: ", rejectLoadLinkTableReason);
throw rejectLoadLinkTableReason;
}
})  
.then((successPushLinkTaleMsg) => { 
console.log("Successfully pushed link table: " + successPushLinkTaleMsg);
return dispatch(loadAllUsersStationsFromDB(username)); // I want this to occur regardless of if the link table stuff succeeds or fails...  but it must occur AFTER the loadLinkTableFromDB at least tries...
})
.catch((rejectPushLinkTableReason) => {
console.log("Failed to push link table: " + rejectPushLinkTableReason);
return dispatch(loadAllUsersStationsFromDB(username)); // I want this to occur regardless of if the link table stuff succeeds or fails...  but it must occur AFTER the loadLinkTableFromDB at least tries... 
})
.then((successLoadAllUserStationsMsg) => {
console.log("Successfully loaded all user stations: " + successLoadAllUserStationsMsg);
return dispatch(pushAllUserStationsToDB(username))
})
.catch((rejectLoadAllUserStationsReason) => {
console.log("Failed to push all users stations: " + rejectLoadAllUserStationsReason);
if (allReasonsAcceptableForOverwrite(rejectLoadAllUserStationsReason)) {  // some rejection reasons are accectable... so if failed reason is okay.... 
console.log("Load users stations reasons are acceptable...");
return dispatch(pushAllUserStationsToDB(username))
} else {
console.log("throwing: ", rejectLoadAllUserStationsReason);
throw rejectLoadAllUserStationsReason;
}
})
.then((successPushAllUserStationsMgs) => {
console.log("Successfully pushed all users stations: " + successPushAllUserStationsMgs);
return Promise.resolve();
})
.catch((rejectPushAllUserStationsReason) => {
console.log("Failed to push all users stations: " + rejectPushAllUserStationsReason);
throw rejectPushAllUserStationsReason;
})
};
}

export function syncAllWithDB(username) { 
return (dispatch, getState) => {
// other stuff will occur here...
dispatch(syncLinkTablesAndElementsWithDB(username))  // *** Error here ***
.then((successMsg) => {
console.log("Successful sync for : " + successMsg);
})
.catch(allReasons => {
console.warn("Link tables and elements sync error: ", allReasons);
})
// });
}
}

不幸的是,我现在在syncAllWithDB函数中的调度上得到"类型错误:调度(...(未定义"。 此功能未更改...

我不完全遵循您要完成的任务(更多内容见下文(,但这里要做的第一件事是清理流程,而不是围绕现有承诺进行额外的new Promise()。 永远没有理由这样做:

function someFunc() {
return new Promise((resolve, reject) => {
callSomething.then(result => {
...
doSomethingElse(result).then(result2 => {
...
resolve(result2);
}).catch(err => {
...
reject(err);
});
}).catch(err => {
...
reject(err);
});
});
}

这是一个众所周知的承诺反模式。 你不需要额外的手动创建的承诺包裹在已经做出承诺的函数周围。 相反,您可以返回您已经拥有的承诺。 这称为"承诺链"。 从链内,您可以从任何地方拒绝或解析链。

function someFunc() {
return callSomething.then(result => {
...
// return promise here, chaining this new async operation 
// to the previous promise
return doSomethingElse(result).then(result2 => {
...
return result2;
}).catch(err => {
...
// after doing some processing on the error, rethrow
// to keep the promise chain rejected
throw err;
});
}).catch(err => {
...
reject err;
});
}

或者,你甚至可以像这样扁平化承诺链:

function someFunc() {
return callSomething.then(result => {
...
return doSomethingElse(result);
}).then(result2 => {
...
return result2;
}).catch(err => {
...
throw err;
});
}

例如,您可以像这样简化syncLinkTablesAndElementsWithDB()

export function syncLinkTablesAndElementsWithDB(username) { 
return (dispatch, getState) => {
return dispatch(loadLinkTableAndElementsFromDB(STATIONS_LINK_TABLE_TYPE, username)).then((msg) => {
console.log("loadLinkTableAndElementsFromDB RESOLVED: ", msg);
dispatch(pushLinkTableToDB(STATIONS_LINK_TABLE_TYPE, username))
dispatch(pushAllUserStationsToDB(username))
// have msg be the resolved value of the promise chain
return(msg);
}).catch((allPromReasons) => {
console.log("loadLinkTableAndElementsFromDB REJECTED: ", allPromReasons);
let allReasonsAcceptable = allPromReasons.every(reason => {
return isAcceptableLoadFailureReasonToOverwrite(reason);
});
if (allReasonsAcceptable) {
//TODO:   DO push of local to DB
// eventually return results of the push to DB...
} else {
// have promise stay rejected
throw allPromReasons;
}
});
}
}

至于你的其余问题,你问的是:

因此,如果"loadList"异步函数成功...我想运行"加载元素"异步函数。如果 loadList 函数拒绝...我仍然想运行"loadElements"函数(它会触发多个获取请求 - 每个元素一个(。

但是,您的代码中没有称为loadList()loadElements()的函数,因此您在那里丢失了我,所以我不确定如何提出特定的代码建议。

在承诺链的.then()处理程序中,您可以执行三项操作:

  1. 返回一个值。该值成为承诺链的解析值。
  2. 返回承诺。该承诺附加到承诺链上,并且整个承诺链(调用者将监视的最顶层承诺(最终将在您返回的此承诺解决/拒绝(或也链接到它的任何内容解析/拒绝(时解决/拒绝。
  3. 引发异常。将自动监视所有.then()处理程序是否存在异常,如果抛出任何异常,则会自动拒绝 promise 链,并将异常值设置为拒绝原因。

因此,这为您提供了最大的灵活性,可以用值或错误完成承诺链,或者将其链接到另一个承诺(更多异步操作(。

相关内容

最新更新