javascript - Promise 中的异步代码总是反模式吗?
问题描述
我从这个问题中看到,将s 与代码混合 可能是一种反模式。Promise
async
但是,这是否适用于所有情况?
我看不到避免在以下代码中组合它们的简单方法:
- 这是在安排下一个调用之前
setInterval
等待调用完成的替代方法 - 但是,与recursive不同的是,它不会在
setTimeout
尚不支持TCO的浏览器中构成开放内存泄漏
此代码是否包含反模式?而且,如果是这样,我该如何在不引入内存泄漏的情况下进行补救?
具体参见第 10 行:new Promise( async (resolve) => {
——这似乎很不习惯,但我没有看到另一种实现方式:将await
语句包装在while
循环本身中,调度它,并返回一个句柄以中止循环。
var [setRepeatedTimeout, clearRepeatedTimeout] = (() => {
const asleep = (delay) => new Promise(resolve => setTimeout(resolve, delay));
const repeatedTimeoutIntervals = [];
function setRepeatedTimeout(f, delay, ...arguments) {
//Like setInterval, but waits for an invocation to complete before scheduling the next one
//(Supports both classic and async functions)
const mySemaphores = {notAborted: true};
const intervalID = repeatedTimeoutIntervals.push(mySemaphores) - 1;
new Promise( async (resolve) => {
await asleep(delay);
while(mySemaphores.notAborted) {
await f(...arguments);
await asleep(delay);
}
delete repeatedTimeoutIntervals[intervalID];
});
return intervalID;
}
function clearRepeatedTimeout(intervalID) {
//Clears loops set by setInterval()
repeatedTimeoutIntervals[intervalID].notAborted = false;
}
return [setRepeatedTimeout, clearRepeatedTimeout];
})();
<p><button onclick="(function createInterval(){
const _ = {intervalID: undefined};
_.intervalID = setRepeatedTimeout( () => {
console.log(`Hello from intervalID ${_.intervalID}`)
}, 2000)
})()">Create timer</button><br />
<form action="javascript:void(0);" onsubmit="(function clearInterval(intervalID){
clearRepeatedTimeout(intervalID);
})(parseInt(event.target.elements.intervalID.value))">
<input name="intervalID" placeholder="intervalID"/><button type="submit">Clear timer</button></p>
解决方案
另一个问题警告的问题是,如果传递给 Promise 构造函数的异步回调内部等待拒绝的东西,则 Promise 将挂起而不是拒绝。您当前的代码不会导致f
拒绝,但setRepeatedTimeout
要执行可能拒绝的任务,您将获得未处理的拒绝和永久挂起:
var [setRepeatedTimeout, clearRepeatedTimeout] = (() => {
const asleep = (delay) => new Promise(resolve => setTimeout(resolve, delay));
const repeatedTimeoutIntervals = [];
function setRepeatedTimeout(f, delay, ...arguments) {
//Like setInterval, but waits for an invocation to complete before scheduling the next one
//(Supports both classic and async functions)
const mySemaphores = {notAborted: true};
const intervalID = repeatedTimeoutIntervals.push(mySemaphores) - 1;
new Promise( async (resolve) => {
await asleep(delay);
while(mySemaphores.notAborted) {
await f(...arguments);
await asleep(delay);
}
delete repeatedTimeoutIntervals[intervalID];
});
return intervalID;
}
function clearRepeatedTimeout(intervalID) {
//Clears loops set by setInterval()
repeatedTimeoutIntervals[intervalID].notAborted = false;
}
return [setRepeatedTimeout, clearRepeatedTimeout];
})();
const _ = { intervalID: undefined };
_.intervalID = setRepeatedTimeout(() => {
console.log('Throwing...');
return Promise.reject();
}, 2000)
如果您希望在遇到此类错误时继续循环,有一种方法可以处理此类问题,同时保持async
: 捕获所有可能拒绝的内容(在try
/catch
或 with 中.catch
):
var [setRepeatedTimeout, clearRepeatedTimeout] = (() => {
const asleep = (delay) => new Promise(resolve => setTimeout(resolve, delay));
const repeatedTimeoutIntervals = [];
function setRepeatedTimeout(f, delay, ...arguments) {
//Like setInterval, but waits for an invocation to complete before scheduling the next one
//(Supports both classic and async functions)
const mySemaphores = {notAborted: true};
const intervalID = repeatedTimeoutIntervals.push(mySemaphores) - 1;
new Promise( async (resolve) => {
await asleep(delay);
while(mySemaphores.notAborted) {
await f(...arguments).catch(() => {}); // log error here if you want
await asleep(delay);
}
delete repeatedTimeoutIntervals[intervalID];
});
return intervalID;
}
function clearRepeatedTimeout(intervalID) {
//Clears loops set by setInterval()
repeatedTimeoutIntervals[intervalID].notAborted = false;
}
return [setRepeatedTimeout, clearRepeatedTimeout];
})();
const _ = { intervalID: undefined };
_.intervalID = setRepeatedTimeout(() => {
console.log('Throwing...');
return Promise.reject();
}, 2000)
但是真的根本不需要new Promise
这里——它永远不会解决,也永远不会被使用。只需使用异步 IIFE:
var [setRepeatedTimeout, clearRepeatedTimeout] = (() => {
const asleep = (delay) => new Promise(resolve => setTimeout(resolve, delay));
const repeatedTimeoutIntervals = [];
function setRepeatedTimeout(f, delay, ...arguments) {
//Like setInterval, but waits for an invocation to complete before scheduling the next one
//(Supports both classic and async functions)
const mySemaphores = {notAborted: true};
const intervalID = repeatedTimeoutIntervals.push(mySemaphores) - 1;
(async () => {
await asleep(delay);
while(mySemaphores.notAborted) {
await f(...arguments).catch(() => {}); // log error here if you want
await asleep(delay);
}
delete repeatedTimeoutIntervals[intervalID];
})();
return intervalID;
}
function clearRepeatedTimeout(intervalID) {
//Clears loops set by setInterval()
repeatedTimeoutIntervals[intervalID].notAborted = false;
}
return [setRepeatedTimeout, clearRepeatedTimeout];
})();
const _ = { intervalID: undefined };
_.intervalID = setRepeatedTimeout(() => {
console.log('Throwing...');
return Promise.reject();
}, 2000)
(async () => {
await asleep(delay);
while(mySemaphores.notAborted) {
await f(...arguments).catch(() => {}); // log error here if you want
await asleep(delay);
}
delete repeatedTimeoutIntervals[intervalID];
})();
推荐阅读
- c# - C# Composition - 不完全确定我是否正确实施
- javascript - 根据另一个数组中的值替换数组的值
- data-structures - 如何构建方形四叉树
- c - 带有字符串数组的 C 程序 printf char
- javascript - 反应组件音频播放在 Safari 中不起作用
- javascript - 尝试使用节点 js 创建简单的聊天应用程序 - 无法从本地主机托管
- python - 在 Github Actions 上安装后找不到我的 python 模块
- node.js - node-forge 错误:“无法读取公钥。OID 不是 RSA。” 加载 SSL 证书时
- android - 导入导航撰写时,Android Jetpack Compose 崩溃
- java - Jython:getDeclaredMethod 双类型参数错误 java.lang.NoSuchMethodException