手写promis(1)

目录

前言

核心功能--构造函数 

核心功能--状态及原因

then方法

成功和失败回调

异步及多次调用

异步任务--核心api

Promise.then:

queueMicrotask:

MutationObserver:

setImmediate:

setTimeout:

异步任务---函数封装


前言

Promise(承诺)是一种用于处理异步操作的JavaScript编程技术。它是一种代表一个尚未完成的操作的对象,该操作可能会在将来的某个时刻完成或失败。Promise提供了一种更结构化和可维护的方式来处理异步代码,特别是在处理网络请求、文件I/O、定时器等操作时非常有用。

Promise对象有三种状态:

  1. Pending(进行中):初始状态,表示操作尚未完成或失败。
  2. Fulfilled(已完成):表示操作成功完成。
  3. Rejected(已失败):表示操作失败。

Promise对象具有两个重要的方法:

  1. then(): 用于注册回调函数,当Promise状态变为Fulfilled时执行。
  2. catch(): 用于注册回调函数,当Promise状态变为Rejected时执行。

使用Promise,可以更清晰地定义异步操作的工作流程,避免了回调地狱(Callback Hell)的问题,使代码更易于理解和维护。以下是一个简单的Promise示例:

const myPromise = new Promise((resolve, reject) => {
  // 异步操作
  setTimeout(() => {
    const randomValue = Math.random();
    if (randomValue > 0.5) {
      resolve("操作成功");
    } else {
      reject("操作失败");
    }
  }, 1000);
});

myPromise
  .then(result => {
    console.log(result); // 在操作成功时执行
  })
  .catch(error => {
    console.error(error); // 在操作失败时执行
  });

这个示例创建了一个Promise对象,模拟了一个异步操作,并根据随机值决定是成功还是失败。通过.then().catch()方法,我们可以分别处理成功和失败的情况。这使得异步代码的处理更加结构化和可控。

手写原来步骤

核心功能--构造函数 

  1. 定义类(Define the class): 这里定义了一个名为MyPromise的类,用于创建自定义Promise对象。

  2. 添加构造函数(Add a constructor): 在构造函数中,通过constructor方法定义了一个新的MyPromise对象。当创建MyPromise对象时,会执行构造函数。构造函数接受一个函数func作为参数,这个函数在创建MyPromise对象时传入。

  3. 定义resolve/reject(Define resolve and reject functions): 在构造函数中,定义了resolvereject函数,它们分别用于处理Promise的成功和失败情况。resolve函数用于处理成功情况,它接受一个参数result,表示成功的原因。reject函数用于处理失败情况,它也接受一个参数result,表示失败的原因。

  4. 执行回调函数(Execute the callback function): 最后,构造函数中调用了传入的func函数,这个函数接受resolvereject作为参数。这意味着在创建MyPromise对象时,会执行传入的回调函数,并在适当的时候调用resolvereject函数来处理异步操作的结果

/**
 * 构造函数
 * 1. 定义类
 * 2. 添加构造函数
 * 3. 定义reslove/reject
 * 4. 执行回调函数
 */

//1.定义类
class MyPromise {
    // 2.添加构造函数 new时会执行 constructor 传入回调函数
    constructor(func) {
        // 3.func 接受两个行参 成功回调(成功原因),失败回调(失败原因)
        // resolve:<Function>(result:<any>)  reject:<Function>(result:<any>) 
        const resolve = (result) => {
            console.log('resolve执行了--', result);
        }
        const reject = (result) => {
            console.log('reject执行了--', result);
        }

        // 4. 执行回调函数
        func(resolve, reject)
    }
}


// 测试代码
const p = new MyPromise((resolve, reject) => {
    console.log('执行回调函数');
    // resolve('success')
    reject('error')
})

核心功能--状态及原因

  1. 添加实例属性状态(pending / fulfilled / rejected)(默认为等待)

  2. 添加实例属性原因(默认为undefined)

  3. 调整resolve函数和reject函数 resolvereject函数改变状态和保存原因,这是Promise的核心功能之一。

  4. 添加状态检查:在resolvereject函数中,添加状态检查来确保状态只能从pending改变一次。这可以防止状态被多次改变。
/**
 * 状态及原因
 * 1. 添加状态 pending / fulfilled / rejected
 * 2. 添加原因
 * 3. 调整reslove/reject
 * 4. 状态不可逆
 */

