手写promise A+、catch、finally、all、allsettled、any、race
目录
手写promise
同步版
1.Promise的构造方法接收一个executor(),在new Promise()时就立刻执行executor回调
2.executor()内部的异步任务被放入宏/微任务队列,等待执行
3.状态与结果的管理
状态只能变更一次
4.then()调用成功/失败回调
catch是调用失败回调的简写
异步版
1.缓存成功与失败回调
2.then 增加 Pending处理
3.resolve 与 reject 中调用回调函数
多次调用同一个promise的then
1.缓存成功与失败回调 队列
2.pengding时,then()收集依赖,将成功/失败回调放入成功/失败队列
3.触发resolve/reject,从成功/失败队列中取出回调依次执行
then链式调用:返回一个 Promise 对象
then返回自己时,抛错循环调用
等返回的promise初始化好:queueMicrotask微任务
捕获错误
executor错误
then错误
then([onFulfilled, onRejected])参数可选
then 穿透:忽略非函数参数,非函数会同步执行
静态调用resolve、reject
完整版
Promise A+ 规范版的resolvePromise
catch
finally
并发请求
模板
all
allSettled
any
race
手写promise
同步版
1.将promise的resolve和reject函数传给实例用
constructor(executor){// executor 是一个执行器,进入会立即执行// 并传入resolve和reject方法executor(this.resolve, this.reject) }2.实例给resolve和reject函数传值
resolve('success') reject('err')
// 新建 test.js// 引入我们的 MyPromise.js
const MyPromise = require('./MyPromise')
const promise = new MyPromise((resolve, reject) => {resolve('success')reject('err')
})promise.then(value => {console.log('resolve', value)
}, reason => {console.log('reject', reason)
})// 执行结果:resolve success
1.Promise的构造方法接收一个executor(),在new Promise()时就立刻执行executor回调
class Promise{// 构造方法接收一个回调constructor(executor){executor();}
2.executor()内部的异步任务被放入宏/微任务队列,等待执行
// resolve和reject为什么要用箭头函数?
// 如果直接调用的话,普通函数this指向的是window或者undefined
// 用箭头函数就可以让this指向当前实例对象
class MyPromise {constructor(executor){// executor 是一个执行器,进入会立即执行// 并传入resolve和reject方法executor(this.resolve, this.reject) }// 更改成功后的状态resolve = () => {}// 更改失败后的状态reject = () => {}
}
3.状态与结果的管理
状态只能变更一次
// 先定义三个常量表示状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';// 新建 MyPromise 类
class MyPromise {constructor(executor){...}// 储存状态的变量,初始值是 pendingstatus = PENDING;// 成功之后的值value = null;// 失败之后的原因reason = null;// 更改成功后的状态resolve = (value) => {// 只有状态是等待,才执行状态修改if (this.status === PENDING) {// 状态修改为成功this.status = FULFILLED;// 保存成功之后的值this.value = value;}}// 更改失败后的状态reject = (reason) => {// 只有状态是等待,才执行状态修改if (this.status === PENDING) {// 状态成功为失败this.status = REJECTED;// 保存失败后的原因this.reason = reason;}}
}
4.then()调用成功/失败回调
catch是调用失败回调的简写
// MyPromise.jsthen(onFulfilled, onRejected) {// 判断状态if (this.status === FULFILLED) {// 调用成功回调,并且把值返回onFulfilled(this.value);} else if (this.status === REJECTED) {// 调用失败回调,并且把原因返回onRejected(this.reason);}
}
异步版
// test.jsconst MyPromise = require('./MyPromise')
const promise = new MyPromise((resolve, reject) => {setTimeout(() => {resolve('success')}, 2000);
})promise.then(value => {console.log('resolve', value)
}, reason => {console.log('reject', reason)
})// 同步版没有打印信息(执行到then时,状态还是pending)
// 异步版等待 2s 输出 resolve success
1.缓存成功与失败回调
// MyPromise 类中新增
// 存储成功回调函数
onFulfilledCallback = null;
// 存储失败回调函数
onRejectedCallback = null;
2.then 增加 Pending处理
// MyPromise.jsthen(onFulfilled, onRejected) {...if (this.status === PENDING) {// ==== 新增 ====// 因为不知道后面状态的变化情况,所以将成功回调和失败回调存储起来// 等到执行成功失败函数的时候再传递this.onFulfilledCallback = onFulfilled;this.onRejectedCallback = onRejected;}
}
3.resolve 与 reject 中调用回调函数
// MyPromise.js// 更改成功后的状态
resolve = (value) => {// 只有状态是等待,才执行状态修改if (this.status === PENDING) {// 状态修改为成功this.status = FULFILLED;// 保存成功之后的值this.value = value;// ==== 新增 ====// 判断成功回调是否存在,如果存在就调用this.onFulfilledCallback && this.onFulfilledCallback(value);}
}
多次调用同一个promise的then
// test.jsconst MyPromise = require('./MyPromise')
const promise = new MyPromise((resolve, reject) => {setTimeout(() => {resolve('success')}, 2000);
})promise.then(value => {console.log(1)console.log('resolve', value)
})promise.then(value => {console.log(2)console.log('resolve', value)
})promise.then(value => {console.log(3)console.log('resolve', value)
})
//单个回调:3
resolve success
//回调队列:
1
resolve success
2
resolve success
3
resolve success
1.缓存成功与失败回调 队列
// MyPromise.js// 存储成功回调函数
// onFulfilledCallback = null;
onFulfilledCallbacks = [];
// 存储失败回调函数
// onRejectedCallback = null;
onRejectedCallbacks = [];
2.pengding时,then()收集依赖,将成功/失败回调放入成功/失败队列
// MyPromise.jsthen(onFulfilled, onRejected) {// 判断状态if (this.status === FULFILLED) {// 调用成功回调,并且把值返回onFulfilled(this.value);} else if (this.status === REJECTED) {// 调用失败回调,并且把原因返回onRejected(this.reason);} else if (this.status === PENDING) {// ==== 新增 ====// 因为不知道后面状态的变化,这里先将成功回调和失败回调存储起来// 等待后续调用this.onFulfilledCallbacks.push(onFulfilled);this.onRejectedCallbacks.push(onRejected);}
}
3.触发resolve/reject,从成功/失败队列中取出回调依次执行
// MyPromise.js// 更改成功后的状态
resolve = (value) => {// 只有状态是等待,才执行状态修改if (this.status === PENDING) {// 状态修改为成功this.status = FULFILLED;// 保存成功之后的值this.value = value;// ==== 新增 ====// resolve里面将所有成功的回调拿出来执行while (this.onFulfilledCallbacks.length) {// Array.shift() 取出数组第一个元素,然后()调用,shift不是纯函数,取出后,数组将失去该元素,直到数组为空this.onFulfilledCallbacks.shift()(value)}}
}
then链式调用:返回一个 Promise 对象
以fulfilled为例,其他同理
// MyPromise.jsclass MyPromise {...then(onFulfilled, onRejected) {// 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去const promise2 = new MyPromise((resolve, reject) => {// 这里的内容在执行器中,会立即执行if (this.status === FULFILLED) {// 获取成功回调函数的执行结果const x = onFulfilled(this.value);// 传入 resolvePromise 集中处理resolvePromise(x, resolve, reject);} ...}) return promise2;}
}function resolvePromise(x, resolve, reject) {// 判断x是不是 MyPromise 实例对象if(x instanceof MyPromise) {// 执行 x,调用 then 方法,目的是将其状态变为 fulfilled 或者 rejected// x.then(value => resolve(value), reason => reject(reason))// 简化之后x.then(resolve, reject)} else{// 普通值resolve(x)}
}
then返回自己时,抛错循环调用
// test.jsconst promise = new Promise((resolve, reject) => {resolve(100)
})
const p1 = promise.then(value => {console.log(value)return p1
})
function resolvePromise(promise2, x, resolve, reject) {// 如果相等了,说明return的是自己,抛出类型错误并返回if (promise2 === x) {return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}...
}
等返回的promise初始化好:queueMicrotask微任务

