首页 > 编程语言 >面试必备:从源码解析 Promise 方法的核心实现

面试必备:从源码解析 Promise 方法的核心实现

时间:2024-09-08 17:52:44浏览次数:3  
标签:resolve const res 必备 源码 Promise result reject

在这里插入图片描述

前言

手写Promise相关经常是各大公司手撕代码环节会被问到的问题,本文手把手带你实现一遍Promise的核心功能和方法。

基础功能实现

    const test = new Promise((reslove, reject) => {
      reslove("siu");
    });
    test.then((res) => {
      console.log(res); // siu
    });

接下来实现这一部分功能

const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class selfPromise {
  constructor(exec) {
    this.status = PENDING;
    this.result = null;
    // 用bind绑定this或resolve和reject用箭头函数 让它绑定到实例
    exec(this.resolve.bind(this), this.reject.bind(this));
  }
  resolve(result) {
    // 只有在PENDING状态下,才需要改变状态和记录结果
    // 这样也保证了Promise状态一旦改变就不能再改变
    // reject和reslove相同
    if (this.status === PENDING) {
      this.status = FULFILLED;
      this.result = result;
    }
  }
  reject(reason) {
    if (this.status === PENDING) {
      this.status = REJECTED;
      this.result = reason;
    }
  }
  then(onFULFILLED, onREJECTED) {
    if (this.status === FULFILLED) {
      onFULFILLED(this.result);
    }
    if (this.status === REJECTED) {
      onREJECTED(this.result);
    }
  }
}
const test = new selfPromise((resolve, reject) => {
  resolve("siu is good");
  //   reject("reject is good");
});
test.then(
  (res) => {
    console.log(res); // siu is good
  },
  (rej) => {
    console.log(rej); //reject is good
  }
);

实现异步逻辑和抛出错误

const test = new selfPromise((resolve, reject) => {
  setTimeout(() => {
    resolve("siu is good");
  });
  //   throw new Error("error");
});
test.then(
  (res) => {
    console.log(res); // 无输出
  },
  (rej) => {
    console.log(rej);
  }
);

因为setTimeout方法执行将resolve函数导致then方法比resolve先执行,所以当时Promise状态为pending,在then中还没有处理pending的情况,导致无输出。



处理执行函数时如果抛出错误 这时Promise的状态因由pending转为rejected,而捕获异常需要用到try catch

  constructor(exec) {
    this.status = PROMISE_PENDING_STATE;
    this.result = null;
    this.reason = null;
    this.resolveCallbacks = [];
    this.rejectCallbacks = [];
    try {
      exec(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error);
    }
  }
    resolve(result) {
    if (this.status === PENDING) {
      this.status = FULFILLED;
      this.result = result;
      this.resolveCallbacks.forEach((fn) => {
        fn(result);
      });
    }
  }
  reject(reason) {
    if (this.status === PENDING) {
      this.status = REJECTED;
      this.reason = reason;
      this.rejectCallbacks.forEach((fn) => {
        fn(reason);
      });
    }
  }
  then(onFULFILLED, onREJECTED) {
    if (this.status === PENDING) {
      this.resolveCallbacks.push(onFULFILLED);
      this.rejectCallbacks.push(onREJECTED);
    }
    if (this.status === FULFILLED) {
      onFULFILLED(this.result);
    }
    if (this.status === REJECTED) {
      onREJECTED(this.reason);
    }
  }
}
const test = new selfPromise((resolve, reject) => {
  setTimeout(() => {
    resolve("siu is good");
  });
  //   throw new Error("error");
});
test.then(
  (res) => {
    console.log(res); // siu is good
  },
  (rej) => {
    console.log(rej); //reject is good
  }
);