//通过变量保存状态,方便使用
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
    // 1. 添加实例属性 状态(pending / fulfilled / rejected)(默认为等待)
    state = PENDING
    // 2. 添加实例属性 原因(默认为undefined)
    result = undefined
    constructor(func) {
        // this 箭头函数this-->上级作用域(构造函数)-->  实例 
        // 3. 调整reslove pending-- > fulfilled 添加原因
        const resolve = (result) => {
            // 4. 状态不可逆
            if (this.state == PENDING) {
                this.state = FULFILLED
                this.result = result
            }
        }

        // 3. reject pending-- > rejected 添加原因
        const reject = (result) => {
            if (this.state == PENDING) {
                this.state = REJECTED
                this.result = result
            }
        }

        func(resolve, reject)
    }
}


// 测试代码
const p = new MyPromise((resolve, reject) => {

    resolve('success')
    // reject('error')
})

then方法

成功和失败回调

  1. 添加实例方法(then)
  2. 参数判断(参考文档)

如果是个函数 执行回调函数 

如果 onFulfilled 不是一个函数,则内部会被替换为一个恒等函数((x) => x),它只是简单地将兑现值向前传递。

如果 onRejected 不是一个函数,则内部会被替换为一个抛出器函数((x) => { throw x; }),它会抛出它收到的拒绝原因。

3.判断状态执行成功回调函数or失败回调函数(实例化完成后状态已经确定)

/**
 * 成功和失败回调
 * 1. 添加实例方法
 * 2. 参数判断(参考文档)
 *  2.1. 执行成功回调
 *  2.2. 执行失败回调
 */

//通过变量保存状态,方便使用
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
    state = PENDING
    result = undefined
    constructor(func) {
        const resolve = (result) => {
            if (this.state == PENDING) {
                this.state = FULFILLED
                this.result = result
            }
        }

        const reject = (result) => {
            if (this.state == PENDING) {
                this.state = REJECTED
                this.result = result
            }
        }

        func(resolve, reject)
    }
    // 添加实例方法
    then(onFulfilled, onRejected) {
        // 参数判断  如果 onFulfilled 不是一个函数,则内部会被替换为一个恒等函数((x) => x),它只是简单地将兑现值向前传递。
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
        // 参数判断  如果 onRejected 不是一个函数,则内部会被替换为一个抛出器函数((x) => { throw x; }),它会抛出它收到的拒绝原因。
        onRejected = typeof onRejected === 'function' ? onRejected : (x) => { throw x }

        // 执行成功回调or执行失败回调(状态实例化完成就立即调用了,所以可以执行返回结果--》异步暂时不考虑)
        if (this.state === FULFILLED) {
            onFulfilled(this.result)
        } else if (this.state === REJECTED) {
            onRejected(this.result)
        }

    }
}


// 测试代码
const p = new MyPromise((resolve, reject) => {

    // resolve('success')
    reject('error')
})
// p.then((result) => {
//     console.log('成功回调', result)
// }, err => {
//     console.log('失败回调', err);
// })
p.then((result) => {
    console.log('成功回调', result)
})

异步及多次调用

  1. 定义实例属性,添加#为类内部使用标识
  2. 如果then执行后状态为pending存储异步时成功回调与失败回调
  3. 定时器两秒后 resolve执行 取出成功回调函数放入成功原因

  4. 定时器两秒后 reject执行 取出失败回调函数放入失败原因

/**
 * then-异步及多次调用
 * 1. 定义实例属性
 * 2. 保存回调函数
 * 3. 调用成功回调
 * 4. 调用失败回调
 */

