gpt4 book ai didi

javascript - 无论结果如何,在 promise 之后执行次要行动?

转载 作者:行者123 更新时间:2023-12-02 22:24:35 24 4
gpt4 key购买 nike

我找到了之前的帖子 ( How to perform same action regardless of promise fulfilment? ),但它已经有 5 年历史了,并且引用 winjs 是一个拼凑。

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

该过程应该像这样工作:将列表从数据库加载到本地存储(与本地存储进行比较)-->然后从列表中列出的数据库加载(多个)数据元素。

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

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

我想将结果传递给调用函数的原因是查看拒绝原因是否是可接受的原因以及我是否可以信任本地副本作为权威副本(例如,如果数据库不包含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() 围绕现有的 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);
});
});
}

这是一个众所周知的 promise 反模式。您不需要额外手动创建的 promise 包含在已经做出 promise 的函数中。相反,你可以只返回你已有的 promise 。这称为“ promise 链”。在链内,您可以从任何地方拒绝或解决该链。

 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;
});
}

或者,您甚至可以像这样展平 promise 链:

 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;
}
});
}
}

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

So if the "loadList" async function succeeds... I want to run the "loadElements" async function. If the loadList function rejects... I STILL want to run the "loadElements" function (Which fires off multiple fetch requests - one for each element).

但是,您的代码中没有名为 loadList()loadElements() 的函数,因此您迷失了方向,所以我不确定如何制作特定的代码建议。

在 Promise 链的 .then() 处理程序中,您可以执行三件事:

  1. 返回一个值。该值将成为 promise 链的解析值。
  2. 返回一个 Promise。该 Promise 附加到 Promise 链,并且当您执行此 Promise 时,整个 Promise 链(调用者将看到的最顶层的 Promise)将最终解决/拒绝返回解析/拒绝(或任何链接到它的解析/拒绝)。
  3. 抛出异常。所有 .then() 处理程序都会自动监视异常,如果抛出任何异常,则 Promise 链会自动拒绝并显示异常值设置为拒绝原因。

因此,这为您提供了最终的灵 active ,可以使用值或错误来完成 Promise 链,或者将其链接到另一个 Promise(更多异步操作)。

关于javascript - 无论结果如何,在 promise 之后执行次要行动?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59108421/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com