有没有更好的方法来让 jQuery 的回调 API 适应 Promises,而不是将它们全部包装在这些函数中?
首先,jQuery 已经包含一些对完成通知的承诺支持。例如,如果您想知道动画何时完成,他们有.promise(),它会在特定对象的 fx 动画队列完成时得到一个解决方案。这些类型的操作是一次性通知,非常适合 Promise 的工作方式。
jQuery 还内置了对 ajax 调用的 Promise 支持,您可以使用它们的回调接口或 jQuery ajax 的 Promise 接口。
jQuery 没有任何内置的 Promise 支持,因为它们不直接与 Promise 的一次性功能相匹配。
因此,如果您真的想在下一次点击特定元素时使用 Promise,那么您必须为此构建自己的 Promise 支持。
您提出的函数适用于某些输入参数:
function clickPromise(selector) {
return new Promise((resolve, reject) => {
$(selector).click((event) => resolve(event));
});
}
例如,如果选择器只匹配一个 DOM 元素或者它匹配多个 DOM 元素,并且您只希望在任何这些元素上发生第一次点击,并且这些元素不会持续很长时间,因此您要调用它再用相同的元素(它会随着时间的推移建立事件侦听器),然后这可以正常工作。
就个人而言,如果你打算这样做,我建议这样做:
// Get promise for the very next click on any of 1 to many items
// resolves when the first click happens
// rejects if the selector doesn't match any elements
function clickPromise(selector) {
return new Promise((resolve, reject) => {
const items = $(selector);
if (!items.length) {
reject(new Error("selector empty"));
return;
}
const handler = function(event) {
// remove all event listeners we previously installed so they don't build up
items.off('click', handler);
resolve(event);
}
// install click handlers
items.on('click', handler);
});
}
与您的实现的主要区别在于,这会在单击发生时删除事件侦听器,因此如果在相同元素上反复使用它,它们不会随着时间的推移而建立,并且如果选择器与任何元素都不匹配,它会拒绝因为否则这将是一个永远不会解决的承诺。
仅供参考,这种类型的功能不依赖于 jQuery。再添加几行代码,您就可以使用普通的 DOM Javascript 实现相同的功能。
如果您一次只打算对一个元素使用它并且只传递一个与一个元素完全匹配的选择器,那么您可以使用.one() 使其更简单一些:
// Get promise for the very next click on any of 1 to many items
// resolves when the first click happens
// rejects if the selector doesn't match any elements
function clickPromise(selector) {
return new Promise((resolve, reject) => {
const items = $(selector);
if (items.length === 0) {
reject(new Error("selector empty"));
return;
} else if (items.length > 1) {
reject(new Error("selector matches more than one element"));
return;
}
items.one('click', function(event) {
resolve(event);
});
}