//通过变量保存状态,方便使用
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
    state = PENDING
    result = undefined
    // 定义实例属性 #外部不能访问 保存回调
    #handlers = []//[{onFulfilled,onRejected}...]
    constructor(func) {
        const resolve = (result) => {
            if (this.state == PENDING) {
                this.state = FULFILLED
                this.result = result
                // 3.定时器两秒后 resolve执行 取出成功回调函数放入成功原因
                this.#handlers.forEach(({ onFulfilled }) => {
                    onFulfilled(this.result)
                })
            }
        }

        const reject = (result) => {
            if (this.state == PENDING) {
                this.state = REJECTED
                this.result = result
                // 4.定时器两秒后 reject执行 取出失败回调函数放入失败原因
                this.#handlers.forEach(({ onRejected }) => {
                    onRejected(this.result)
                })
            }
        }

        func(resolve, reject)
    }

    then(onFulfilled, onRejected) {

        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x

        onRejected = typeof onRejected === 'function' ? onRejected : (x) => { throw x }

        if (this.state === FULFILLED) {
            onFulfilled(this.result)
        } else if (this.state === REJECTED) {
            onRejected(this.result)
        } else if (this.state === PENDING) {
            // 2. 代表状态还没有发生过改变,保存回调函数
            this.#handlers.push({
                onFulfilled, onRejected
            })
        }

    }
}


// 测试代码
const p = new MyPromise((resolve, reject) => {

    setTimeout(() => {
        // resolve('success')
        reject('error')
    }, 2000);
})
p.then((result) => {
    console.log('成功回调', result)
}, err => {
    console.log('失败回调', err);
})
p.then((result) => {
    console.log('成功回调', result)
})

异步任务--核心api

 * Vue Promise.then, MutationObserver,setImmediate,setTimeout

 * 我们选用 queueMicrotask MutationObserver setTimeout

  • Promise.then,手写promise 不考虑这个
  • queueMicrotask:node11,新式浏览器(不包括ie11)
  • MutationObserver node不支持 ie11支持
  • setImmediate:ie10,11支持 edge:(12-18)支持(不考虑)
  • setTimeout:node,浏览器全支持

Promise.then:

  • 兼容性: 几乎所有现代浏览器和Node.js都支持Promise。
  • 用法: Promise是一种用于处理异步操作的机制,通过.then()方法可以注册回调函数来处理异步任务的完成或失败。例如:
const myPromise = new Promise((resolve, reject) => {
  // 异步操作
  if (/* 操作成功 */) {
    resolve(result);
  } else {
    reject(error);
  }
});

myPromise.then(
  (result) => {
    // 处理成功的情况
  },
  (error) => {
    // 处理失败的情况
  }
);

queueMicrotask:

Window 或 Worker 接口的 queueMicrotask() 方法,将微任务加入队列以在控制返回浏览器的事件循环之前的安全时间执行。

微任务是一个简短的函数,它将在当前任务完成其工作后运行,并且在执行上下文的控制权返回到浏览器的事件循环之前没有其他代码等待运行时运行。

它让你的代码在运行时不会干扰任何可能具有更高优先级的代码的运行,但在浏览器重新获得对执行上下文的控制之前,这可能取决于你需要完成的工作。你可以在我们的微任务指南中了解更多关于如何使用微任务以及选择这样做的原因。

微任务的重要性在于它能够以特定顺序异步执行任务。查看在 JavaScript 中通过 queueMicrotask() 使用微任务的详情。

微任务对于需要执行最后阶段的任务或其他在渲染之前的任务的库和框架特别有用。

参数