继续优化then功能

  1. 处理then函数参数
  then(onFULFILLED, onREJECTED) {
    // Promise 中的 then 方法回调参数都是可选的,当调用 then 方法未传参数时,需要给默认值
        onFULFILLED =
      typeof onFULFILLED === "function"
        ? onFULFILLED
        // 值穿透
        : (value) => {
            return value;
          };
    onREJECTED =
      typeof onREJECTED === "function"
        ? onREJECTED
        : (reason) => {
            throw reason;
          };
    ...
    }
    
  1. Promisethen方法是异步执行的。让then方法在同步任务完成后执行,通过setTimeout方法将then方法的执行延后,在同步任务执行完毕后then方法才会被调用。
  resolve(result) {
    setTimeout(() => {
      if (this.status === PENDING) {
        this.status = FULFILLED;
        this.result = result;
        this.resolveCallbacks.forEach((fn) => {
          fn(result);
        });
      }
    });
  }
  reject(reason) {
    setTimeout(() => {
      if (this.status === PENDING) {
        this.status = REJECTED;
        this.reason = reason;
        this.rejectCallbacks.forEach((fn) => {
          fn(reason);
        });
      }
    });
  }
  then(onFULFILLED, onREJECTED) {
    if (this.status === PENDING) {
      this.resolveCallbacks.push(onFULFILLED);
      this.rejectCallbacks.push(onREJECTED);
    }
    if (this.status === FULFILLED) {
      setTimeout(() => {
        onFULFILLED(this.result);
      });
    }
    if (this.status === REJECTED) {
      setTimeout(() => {
        onREJECTED(this.reason);
      });
    }
  }
}
console.log("1");
const test = new selfPromise((resolve, reject) => {
  resolve("siu is good");
});
test.then(
  (res) => {
    console.log("3  " + res);
  },
  (rej) => {}k
);
console.log("2");
//输出
//1 
//2
//3 siu is good
  1. 链式调用
    then方法的链式调用 要实现链式调用需要让then方法有返回值并且是Promise对象 下一个then方法会依赖上一个then方法的回调函数返回值
  then(onFULFILLED, onREJECTED) {
  ...
      //重复逻辑太多抽离成函数
      const fn = (fn) => {
        try {
          const result = fn(this.result);
          if (result instanceof selfPromise) {
            result.then(
              (res) => {
                resolve(res);
                // console.log(res);
              },
              (err) => {
                reject(err);
              }
            );
          } else {
            resolve(result);
          }
        } catch (err) {
          reject(err);
        }
      };
      if (this.status === FULFILLED) {
        setTimeout(() => {
          //   try {
          //     const result = onFULFILLED(this.result);
          //     resolvePromise(newPromise, result, resolve, reject);
          //   } catch (error) {
          //     reject(error);
          //   }
          fn(onFULFILLED);
        });
      }
      if (this.status === REJECTED) {
        setTimeout(() => {
          //   try {
          //     const reason = onREJECTED(this.result);
          //     resolvePromise(newPromise, reason, resolve, reject);
          //   } catch (error) {
          //     reject(error);
          //   }
          fn(onREJECTED);
        });
      }
      if (this.status === PENDING) {
        this.resolveCallbacks.push(() => {
          //   try {
          //     const result = onFULFILLED(this.result);
          //     resolvePromise(newPromise, result, resolve, reject);
          //   } catch (error) {
          //     reject(error);
          //   }
          fn(onFULFILLED);
        });
        this.rejectCallbacks.push(() => {
          //   try {
          //     const result = onREJECTED(this.result);
          //     resolvePromise(newPromise, result, resolve, reject);
          //   } catch (error) {
          //     reject(error);
          //   }
          fn(onREJECTED);
        });
      }
    });
    return newPromise;
    }
    const test = new selfPromise((resolve, reject) => {
  resolve("siu is good");
});
test
  .then((res) => {
    console.log("1   " + res);
    return new selfPromise((resolve, reject) => {
      resolve(res);
    });
  })
  .then((res) => {
    console.log(res);
  });
// 1 siu is good
// siu is good

Promise 实例对象方法的实现

catch

catch(onRejected):该方法是 then() 方法的一个特殊形式,用于注册对 Promise 拒绝状态的处理函数。它只接收一个参数 onRejected,表示在 Promise 拒绝时要执行的回调函数。catch() 方法也返回一个新的 Promise 对象,可以用于链式调用。

catch(onREJECTED) {
    return this.then(null, onREJECTED);
 }
 const test = new selfPromise((resolve, reject) => {
  reject("siu siu siu");
});
test.then().catch((rea) => {
  console.log(rea);
});
// siu siu siu
finally

finally(onFinally):该方法在 Promise 的状态最终确定后执行指定的回调函数,无论是解决还是拒绝状态。它接收一个参数 onFinally,表示要执行的回调函数。finally() 方法返回一个新的 Promise 对象,可以用于链式调用。

