在网络世界中,突然间失去了所有的连接。作为勇敢的冒险者,你将踏上一段惊险刺激的旅程,穿越充满谜题和挑战的网络景观,与神秘的网络幽灵对抗,解开断网之谜,找回失去的连接,带领人们重返数字世界。准备好迎接这场奇幻之旅吗?
开始答题前,需要先打开本题的项目代码文件夹,目录结构如下:
├── css
├── images
├── index.html
├── effect.gif
└── js
└── index.js
其中:
index.html
是主页面。css
是样式文件夹。images
是图片文件夹。effect.gif
是项目最终完成的效果图。js/index.js
是待补充的 js 文件。在浏览器中预览 index.html
页面效果如下:
请在 js/index.js
文件中补充 resetableOnce
函数,实现在接收相同的函数时只执行一次。
函数返回值说明:
resetableOnce
函数的返回值为一个对象 ,格式为 :{runOnce:func, reset:func}
,对应说明如下:
runOnce
:一个函数,用于执行包装后的函数 fn
。当第一次调用 runOnce
时,它将执行 fn
函数,并将结果保存,之后的每次调用将直接返回之前计算的结果。注意:如果传入的函数(fn
)不是同一个函数,则 resetableOnce
函数重新执行。reset
:一个函数,用于重置包装后的函数的状态。调用 reset
后可以让下一次调用 runOnce
时,再次执行 fn
函数。函数使用示例如下:
// 测试用例 1:resetableOnce(fn) fn 有参数的情况
// 定义一个加法函数
function addNumbers(a, b) {
return a + b;
}
const test1 = resetableOnce(addNumbers);
console.log(test1.runOnce(2, 3)); // 输出: 5
console.log(test1.runOnce(4, 5)); // 第二次调用不会执行加法操作,返回上次执行的值,输出: 5
// 重置 once
test1.reset();
console.log(test1.runOnce(4, 5)); // 因为重置,addNumbers 再次执行,输出: 9
// 测试用例 2:resetableOnce(fn) fn 无参数的情况
let a = 10;
let fn = () => {
return a = a + 1;
};
const test2 = resetableOnce(fn); // 传入了不同的函数,之前的 once 不针对此函数生效。
console.log(test2.runOnce()); //输出 11
console.log(test2.runOnce()); // 输出 11
test2.reset();
console.log(test2.runOnce()); // 输出 12
最终效果可参考文件夹下面的 gif 图,图片名称为 effect.gif
(提示:可以通过 VS Code 或者浏览器预览 gif 图片)。
js/index.js
文件外的任何内容。/**
* 定义一个可重置的一次性函数
* @param {func} fn 要作用的函数
* @returns {object} {runOnce:func, reset:func }
*/
function resetableOnce(fn) {
// 存储上次传入的函数
let lastFn = null;
// 存储函数执行结果
let result = null;
// 标记函数是否已经执行过
let hasExecuted = false;
function runOnce() {
if (lastFn!== fn) {
// 如果传入的函数和上次不同,重置状态
lastFn = fn;
hasExecuted = false;
}
if (!hasExecuted) {
// 如果函数还未执行过,执行函数并保存结果
result = fn.apply(this, arguments);
hasExecuted = true;
}
return result;
}
function reset() {
// 重置执行标记,让下一次调用 runOnce 时再次执行 fn 函数
hasExecuted = false;
}
return { runOnce, reset };
}
// 以下代码为检测需要,请勿删除
try {
module.exports = resetableOnce;
} catch (e) {}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>找回连接的奇幻之旅</title>
<link rel="stylesheet" href="./css/style.css">
</head>
<body>
<!-- 网络连接错误页面 -->
<div class="page_error">
<main>
<!-- 错误图标 -->
<img src="./images/error.png" alt="" width="72px" height="72px" style="margin-bottom: 20px;">
<!-- 错误标题 -->
<h2>未连接到互联网</h2>
<!-- 错误提示信息 -->
<p>
<span>请试试以下方法:</span>
<!-- 解决网络问题的建议列表 -->
<ul>
<li>检查网线、调制解调器和路由器</li>
<li>重新连接到 Wi-Fi 网络</li>
</ul>
</p>
<!-- 错误代码 -->
<p style="font-size: 12px;margin-top: 12px;">ERR_INTERNET_DISCONNECTED</p>
<!-- 重新连接网络按钮 -->
<button id="reconnect">
点击重新连接网络
</button>
</main>
<!-- 显示连接结果的区域 -->
<div id="result"></div>
</div>
<!-- 网络连接成功后的页面 -->
<div class="page">
<!-- 页面顶部的图片区域 -->
<div class="webz">
<img src="./images/webz.png">
</div>
<!-- 报名按钮 -->
<button class="btn">马上报名</button>
<!-- 备考路径按钮 -->
<button class="btn-bk">备考路径</button>
<!-- 页面内容区域 -->
<div class="content">
<!-- 标题图片 -->
<img src="./images/title.svg" class="block mt-40 mx-auto">
<!-- 背景图片 -->
<img src="./images/bg.svg" alt="">
</div>
</div>
<!-- 引入 JavaScript 文件 -->
<script src="./js/index.js"></script>
<script>
const lintier = 2000; // 重连成功后页面的跳转时间
const reconnect = document.getElementById('reconnect')
const page = document.querySelector('.page')
const page_error = document.querySelector('.page_error')
var tryCount = 0
let clickEvent = resetableOnce(() => {
retry(handleLink, 5, 400).then(res => {
result.innerHTML += `<p>${res}</p>`;
let flag=false
// 测试用例 1:resetableOnce(fn) fn 有参数的情况
// 定义一个加法函数
function addNumbers(a, b) {
return a + b;
}
const test1 = resetableOnce(addNumbers);
let one=test1.runOnce(2, 3)
let two=test1.runOnce(4, 5)
if(one===two){flag=true}else{flag=false}
// 重置 once
test1.reset();
// 测试用例 2:resetableOnce(fn) fn 无参数的情况
let a = 10;
let fn = () => {
return a = a + 1;
};
const test2 = resetableOnce(fn); // 传入了不同的函数,之前的 once 不针对此函数生效。
let three=test2.runOnce()
let four=test2.runOnce()
if(three===four){flag=true}else{flag=false}
test2.reset();
let five=test2.runOnce()
if(five!=four){flag=true}else{flag=false}
if(flag){
setTimeout(() => {
page_error.style.display = 'none'
page.style.display = 'flex'
}, lintier)
}
}).catch(err => {
reconnect.innerText = '点击重新连接网络'
clickEvent.reset()
result.innerHTML += `<p>${err}</p>`;
})
})
reconnect.onclick = clickEvent.runOnce
function handleLink() {
reconnect.innerText = '已经在尝试连接网络...'
tryCount++
result.innerHTML += `<p>尝试重连${Date.now()}<p/>`;
return new Promise((resolve, reject) => {
let success = tryCount > 7; // 尝试7次以上将重连成功
if (success) {
resolve('网络连接成功');
} else {
reject('网络连接失败');
}
});
}
async function retry(operation, maxAttempts, delayBetweenRetries) {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
// 执行异步操作
const result = await operation();
return result; // 如果成功,返回结果
} catch (error) {
if (attempt < maxAttempts) {
console.log(`第 ${attempt} 次尝试重连. 在 ${delayBetweenRetries}ms 后重试...`);
await new Promise((resolve) => setTimeout(resolve, delayBetweenRetries));
} else {
throw error; // 如果达到最大尝试次数仍然失败,抛出错误
}
}
}
}
</script>
</body>
</html>
功能概述:
详细解释:
page_error
):包含错误图标、标题、解决建议列表、错误代码、重新连接按钮和显示连接结果的区域。page
):包含顶部图片、报名和备考路径按钮以及页面内容图片。lintier
。resetableOnce
函数包装点击事件处理函数,确保点击事件只执行一次。handleLink
函数模拟网络连接尝试,尝试 7 次以上认为连接成功。retry
函数用于重试网络连接操作,最多尝试 maxAttempts
次,每次尝试间隔 delayBetweenRetries
毫秒。* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
.page_error {
width: 100vw;
height: 100vh;
padding-top: 100px;
display: flex;
justify-content: center;
}
#result{
margin: 80px;
}
h2 {
margin-bottom: 16px;
font-size: 24px;
color: #202124;
line-height: 1.5;
}
p,
li {
font-size: 15px;
color: #5f6368;
line-height: 1.55;
}
ul {
padding-left: 40px;
}
button {
width: 200px;
height: 42px;
margin-top: 16px;
background-color: #1989fa;
border-radius: 6px;
font-size: 15px;
color: #fff;
border: none;
outline: none;
}
.webz {
width: 100%;
background-color: #2b4af5;
height: 280px;
position: relative;
}
.webz img {
height: 176px;
top: 60px;
position: absolute;
width: 422px;
left: 22%;
}
.btn {
border: 0px;
left: 20%;
position: relative;
top: -140px;
font-size: 26px;
font-weight: 500;
color: #FFFFFF;
width: 170px;
height: 55px;
background: linear-gradient(180deg, #FFCE39 0%, #FD9301 100%);
box-shadow: 0px 7px 11px 0px rgba(18, 36, 96, 0.19);
border-radius: 30px;
}
.btn-bk {
border: 0px;
left: 22%;
position: relative;
top: -140px;
font-weight: 500;
color: #2E48F7;
font-size: 26px;
width: 170px;
height: 55px;
background: #FFFFFF;
box-shadow: 0px 7px 11px 0px rgba(18, 36, 96, 0.19);
border-radius: 30px
}
.page {
width: 100vw;
height: 100vh;
display: none;
justify-content: center;
align-content: flex-start;
flex-wrap: wrap;
}
.content{
display: flex;
justify-content: center;
align-content: flex-start;
flex-wrap: wrap;
}
.content img:nth-child(1) {
margin-top: -40px;
}
.content img:nth-child(2) {
width: 80%;
height: auto;
}
功能概述:
详细解释:
box-sizing: border-box
盒模型。page_error
):设置页面宽度和高度为视口大小,垂直居中显示内容。#result
):设置外边距为 80px。page
):初始状态下隐藏页面,设置页面宽度和高度为视口大小,使用 flex 布局。/**
* 定义一个可重置的一次性函数
* @param {func} fn 要作用的函数
* @returns {object} {runOnce:func, reset:func }
*/
function resetableOnce(fn) {
// 存储上次传入的函数
let lastFn = null;
// 存储函数执行结果
let result = null;
// 标记函数是否已经执行过
let hasExecuted = false;
function runOnce() {
if (lastFn!== fn) {
// 如果传入的函数和上次不同,重置状态
lastFn = fn;
hasExecuted = false;
}
if (!hasExecuted) {
// 如果函数还未执行过,执行函数并保存结果
result = fn.apply(this, arguments);
hasExecuted = true;
}
return result;
}
function reset() {
// 重置执行标记,让下一次调用 runOnce 时再次执行 fn 函数
hasExecuted = false;
}
return { runOnce, reset };
}
// 以下代码为检测需要,请勿删除
try {
module.exports = resetableOnce;
} catch (e) {}
功能概述:
resetableOnce
函数,用于包装另一个函数,确保该函数只执行一次,并且可以重置状态,让函数再次执行。详细解释:
resetableOnce
函数: fn
作为参数。lastFn
存储上次传入的函数,result
存储函数执行结果,hasExecuted
标记函数是否已经执行过。runOnce
函数:如果传入的函数和上次不同,重置状态;如果函数还未执行过,执行函数并保存结果,将 hasExecuted
标记为 true
;返回函数执行结果。reset
函数:将 hasExecuted
标记重置为 false
,让下一次调用 runOnce
时再次执行 fn
函数。runOnce
和 reset
函数的对象。四、工作流程▶️
page_error
)显示,网络连接成功页面(page
)隐藏。clickEvent.runOnce
函数。clickEvent
是使用 resetableOnce
函数包装的点击事件处理函数,确保点击事件只执行一次。retry
函数开始尝试重新连接网络,最多尝试 5 次,每次尝试间隔 400 毫秒。handleLink
函数模拟网络连接尝试,尝试 7 次以上认为连接成功。retry
函数返回 “网络连接成功”,并在结果显示区域显示该信息。resetableOnce
函数的功能。retry
函数抛出错误,按钮文本恢复为 “点击重新连接网络”,重置点击事件状态,并在结果显示区域显示错误信息。clickEvent.reset()
函数重置点击事件状态。