当浏览器引擎确定可以安全调用你的代码时执行的 function。微任务(microtask)的执行顺序在所有进行中的任务(pending task)完成之后,在对浏览器的事件循环产生控制(yielding control to the browser's event loop)之前。

返回值

无 undefined

  • 兼容性: 支持新式浏览器,但不包括IE11。
  • 用法: queueMicrotask用于将微任务排入微任务队列中,通常在Promise处理中使用,以确保微任务在宏任务之后执行。示例:
queueMicrotask(() => {
  // 这里执行微任务
});

MutationObserver:

MutationObserver 接口提供了监视对 DOM 树所做更改的能力。它被设计为旧的 Mutation Events 功能的替代品,该功能是 DOM3 Events 规范的一部分。

构造函数

MutationObserver()

创建并返回一个新的 MutationObserver 它会在指定的 DOM 发生变化时被调用。

方法

disconnect()

阻止 MutationObserver 实例继续接收的通知,直到再次调用其 observe() 方法,该观察者对象包含的回调函数都不会再被调用。

observe()

配置 MutationObserver 在 DOM 更改匹配给定选项时,通过其回调函数开始接收通知。

takeRecords()

从 MutationObserver 的通知队列中删除所有待处理的通知,并将它们返回到 MutationRecord 对象的新 Array 中。

  • 兼容性: 在大多数现代浏览器中支持,但Node.js不支持,而IE11也支持。
  • 用法: MutationObserver用于监视DOM树的变化,并在发生变化时触发回调函数。这通常用于监听DOM元素的变化。示例:
// 选择需要观察变动的节点
const targetNode = document.getElementById("some-id");

// 观察器的配置(需要观察什么变动)
const config = { attributes: true, childList: true, subtree: true };

// 当观察到变动时执行的回调函数
const callback = function (mutationsList, observer) {
  // Use traditional 'for loops' for IE 11
  for (let mutation of mutationsList) {
    if (mutation.type === "childList") {
      console.log("A child node has been added or removed.");
    } else if (mutation.type === "attributes") {
      console.log("The " + mutation.attributeName + " attribute was modified.");
    }
  }
};

// 创建一个观察器实例并传入回调函数
const observer = new MutationObserver(callback);

// 以上述配置开始观察目标节点
observer.observe(targetNode, config);

// 之后,可停止观察
observer.disconnect();

setImmediate:

setImmediate参数设置:第一个参数是需要执行的方法,第二个参数到第n个参数是传入方法中的参数。

setImmediate表示立即执行,它是宏任务,回调函数会被放置到事件循环的check阶段。
在应用中如果大量的计算型任务,它是不适合放在主线程中执行的,因为计算任务会阻塞主线程,主线程一旦被阻塞,其他任务就需要等待,
可以通过setImmediate方法将任务放入事件循环中的check阶段,因为代码在这一个阶段执行不会阻塞主线程,也不会阻塞事件循环
 

  • 兼容性: 主要支持IE10和IE11,以及一些较旧版本的Edge浏览器。
  • 用法: setImmediate用于将函数排入宏任务队列,以便在当前任务完成后立即执行。示例:
function sleep(delay) {
  var start = new Date().getTime()
  while (new Date().getTime() - start < delay) {
    continue
  }
  console.log('ok')
}

console.log('start')
setImmediate(sleep, 2000)
console.log('end')

先打印出start,然后再打印end,最后等待2000ms后打印ok。 

setTimeout:

  • 兼容性: 在Node.js和几乎所有现代浏览器中都支持。
  • 用法: setTimeout用于在一定时间后将函数排入宏任务队列。它是处理异步操作的常用方法。示例:
setTimeout(() => {
  // 这里执行宏任务
}, 1000);

异步任务---函数封装

  •  1.定义函数
  •  2.调用核心api(queueMicrotask,MutationObserver,setTimeout)
  •  3.使用封装的函数

 在then方法中使用无论promse是啥状态都需要直接或者间接的执行回调函数

/**
 * 异步任务--函数封装
 * 1.定义函数
 * 2.调用核心api(queueMicrotask,MutationObserver,setTimeout)
 * 3.使用封装的函数
 */

//1.定义函数
function runAsyncTask(callback) {
  //  2.调用核心api(queueMicrotask,MutationObserver,setTimeout)
  if (typeof queueMicrotask === "function") {
    queueMicrotask(callback);
  } else if (typeof MutationObserver == "function") {
    const obs = new MutationObserver(callback);
    const divNode = document.createElement("div");
    obs.observe(divNode, { childList: true });
    divNode.innerHTML = "贾公子";
  } else {
    setTimeout(callback, 0);
  }
}

const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

class MyPromise {
  state = PENDING;
  result = undefined;
  #handlers = [];
  constructor(func) {
    const resolve = (result) => {
      if (this.state == PENDING) {
        this.state = FULFILLED;
        this.result = result;
        this.#handlers.forEach(({ onFulfilled }) => {
          onFulfilled(this.result);
        });
      }
    };

    const reject = (result) => {
      if (this.state == PENDING) {
        this.state = REJECTED;
        this.result = result;
        this.#handlers.forEach(({ onRejected }) => {
          onRejected(this.result);
        });
      }
    };

    func(resolve, reject);
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (x) => x;

    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (x) => {
            throw x;
          };
    // 3.使用封装的函数
    if (this.state === FULFILLED) {
      runAsyncTask(() => {
        onFulfilled(this.result);
      });
    } else if (this.state === REJECTED) {
      runAsyncTask(() => {
        onRejected(this.result);
      });
    } else if (this.state === PENDING) {
      this.#handlers.push({
        // 成功或者失败后调用 onFulfilled
        // onFulfilled 执行之后调用runAsyncTask(传入:promise传入的回调)
        //runAsyncTask内部执行了回调 onFulfilled
        onFulfilled: () => {
          runAsyncTask(() => {
            onFulfilled(this.result);
          });
        },
        onRejected: () => {
          runAsyncTask(() => {
            onRejected(this.result);
          });
        },
      });
    }
  }
}