finally特点
  1. finally 没有参数
  2. 成功和失败都会走的回调
  3. 成功的返回值
  4. 错误是能捕获到的
  finally(onFinally) {
  // `then(() => value)` 表示 `onFinally` 执行完毕后,仍然返回原 Promise 的成功值 `value`。
    return this.then(
      (value) => selfPromise.resolve(onFinally()).then(() => value),
      (reason) =>
        selfPromise.resolve(onFinally()).then(() => {
          throw reason;
        })
    );
  }
  const test = new selfPromise((resolve, reject) => {
  reject("siu siu siu");
  //resolve("666");
});
test
  .then()
  .catch((rea) => {
    console.log(rea);
  })
  .finally(() => {
    console.log("123");
  });
  //siu siu siu
  //123

Promise 静态方法的实现

all

⭐⭐⭐ all:该方法接收一个可迭代对象(比如数组)作为参数,返回一个新的 Promise 对象。这个新的 Promise 对象在所有传入的 Promise 都解决时才会解决,并把所有解决结果按顺序作为数组传递给回调函数。如果传入的 Promise 中有任何一个被拒绝,它将立即拒绝并把第一个拒绝原因传递给回调函数

  static all(promises) {
    let result = [];
    let resolveCount = 0;
    return new selfPromise((resolve, reject) => {
      for (let i = 0; i < promises.length; i++) {
        promises[i].then(
          (res) => {
            // 记录数据
	        result[i] = res;
            resolveCount++;
            if (resolveCount === promises.length) {
              resolve(result);
            }
          },
          (reason) => {
            reject(reason);
          }
        );
      }
    });
  }
const t1 = Promise.resolve("1");
const t2 = Promise.resolve("2");
const t3 = Promise.resolve("3");
const t = selfPromise.all([t1, t2, t3]).then((res) => {
  console.log(res);
});

any

any:Promise.any(iterable)该方法接收一个可迭代对象(比如数组)作为参数,返回一个新的 Promise 对象。这个新的 Promise 对象在传入的任意一个 Promise 解决时立即解决,并将该解决值传递给回调函数。如果传入的所有 Promise 都被拒绝,它将立即拒绝并把所有拒绝原因作为数组传递给回调函数。

  static any(promises) {
    return new selfPromise((resolve, reject) => {
      const errors = [];
      let completedCount = 0;
      for (let i = 0; i < promises.length; i++) {
        promises[i].then(
          (res) => {
            resolve(res);
          },
          (err) => {
            errors.push({ index: i, err});
            completedCount++;
            if (completedCount === promises.length) {
              reject(new AggregateError(errors));
            }
          }
        );
      }
   });
  }
race

race(iterable):该方法接收一个可迭代对象(比如数组)作为参数,返回一个新的 Promise 对象。这个新的 Promise 对象在传入的任意一个 Promise 解决或拒绝时立即解决或拒绝,并把第一个解决或拒绝的结果传递给回调函数。

  static race(promises) {
    return new selfPromise((resolve, reject) => {
      for (let i = 0; i < promises.length; i++) {
        promises[i].then(
          (res) => {
            resolve(res);
          },
          (reason) => {
            reject(reason);
          }
        );
      }
    });
  }
const t1 = Promise.resolve("1");
const t2 = Promise.resolve("2");
const t3 = Promise.resolve("3");
const t4 = Promise.reject("4");
selfPromise.race([t2, t1, t3, t4]).then((res) => {
  console.log(res);
});
// 2
Promise.allSettled

allSettled:该方法接收一个可迭代对象(比如数组)作为参数,返回一个新的 Promise 对象。这个新的 Promise 对象在传入的所有 Promise 都已解决或拒绝时才会解决,并把所有 Promise 的最终结果作为对象数组传递给回调函数。每个对象包含一个 status 属性,表示 Promise 的状态(“fulfilled” 表示解决,“rejected” 表示拒绝),以及一个 valuereason 属性,分别表示解决值或拒绝原因。

  static allSettled(promises) {
    return new selfPromise((resolve) => {
      const results = [];
      let pendingCount = promises.length;
      for (let i = 0; i < promises.length; i++) {
        promises[i]
          .then(
            (value) => {
              results[i] = { status: "fulfilled", value };
            },
            (reason) => {
              results[i] = { status: "rejected", reason };
            }
          )
          .finally(() => {
            pendingCount--;
            if (pendingCount === 0) {
              resolve(results);
            }
          });
      }
    });
  }