// MyPromise.jsclass MyPromise {......then(onFulfilled, onRejected) {const promise2 = new MyPromise((resolve, reject) => {if (this.status === FULFILLED) {// 创建一个微任务等待 promise2 完成初始化queueMicrotask(() => {// 获取成功回调函数的执行结果const x = onFulfilled(this.value);// 传入 resolvePromise 集中处理resolvePromise(promise2, x, resolve, reject);}) } ...}) return promise2;}
}
捕获错误
try {异步操作
} catch (error) {reject(error)
}
executor错误
// MyPromise.jsconstructor(executor){// ==== 新增 ====// executor 是一个执行器,进入会立即执行// 并传入resolve和reject方法try {executor(this.resolve, this.reject)} catch (error) {// 如果有错误,就直接执行 rejectthis.reject(error)}
}
then错误
// MyPromise.jsthen(onFulfilled, onRejected) {// 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去const promise2 = new MyPromise((resolve, reject) => {// 判断状态if (this.status === FULFILLED) {// 创建一个微任务等待 promise2 完成初始化queueMicrotask(() => {try {// 获取成功回调函数的执行结果const x = onFulfilled(this.value);// 传入 resolvePromise 集中处理resolvePromise(promise2, x, resolve, reject);} catch (error) {reject(error)} }) } ...}) return promise2;
}
then([onFulfilled, onRejected])参数可选
then 穿透:忽略非函数参数,非函数会同步执行
Promise.resolve(1).then(2)//传入值.then(Promise.resolve(3))//传入promise对象.then(console.log)//传入函数
1
Promise.resolve().then(new Promise(r => {setTimeout(() => {r(console.log(1))}, 1000)})).then(new Promise(r => {setTimeout(() => {r(console.log(2))}, 1000)})).then(new Promise(r => {setTimeout(() => {r(console.log(3))}, 1000)}))
延迟1秒后,打印123
不同于下面
// MyPromise.jsthen(onFulfilled, onRejected) {// 如果不传,就使用默认函数onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason};// 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去const promise2 = new MyPromise((resolve, reject) => {......
}
静态调用resolve、reject
// MyPromise.jsMyPromise {......// resolve 静态方法static resolve (parameter) {// 如果传入 MyPromise 就直接返回if (parameter instanceof MyPromise) {return parameter;}// 转成常规方式return new MyPromise(resolve => {resolve(parameter);});}// reject 静态方法static reject (reason) {return new MyPromise((resolve, reject) => {reject(reason);});}
}
完整版
// MyPromise.js// 先定义三个常量表示状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';// 新建 MyPromise 类
class MyPromise {constructor(executor){// executor 是一个执行器,进入会立即执行// 并传入resolve和reject方法try {executor(this.resolve, this.reject)} catch (error) {this.reject(error)}}// 储存状态的变量,初始值是 pendingstatus = PENDING;// 成功之后的值value = null;// 失败之后的原因reason = null;// 存储成功回调函数onFulfilledCallbacks = [];// 存储失败回调函数onRejectedCallbacks = [];// 更改成功后的状态resolve = (value) => {// 只有状态是等待,才执行状态修改if (this.status === PENDING) {// 状态修改为成功this.status = FULFILLED;// 保存成功之后的值this.value = value;// resolve里面将所有成功的回调拿出来执行while (this.onFulfilledCallbacks.length) {// Array.shift() 取出数组第一个元素,然后()调用,shift不是纯函数,取出后,数组将失去该元素,直到数组为空this.onFulfilledCallbacks.shift()(value)}}}// 更改失败后的状态reject = (reason) => {// 只有状态是等待,才执行状态修改if (this.status === PENDING) {// 状态成功为失败this.status = REJECTED;// 保存失败后的原因this.reason = reason;// resolve里面将所有失败的回调拿出来执行while (this.onRejectedCallbacks.length) {this.onRejectedCallbacks.shift()(reason)}}}then(onFulfilled, onRejected) {const realOnFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;const realOnRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason};// 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去const promise2 = new MyPromise((resolve, reject) => {const fulfilledMicrotask = () => {// 创建一个微任务等待 promise2 完成初始化queueMicrotask(() => {try {// 获取成功回调函数的执行结果const x = realOnFulfilled(this.value);// 传入 resolvePromise 集中处理resolvePromise(promise2, x, resolve, reject);} catch (error) {reject(error)} }) }const rejectedMicrotask = () => { // 创建一个微任务等待 promise2 完成初始化queueMicrotask(() => {try {// 调用失败回调,并且把原因返回const x = realOnRejected(this.reason);// 传入 resolvePromise 集中处理resolvePromise(promise2, x, resolve, reject);} catch (error) {reject(error)} }) }// 判断状态if (this.status === FULFILLED) {fulfilledMicrotask() } else if (this.status === REJECTED) { rejectedMicrotask()} else if (this.status === PENDING) {// 等待// 因为不知道后面状态的变化情况,所以将成功回调和失败回调存储起来// 等到执行成功失败函数的时候再传递this.onFulfilledCallbacks.push(fulfilledMicrotask);this.onRejectedCallbacks.push(rejectedMicrotask);}}) return promise2;}// resolve 静态方法static resolve (parameter) {// 如果传入 MyPromise 就直接返回if (parameter instanceof MyPromise) {return parameter;}// 转成常规方式return new MyPromise(resolve => {resolve(parameter);});}// reject 静态方法static reject (reason) {return new MyPromise((resolve, reject) => {reject(reason);});}
}function resolvePromise(promise2, x, resolve, reject) {// 如果相等了,说明return的是自己,抛出类型错误并返回if (promise2 === x) {return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}// 判断x是不是 MyPromise 实例对象if(x instanceof MyPromise) {// 执行 x,调用 then 方法,目的是将其状态变为 fulfilled 或者 rejected// x.then(value => resolve(value), reason => reject(reason))// 简化之后x.then(resolve, reject)} else{// 普通值resolve(x)}
}module.exports = MyPromise;
Promise A+ 规范版的resolvePromise
要求判断 x 是否为 object 或者 function,满足则接着判断 x.then 是否存在,这里可以理解为判断 x 是否为 promise,这里都功能实际与我们手写版本中 x instanceof MyPromise 功能相似
// MyPromise.jsfunction resolvePromise(promise, x, resolve, reject) {// 如果相等了,说明return的是自己,抛出类型错误并返回if (promise === x) {return reject(new TypeError('The promise and the return value are the same'));}if (typeof x === 'object' || typeof x === 'function') {// x 为 null 直接返回,走后面的逻辑会报错if (x === null) {return resolve(x);}let then;try {// 把 x.then 赋值给 then then = x.then;} catch (error) {// 如果取 x.then 的值时抛出错误 error ,则以 error 为据因拒绝 promisereturn reject(error);}// 如果 then 是函数if (typeof then === 'function') {let called = false;try {then.call(x, // this 指向 x// 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)y => {// 如果 resolvePromise 和 rejectPromise 均被调用,// 或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用// 实现这条需要前面加一个变量 calledif (called) return;called = true;resolvePromise(promise, y, resolve, reject);},// 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promiser => {if (called) return;called = true;reject(r);});} catch (error) {// 如果调用 then 方法抛出了异常 error:// 如果 resolvePromise 或 rejectPromise 已经被调用,直接返回if (called) return;// 否则以 error 为据因拒绝 promisereject(error);}} else {// 如果 then 不是函数,以 x 为参数执行 promiseresolve(x);}} else {// 如果 x 不为对象或者函数,以 x 为参数执行 promiseresolve(x);}
}
catch
//catch方法其实就是执行一下then的第二个回调
catch(rejectFn) {return this.then(undefined, rejectFn)
}
finally
由于无法知道promise的最终状态,所以finally的回调函数中不接收任何参数,它仅用于无论最终结果如何都要执行的情况
finally(callBack) {return this.then(callBack, callBack)}
并发请求
模板
/*** @param {iterable} promises 一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入* @returns */
static 并发(promises) {
// 参数校验
if (Array.isArray(promises)) {let result = []; // 存储结果let count = 0; // 计数器if (promises.length === 0) {
// 如果传入的参数是一个空的可迭代对象,则返回一个已完成(already resolved)状态的 Promisereturn resolve(promises);//C. 返回一个 已失败(already rejected) 状态的 Promise。return reject(new AggregateError('All promises were rejected'));}return new myPromise((resolve, reject) => {promises.forEach((item, index) => {myPromise.resolve(item).then(value => {count++;// 每个promise执行的结果存储在result中//A.记录所有reject/fulfilled,需要区分状态result[index] = {status: 'fulfilled',value}//B.只记录fulfilledresult[index] = value// 如果所有的 Promise 都已经处理完毕,就调用 resolve(result)count === promises.length && resolve(result);//C.只要一个成功resolve(value);},reason => {//A.记录所有rejectcount++;result[index] = {status: 'rejected',reason}count === promises.length && resolve(result);//B.一旦rejectreject(reason); //C.全rejectcount++;errors.push(reason);//AggregateError是 Error 的一个子类,用于把单一的错误集合在一起。count === promises.length && reject(new AggregateError(errors));})})} else {return reject(new TypeError('Argument is not iterable'))
}}
all
/**
* 如果传入的 promise 中有一个失败(rejected),
* Promise.all 异步地将失败的那个结果给失败状态的回调函数,而不管其它 promise 是否完成
*/
static all(promises) {
return new myPromise((resolve, reject) => {promises.forEach((item, index) => {myPromise.resolve(item).then(value => {count++;// 每个promise执行的结果存储在result中result[index] = value;// 如果所有的 Promise 都已经处理完毕,就调用 resolve(result)count === promises.length && resolve(result);},reason => {reject(reason); })})
}
allSettled
static allSettled(promises) {
return new myPromise((resolve, reject) => {promises.forEach((item, index) => {myPromise.resolve(item).then(value => {count++;// 每个promise执行的结果存储在result中//A.记录所有reject/fulfilled,需要区分状态result[index] = {status: 'fulfilled',value}// 如果所有的 Promise 都已经处理完毕,就调用 resolve(result)count === promises.length && resolve(result);},reason => {//A.记录所有rejectcount++;result[index] = {status: 'rejected',reason}count === promises.length && resolve(result); })})
}
any
static any(promises){return new myPromise((resolve, reject) => {promises.forEach((item, index) => {myPromise.resolve(item).then(value => {//C.只要一个成功resolve(value);},reason => {//C.全rejectcount++;errors.push(reason);//AggregateError是 Error 的一个子类,用于把单一的错误集合在一起。count === promises.length && reject(new AggregateError(errors));})})
}
race
//race方法(返回最早执行完的promise结果,无论成功与否)
Promise.race = function(promises){return new myPromise((resolve, reject) => {// 如果传入的迭代promises是空的,则返回的 promise 将永远等待。if (promises.length > 0) {promises.forEach(item => {myPromise.resolve(item).then(resolve, reject);})}}})
手写实现 Promise 全部实例方法和静态方法,来看看 Promise.all、Promise.race 和 Promise.any 都是怎么实现的 - 掘金
从一道让我失眠的 Promise 面试题开始,深入分析 Promise 实现细节 - 掘金
相关文章:
手写promise A+、catch、finally、all、allsettled、any、race
目录 手写promise 同步版 1.Promise的构造方法接收一个executor(),在new Promise()时就立刻执行executor回调 2.executor()内部的异步任务被放入宏/微任务队列,等待执行 3.状态与结果的管理 状态只能变更一次 4.then()调用成功/失败回调 catch是…...
【原神游戏开发日志1】缘起
【原神游戏开发日志1】缘起 版权声明 本文为“优梦创客”原创文章,您可以自由转载,但必须加入完整的版权声明 文章内容不得删减、修改、演绎 相关学习资源见文末 大家好,最近看到原神在TGA上频频获奖,作为一个14年经验的游戏开…...
leetcode5 最长公共前缀三种python解法
14. 最长公共前缀 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀,返回空字符串 ""。 示例 1: 输入:strs ["flower","flow","flight"] 输出:"fl"示…...
对小程序的初了解
WXML和HTML的区别 标签名称不同 HTML:div、a、span、img WXML:view、text、image、navigator 属性节点不同 <a href"#">超链接</a> <navigator url"/pages/home/home"></navigator> 提供了类似vue的…...
QLineEdit 的 InputMask掩码
QLineEdit 的 InputMask掩码 A:只能输入字母,且不可省略 a:只能输入字母,可以省略 N:只能输入 字母和数字,且不可省略 n:只能输入 字母和数字,可以省略 X:可以输入任意字…...
关于队列的简单理解
1.队列(Queue) 1.1 关于队列 队列 :只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表, 队列具有先进先出 FIFO(First In First Out)的操作特性(队列是个接口); 入队列&#x…...
加密市场进入牛初阶段?一场新的造富效应即将拉开帷幕!
周一(12月4日),比特币一度上涨至42000美元,创下自2022年4月以来的最高水平。从目前比特币的走势来看,加密市场无疑已然进入到牛初阶段。 在牛市初期,确实存在人们不相信牛市到来的情况。由于在熊市中亏损的心理阻碍和对市场进一步…...
Superset基础入门
1 Superset概述 Apache Superset 是一个现代的数据探索和可视化平台。它功能强大且十分易用,可对接 各种数据源,包括很多现代的大数据分析引擎,拥有丰富的图表展示形式,并且支持自定义 仪表盘。 2 Superset安装 Superset 是由 P…...
【泛微ecology】将多个字段的数据合并到一个字段
doFieldSQL("select concat(concat(sqr,,),sy) as c from formtable_main_2 where requestid $requestid$ ")...
WebSocket入门介绍及编程实战
HTTP的限制 全双工和半双工: 全双工:全双工(Full Duplex)是允许数据在两个方向上同时传输。 半双工:半双工(Half Duplex)是允许数据在两个方向上传输,但是同一个时间段内只允许一个…...
vue3里面生命周期的使用
前言: vue2里面的生命周期和vue3生命周期是非常的相似的,我们通过访问生命周期钩子来处理不同场景之间的应用。 生命周期钩子的函数定义:每一个Vue组件实例在创建时都需要经历一系列的初始化步骤,比如数据侦听,编译模…...
在python的Scikit-learn库中,可以使用train_test_split函数来划分训练集和测试集。
文章目录 一、在Scikit-learn库中,可以使用train_test_split函数来划分训练集和测试集总结 一、在Scikit-learn库中,可以使用train_test_split函数来划分训练集和测试集 在Scikit-learn库中,可以使用train_test_split函数来划分训练集和测试…...
外包干了2个月,技术明显退步了...
先说一下自己的情况,大专生,19年通过校招进入广州某软件公司,干了接近5年的功能测试,今年11月份,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测…...
数据结构:链表应用:第9关:删除链表中满足区间值的结点
任务描述编程要求 输入输出测试说明来源 任务描述 本关任务:利用单链表表示一个递增的整数序列,删除链表中值大于等于mink且小于等于maxk的所有元素(mink和maxk是给定的两个参数,其值可以和表中的元素相同,也可以不同…...
了解 ignore_above 参数对 Elasticsearch 中磁盘使用的影响
在 Elasticsearch 中,ignore_above 参数允许你忽略(而不是索引)长于指定长度的字符串。 这对于限制字段的大小以避免性能问题很有用。 在本文中,我们将探讨 “ignore_above” 参数如何影响 Elasticsearch 中字段的大小,…...
C#中的async/await异步编程模型
前言 当谈到异步编程时,C#中的async/await是一个强大且方便的工具。它使得编写并发和异步操作变得更加简单和可读,同时提供良好的可维护性。本文将详细解释async/await的使用,以及如何在C#中有效地利用它来实现异步操作。 目录 前言1. async…...
【原创】提升MybatisPlus分页便捷性,制作一个属于自己的分页插件,让代码更加优雅
前言 MybatisPlus的分页插件有一点非常不好,就是要传入一个IPage,别看这个IPage没什么大不了的,最多多写一两行代码,可这带来一个问题,即使用xml的查询没法直接取对象里面变量的值了,得Param指定xml中的变…...
pythonselenium自动化测试实战项目
说明:本项目采用流程控制思想,未引用unittest&pytest等单元测试框架 一.项目介绍 目的 测试某官方网站登录功能模块可以正常使用 用例 1.输入格式正确的用户名和正确的密码,验证是否登录成功; 2.输入格式正确的用户名和不…...
智能优化算法应用:基于瞬态优化算法无线传感器网络(WSN)覆盖优化 - 附代码
智能优化算法应用:基于瞬态优化算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于瞬态优化算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.瞬态优化算法4.实验参数设定5.算法结果6.参考…...
springMVC 三大组件解析
springMVC组件概述 DispatcherServlet(调度器Servlet): DispatcherServlet 是 Spring MVC 的前端控制器(Front Controller)。它负责接收来自客户端的请求,然后将请求分发给相应的处理器(Control…...
使用Yolo 11进行定制化图像识别全流程
全流程预览 Label Studio标注 → 导出YOLO格式 → 编写data.yaml → 拆分数据集 → 模型训练 → 预测部署步骤工具/技术产出物数据标注Label Studio标注好的图片数据导出YOLO with imagesimages/ labels/配置文件data.yaml数据集配置数据拆分Python脚本train/val/test模型训练…...
OpenClaw技能扩展实战:用百川2-13B-4bits量化模型开发自定义自动化模块
OpenClaw技能扩展实战:用百川2-13B-4bits量化模型开发自定义自动化模块 1. 为什么选择百川2-13B-4bits量化模型 去年冬天,当我第一次尝试用本地部署的大模型开发OpenClaw技能时,显存不足的报错成了家常便饭。直到发现百川2-13B的4bits量化版…...
SAR ADC与Sigma Delta ADC:速度与精度的技术博弈
1. ADC基础:模拟世界与数字世界的桥梁 当你用手机录音时,麦克风捕捉到的声波是连续变化的模拟信号,但手机存储的却是0101的数字文件。这个神奇转换的背后功臣就是模数转换器(ADC)。作为连接物理世界与数字系统的关键部…...
规则直观落地操作指南(零理解成本・照做就生效・效果肉眼可见)
规则直观落地操作指南(零理解成本・照做就生效・效果肉眼可见) 核心原则:所有内容全是「动作指令」,无概念、无术语、无废话;每一步操作都有「即时可验证的落地效果」,不用等项目结束,做完立刻知道有没有用。 一、先锁死 3 条零理解成本操作铁律(必须先遵守,否则所有…...
OpenClaw 的模型服务是否支持限流和熔断?策略如何配置?
在讨论OpenClaw模型服务的限流与熔断机制之前,不妨先回想一下城市交通系统。早晚高峰时,交警会在关键路口设置信号灯或临时管制,防止车辆过度涌入导致整个区域瘫痪。模型服务面临的场景其实非常相似——外部请求就像不断驶入的车辆࿰…...
告别回调地狱:用Qt信号与槽重构你的第一个GUI应用(Qt6/C++实战)
重构GUI应用:Qt信号与槽的工程化实践 在传统C GUI开发中,我们常常陷入回调函数嵌套的泥潭——按钮点击触发事件处理函数,函数内部又调用其他模块,最终形成难以维护的"面条式代码"。Qt的信号与槽机制为这一困境提供了优雅…...
别再傻傻下载Gurobi软件了!Anaconda虚拟环境里一条conda命令搞定学术版安装(Win11实测)
颠覆认知的Gurobi安装指南:一条conda命令解锁学术版完整功能 每次看到同行们花半小时下载几个GB的Gurobi安装包,我就忍不住想分享这个被多数人忽略的高效方案。作为在运筹优化领域深耕多年的研究者,我发现90%的学术用户根本不需要走传统安装…...
保姆级教程:用C++刷穿GPLT天梯赛L1基础题(附避坑指南)
从零开始征服GPLT天梯赛:C选手的L1解题全攻略 第一次接触GPLT天梯赛的L1级别题目时,我盯着屏幕上那道关于"零头就抹了吧"的数学题发呆了整整十分钟。作为过来人,我完全理解新手面对算法竞赛时那种既兴奋又忐忑的心情。本文将用最接…...
ASan实战:5种常见内存错误诊断与修复指南(附GCC/Clang编译命令)
ASan实战:5种常见内存错误诊断与修复指南(附GCC/Clang编译命令) 在C/C开发中,内存错误如同潜伏的暗礁,随时可能让程序沉没。AddressSanitizer(ASan)作为Google推出的内存错误检测工具ÿ…...
终极指南:如何用F3工具快速检测U盘和SD卡真实容量
终极指南:如何用F3工具快速检测U盘和SD卡真实容量 【免费下载链接】f3 F3 - Fight Flash Fraud 项目地址: https://gitcode.com/gh_mirrors/f3/f3 在数字时代,存储设备容量造假已成为普遍问题,许多U盘、SD卡通过软件修改显示虚假容量&…...