// 测试代码
console.log("TOP");
const p = new MyPromise((resolve, reject) => {
  // resolve("success");
  reject("error");
});
p.then(
  (result) => {
    console.log("成功回调", result);
  },
  (err) => {
    console.log("失败回调", err);
  }
);
console.log("BOTTOM");

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/168364.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

竞赛选题 行人重识别(person reid) - 机器视觉 深度学习 opencv python

文章目录 0 前言1 技术背景2 技术介绍3 重识别技术实现3.1 数据集3.2 Person REID3.2.1 算法原理3.2.2 算法流程图 4 实现效果5 部分代码6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习行人重识别(person reid)系统 该项目…

KiCad源代码研究:KiCad是如何渲染和绘图的。

common.json文件中appearance.show_scrollbars common.json对应于代码的common_settings 1.EDA_DRAW_PANEL_GAL类 EDA_DRAW_PANEL_GAL类中定义了绘图的基本要素&#xff1a; /// Interface for drawing objects on a 2D-surfaceKIGFX::GAL* m_gal;/// Stores v…

如何在公网环境下使用笔记本的Potplayer访问本地群晖webdav中的影视资源

文章目录 如何在公网环境下使用笔记本的Potplayer访问本地群晖webdav中的影视资源**那么问题来了&#xff0c;potplayer只能局域网内访问资源&#xff0c;那我不在家中怎么看本地电影&#xff1f;** 本教程解决的问题是&#xff1a;按照本教程方法操作后&#xff0c;达到的效果…

目标检测 Faster RCNN全面解读复现

Faster RCNN 解读 经过R-CNN和Fast RCNN的积淀&#xff0c;Ross B. Girshick在2016年提出了新的Faster RCNN&#xff0c;在结构上&#xff0c;Faster RCNN已经将特征抽取(feature extraction)&#xff0c;proposal提取&#xff0c;bounding box regression(rect refine)&…

DGL创建异构图