const t1 = Promise.resolve("1");
const t2 = Promise.resolve("2");
const t3 = Promise.resolve("3");
const t4 = Promise.reject("4");
selfPromise.allSettled([t1, t2, t3, t4]).then((res) => {
  console.log(res);
});
// [
//     { status: 'fulfilled', value: '1' },
//     { status: 'fulfilled', value: '2' },
//     { status: 'fulfilled', value: '3' },
//     { status: 'rejected', reason: '4' }
//   ]

Promise.defer

它的目的是提供一个接口,让你可以创建一个 Promise 并直接访问其 resolvereject 方法。不过Promise.defer是一个非标准的用法。被现代 Promise 构造函数替代

Promise.defer = function(){

let resolve, reject;

// 创建一个新的 Promise

const promise = new Promise((res, rej) => {

resolve = res;

reject = rej;

});

// 返回包含 promise、resolve 和 reject 的对象

return { promise, resolve, reject };

}

function setDelay(test){

  

// return new Promise((res,rej) => {

let {promise,resolve,reject} =Promise.defer()

setTimeout(() => {

resolve(test)

})

// })

return promise

}

最后的完整代码

const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class selfPromise {
  constructor(exec) {
    this.status = PENDING;
    this.result = null;
    this.resolveCallbacks = [];
    this.rejectCallbacks = [];
    exec(this.resolve.bind(this), this.reject.bind(this));
  }
  resolve(result) {
    setTimeout(() => {
      if (this.status === PENDING) {
        this.status = FULFILLED;
        this.result = result;
        this.resolveCallbacks.forEach((fn) => {
          fn(result);
        });
      }
    });
  }
  reject(result) {
    setTimeout(() => {
      if (this.status === PENDING) {
        this.status = REJECTED;
        this.result = result;
        this.rejectCallbacks.forEach((fn) => {
          fn(result);
        });
      }
    });
  }
  then(onFULFILLED, onREJECTED) {
    // Promise 中的 then 方法回调参数都是可选的,当调用 then 方法未传参数时,需要给默认值
    onFULFILLED =
      typeof onFULFILLED === "function"
        ? onFULFILLED
        : (value) => {
            return value;
          };
    onREJECTED =
      typeof onREJECTED === "function"
        ? onREJECTED
        : (reason) => {
            throw reason;
          };
    const newPromise = new selfPromise((resolve, reject) => {
      const fn = (fn) => {
        try {
          const result = fn(this.result);
          if (result instanceof selfPromise) {
            result.then(
              (res) => {
                resolve(res);
              },
              (err) => {
                reject(err);
              }
            );
          } else {
            resolve(result);
          }
        } catch (err) {
          reject(err);
        }
      };
      if (this.status === FULFILLED) {
        setTimeout(() => {
          fn(onFULFILLED);
        });
      }
      if (this.status === REJECTED) {
        setTimeout(() => {
          fn(onREJECTED);
        });
      }
      if (this.status === PENDING) {
        this.resolveCallbacks.push(() => {
          fn(onFULFILLED);
        });
        this.rejectCallbacks.push(() => {
          fn(onREJECTED);
        });
      }
    });
    return newPromise;
  }
  catch(onREJECTED) {
    return this.then(null, onREJECTED);
  }
  finally(onFinally) {
    return this.then(
      (value) => selfPromise.resolve(onFinally()).then(() => value),
      (reason) =>
        selfPromise.resolve(onFinally()).then(() => {
          throw reason;
        })
    );
  }
  static resolve(result) {
    return new selfPromise((resolve, reject) => {
      if (result instanceof selfPromise) {
        result.then(
          (res) => {
            resolve(res);
          },
          (err) => {
            reject(err);
          }
        );
      } else {
        resolve(result);
      }
    });
  }

  static reject(result) {
    return new selfPromise((resolve, reject) => {
      reject(result);
    });
  }
  static all(promises) {
    let result = [];
    let resolveCount = 0;
    return new selfPromise((resolve, reject) => {
      for (let i = 0; i < promises.length; i++) {
        promises[i].then(
          (res) => {
            // 记录数据
            result[i] = res;
            resolveCount++;
            if (resolveCount === promises.length) {
              resolve(result);
            }
          },
          (reason) => {
            reject(reason);
          }
        );
      }
    });
  }
  static any(promises) {
    return new selfPromise((resolve, reject) => {
      const errors = [];
      let completedCount = 0;
      for (let i = 0; i < promises.length; i++) {
        promises[i].then(
          (res) => {
            resolve(res);
          },
          (err) => {
            errors.push({ index: i, err });
            completedCount++;
            if (completedCount === promises.length) {
              reject(new AggregateError(errors));
            }
          }
        );
      }
    });
  }
  static race(promises) {
    return new selfPromise((resolve, reject) => {
      for (let i = 0; i < promises.length; i++) {
        promises[i].then(
          (res) => {
            resolve(res);
          },
          (reason) => {
            reject(reason);
          }
        );
      }
    });
  }
  static allSettled(promises) {
    return new selfPromise((resolve) => {
      const results = [];
      let pendingCount = promises.length;
      for (let i = 0; i < promises.length; i++) {
        promises[i]
          .then(
            (value) => {
              results[i] = { status: FULFILLED, value };
            },
            (reason) => {
              results[i] = { status: REJECTED, reason };
            }
          )
          .finally(() => {
            pendingCount--;
            if (pendingCount === 0) {
              resolve(results);
            }
          });
      }
    });
  }
}

