[我找到了上一个线程(How to perform same action regardless of promise fulfilment?),但是它已有5年历史了,引用winjs有点麻烦。
我想做的是加载数据元素列表。我有列表的本地副本和元素的本地副本-但它们在服务器端可能已更改。
该过程应像这样:将数据库中的LIST加载到本地存储中(与本地比较)->然后从数据库中加载LIST中列出的(多个)DATA ELEMENTS。
因此,如果“ loadList”异步功能成功...我想运行“ loadElements”异步功能。如果loadList函数拒绝...我仍然想运行“ loadElements”函数(将触发多个获取请求-每个元素一个)。
“”使用'finally'“,我听到你说...,但是我想将” 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函数的分派中得到'TypeError:dispatch(...)is undefined'。此功能未更改...
我并没有完全遵循您要完成的工作(下文中有更多内容),但是要做的第一件事是清理流程,而不要在现有的承诺周围加上多余的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”异步功能成功...我想运行“ loadElements”异步功能。如果loadList函数拒绝...我仍然想运行“ loadElements”函数(将触发多个获取请求-每个元素一个)。
但是,您的代码中没有名为loadList()
和loadElements()
的函数,因此您在那里失去了我,因此我不确定如何提出具体的代码建议。
在promise链中的.then()
处理程序内,您可以做三件事:
.then()
处理程序是否存在异常,如果引发任何异常,则将设置异常值作为拒绝原因,自动拒绝promise链。因此,这为您提供了最大的灵活性,可以用一个值或一个错误来完成promise链,或将其链接到另一个promise(更多异步操作)。