利用DGL创建具有3种节点类型和3种边类型的异构图 graph_data {# (src_type, edge_type, dst_type)(drug, interacts, drug): (th.tensor([0, 1]), th.tensor([1, 2])),(drug, interacts,, disease): (th.tensor([1]), th.tensor([2])) }g dgl.heterograph(graph_data)上述代…

110.firefly-overlayroot

折腾rk3399的开发板的时候&#xff0c;突然发现overlayroot这个词汇。 我移植一下linux5.10的内核到firefly3399开发板&#xff0c;结果启动之后文件系统提示只读&#xff01;&#xff01;&#xff01; 这就让我很莫名。后来看到mount文件系统的情况&#xff0c;感觉也是不可…

集成多元算法,打造高效字面文本相似度计算与匹配搜索解决方案,助力文本匹配冷启动[BM25、词向量、SimHash、Tfidf、SequenceMatcher]

搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术细节以及项目实战(含码源) 专栏详细介绍:搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术…

图解算法数据结构-LeetBook-栈和队列03_验证栈的取出顺序

现在图书馆有一堆图书需要放入书架&#xff0c;并且图书馆的书架是一种特殊的数据结构&#xff0c;只能按照 一定 的顺序 放入 和 拿取 书籍。 给定一个表示图书放入顺序的整数序列 putIn&#xff0c;请判断序列 takeOut 是否为按照正确的顺序拿取书籍的操作序列。你可以假设放…

万宾科技智能井盖传感器,预防城市道路安全

随着城市交通的不断发展和城市化进程的加速推进&#xff0c;城市道路安全问题日益凸显。市政井盖作为城市道路的一部分&#xff0c;承担着重要的交通安全保障职责。然而传统的市政井盖管理方式存在许多不足。针对这些问题政府需要采取适当的措施&#xff0c;补足传统管理方式的…

bitmap实践-留存计算

目录 1. 介绍2. 留存问题3. 思路解析4. 逻辑4.1 b表建设4.2 留存计算4.3 近X天的访问天数 5.分析 1. 介绍 bitmap方法是数据压缩使用的常用算法&#xff0c;当字段有明确上下界的时候&#xff0c;使用位图模式来减少存储。在业务指标体系中特别适合通用型留存指标的计算。 2.…

RAID技术复习笔记

Raid&#xff08;Redundant Array of independent Disks&#xff09;独立磁盘冗余阵列&#xff1a;磁盘阵列 Raid 分为:软raid、硬raid、软硬混合三种。 软Raid&#xff1a;所有的功能均有操作系统和CPU来完成&#xff0c;没有独立的raid控制、处理芯片和IO处理处理芯片。 硬R…

如何从零开始制作一本企业宣传画册?

最近公司领导要求为公司制作一本企业宣传画册&#xff0c;用来展示我们的产品和服务&#xff0c;增加品牌影响力。可是&#xff0c;像我这种零基础的小白&#xff0c;完全不知道如何制作啊&#xff1f;对此我感到很焦虑&#xff0c;怕做不好影响公司形象&#xff0c;也怕耽误时…

LR学习笔记——初识lightroom

文章目录 介绍图库界面修改照片界面 介绍 Lightroom是Adobe公司开发的一款用于图片后期处理制作的软件&#xff0c;被称为Adobe Photoshop Lightroom。其增强的校正工具、强大的组织功能以及灵活的打印选项可以帮助加快图片后期处理速度&#xff0c;将更多的时间投入拍摄。 相…

Navicat DML 操作

在表格种插入 列信息 -- 修改数据 update 表名 set 列名 值1, 列名值2,[where 条件]; -- 注意&#xff1a;如果update语句没有加where 表里对应行的全部信息都会被改; -- 删除数据 delecte from 表名 [where 条件]; 未删除前&#xff1a; 执行删除后为&#xff1a; DQL - 条…

打印工具HandyPrint Pro Mac中文版软件特点

HandyPrint Pro Mac是一款打印工具&#xff0c;它支持AIrPrint协议&#xff0c;可以让用户在iPhone、iPad、iPod等设备上进行打印操作&#xff0c;只需要将这些设备连接到Mac电脑的WiFi网络中即可实现打印功能。 ​ HandyPrint Pro Mac软件特点 简单易用&#xff1a;用户只需…

不标年份的葡萄酒质量好吗?

我们在葡萄酒标上经常看到生产年份&#xff0c;也就是指全部葡萄采摘的年份。旧世界葡萄酒产国认为葡萄酒年份对他们的影响较大&#xff0c;而新世界葡萄酒&#xff0c;年份的意义就稍微小些。甚至有一部分葡萄酒酒标上没有年份。在酒标上没有标注年份的葡萄酒&#xff0c;被称…

Java(三)(static,代码块,单例设计模式,继承)

目录 static 有无static修饰的成员变量 有无static修饰的成员方法 static的注意事项 代码块 静态代码块 实例代码块 单例设计模式 饿汉式单例写法 懒汉式单例写法 继承 基本概念 注意事项 权限修饰符 单继承 object 方法重写 子类方法中访问其他成员(成员变量…

Druid介绍

Druid介绍 Druid首先是一个数据库连接池&#xff0c;并且是目前最好的数据库连接池&#xff0c;在功能、性能、扩展性方面&#xff0c;都超过其他数据库连接池&#xff0c;包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。但它不仅仅是一个数据库连接池&#xff0c;它还包…

使用frp搭建内网穿透服务

使用frp搭建内网穿透服务 frp 是一个专注于内网穿透的高性能的反向代理应用&#xff0c;支持 TCP、UDP、HTTP、HTTPS 等多种协议&#xff0c;且支持 P2P 通信。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。 1.下载frp 下载地址 2.服务端安装 …

工作电压范围,转换速率高,相位补偿等特性的双运算放大器芯片D4510的描述

D4510是一块双运算放大器&#xff0c;具有较宽的工作电压范围&#xff0c;转换速率高&#xff0c;相位补偿等特性。电路能在低电源电压下:工作,电源电压范围:双电源为1V-3.5V和单电源电压为2V~7V。 主要特点&#xff1a; ● 低电压工作 ● 转换速率高 ● 动态输…