Promise补充内容

Promise超时相关实现

使用 Promise.race 来实现一个带超时功能的 fetchData 函数。fetchData 函数会在 5 秒钟后解析,而 withTimeout 函数会在给定的超时时间内,如果 fetchData 函数还没有完成,则会拒绝。

function fetchData(){

return new Promise((resolve,reject) => {

setTimeout(() => {

// console.log('1')

resolve('数据以获取')

},5000)

})

}

function withTimeout(promise,ms){

const timeoutPromise = new Promise((res,rej) => {

const timeout = setTimeout(() => {

clearTimeout(timeout)

// console.log('超时')

rej(new Error('超时'))

}, ms);

})

  

return Promise.race([promise,timeoutPromise])

}

  

withTimeout(fetchData(),2000).then(() => {

console.log('123')

}).catch((err) => {

console.log(err + '123')

})
中断promise的链式调用

代码中返回了一个永远不会完成的 Promise,因为它既没有调用 resolve 也没有调用 reject。这种情况会使得链式调用挂起,后续的 thencatch 处理都不会被执行。Promise 链会被“中断”,因为 stopChain 返回的 Promise 永远不会完成。

  

function stopChain(){

return new Promise((resolve,reject)=>{})

}

Promise.resolve().then(() => {

console.log(1)

return stopChain()

}).then(() => {

console.log(2)

}).catch((err) => {

console.log(err)

})

Promise超时重连

fetchWithRetry 函数是一个用于执行带有重试机制的网络请求的工具。这个函数接受两个参数:urlretries。其中,url 是要请求的资源的地址,retries 是允许的最大重试次数,默认值为 3 次。该函数返回一个 Promise 对象,用于处理异步操作。

function fetchWithRetry(url,retries=3){

return new Promise((resolve,reject) => {

function attemptFetch(count) {

fetch(url).then((res) => {

console.log(res)

if(!res.ok){

throw new Error("网络错误")

}

return resolve(res.json())

}).catch((error) => {

console.log(1)

if(count <= retries){

console.log()

setTimeout(() => {

console.log(`正在尝试重连... 第${count}/${retries}次 `)

return attemptFetch(count + 1)

}, 1000);

}else{

reject(error)

}

})

}

attemptFetch(1)

})

}
//实验直接把url搞错就行
const url = "https://jsonplaceholder.typicode.com/posts"

fetchWithRetry(url).then((res) => {

console.log(res)

}

)


请添加图片描述

串行和并行

串行: 异步任务顺序执行,适合任务有严格顺序要求的情况。
并行: 异步任务同时执行,适合任务独立且可同时进行的情况。时间由最长时间的

//串行
task1().then(() => task2()).then(() => task3());
//并行
Promise.all([task1(), task2(), task3()]).then(() => {  });

总结

代码可优化的东西很多,更多作为自我学习,也希望对你有所帮助。

标签:resolve,const,res,必备,源码,Promise,result,reject
From: https://blog.csdn.net/weixin_63625059/article/details/142030330

相关文章

  • 基于SpringBoot的美食分享平台设计与实现,LW+源码+部署讲解
    一、绪论1.1研究意义当今社会作为一个飞速的发展社会,网络已经完全渗入人们的生活,网络信息已成为传播的第一大媒介,可以毫不夸张说网络资源获取已逐步改变了人们以前的生活方式,网络已成为人们日常,休闲主要工具。人们记录、分享和发现美食的方式正在逐渐发生改变,因此借助怎......
  • 基于JAVA的景区行李寄存系统设计与实现,LW+源码+部署讲解
    摘要 针对传统人工行李寄存效率低和安全性不足等问题,设计并实现了一种由网页控制器组成的智能行李寄存系统。首先能够实现行李的寄存管理和行李柜管理以及记录查询和通知公告以及管理员等灵活控制菜单显示权限。经过研究和测试结果显示,该行李寄存系统实现了行李的安全、高效......
  • 基于Javaweb实现的物流管理系统设计与实现(源码+数据库+论文+部署+文档+讲解视频等)
    文章目录1.前言2.详细视频演示3.论文参考4.项目运行截图5.技术框架5.1后端采用SpringBoot框架5.2前端框架Vue6.可行性分析7.系统测试7.1系统测试的目的7.2系统功能测试8.数据库表设计9.代码参考10.数据库脚本11.作者推荐项目12.为什么选择我?13.获取源......
  • 基于Java实现的酒店管理系统设计与实现(源码+数据库+部署+文档+讲解视频等)
    文章目录1.前言2.详细视频演示3.论文参考4.项目运行截图5.技术框架5.1后端采用SpringBoot框架5.2前端框架Vue6.可行性分析7.系统测试7.1系统测试的目的7.2系统功能测试8.数据库表设计9.代码参考10.数据库脚本11.作者推荐项目12.为什么选择我?13.获取源......
  • FreeRTOS 队列 Queue 源码解析
    目录一、队列1、队列结构体2、队列类型二、队列相关操作1、初始化1.1静态创建队列1.2动态创建队列1.3队列的初始化1.4队列的重置2、队列的发送2.1任务级入队函数2.1.1入队函数2.1.2队列锁2.1.3portYIELD_WITHIN_API2.2中断级入队函数3、任务的读取3.1任务......
  • 基于vue.js和node.js的在线购物网站设计和实现----附源码83077
    目 录摘要1绪论1.1研究背景1.2 研究意义1.3论文结构与章节安排2 系统分析2.1可行性分析2.2系统流程分析2.2.1数据新增流程2.2.2 数据删除流程2.3 系统功能分析2.3.1功能性分析2.3.2非功能性分析2.4 系统用例分析3系统总体设计......
  • 基于Web的会议记录与分享系统设计与实现---附源码83155
    目  录摘要第1章绪论1.1研究背景与意义1.2开发现状第2章相关技术介绍2.1JAVA技术2.2springboot框架2.3MySQL数据库第3章系统分析3.1可行性分析3.2功能需求分析3.2.1注册用户功能3.3非功能需求分析3.4安全性需求分析3.4.1系统的......
  • 基于yolov10的行人跌倒检测系统,支持图像检测,也支持视频和摄像实时检测(pytorch框架)【py
       更多目标检测和图像分类识别项目可看我主页其他文章功能演示:基于yolov10的行人跌倒检测系统,支持图像、视频和摄像实时检测【pytorch框架、python】_哔哩哔哩_bilibili(一)简介基于yolov10的行人跌倒检测系统是在pytorch框架下实现的,这是一个完整的项目,包括代码,数据集,训......
  • 八,SpringBoot Web 开发访问静态资源(附+详细源码剖析)
    八,SpringBootWeb开发访问静态资源(附+详细源码剖析)@目录八,SpringBootWeb开发访问静态资源(附+详细源码剖析)1.基本介绍2.快速入门2.1准备工作3.改变静态资源访问前缀,定义为我们自己想要的4.改变SpringBoot当中的默认的静态资源路径(实现自定义静态资源路径)5.静态资......
  • 8---阶段项目:五子棋(附带源码)
    8阶段项目:五子棋8.1-技术实现1.静态变量静态变量只能定义在类中,不能定义在方法中。静态变量可以在static修饰的方法中使用,也可以在非静态的方法中访问。主要解决在静态方法中不能访问非静态的变量。2.静态方法静态方法就相当于一个箱子,只是这个箱子中装的是代码,需要使用......