本文用到的技术点包含Promise、AbortController
整篇从易到难逐步增加功能,对技术一般的同学十分友好。
收获:
- 提前执行、取消执行的思路。
- 方法的提炼。
延迟输出
// 延迟输出
const delay = (ms)=>{
return new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve()
},ms)
})
}
// 执行功能
(async function demo(){
await delay(1000);
console.log('延迟输出');
})()
增加value参数做结果
// 延迟输出
// 加value参数做结果
const delay = (ms,value)=>{
return new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve(value)
},ms)
})
}
(async function demo(){
let res = await delay(1000,{value:'梦想总是有的'});
console.log('延迟输出',res);
})()
失败状态、增加随机时间功能、成功装状态、失败状态封装成一个方法
// --- 包含功能
// 延迟输出
// 加value参数做结果
// 加失败 willResolve
// 成功、失败封装成一个函数
// 随机数封装一个函数
//---
// 随机数
ramdomMs = (minNum, maxNum) => {
return Math.floor(
(maxNum - minNum) * Math.random() + 1 + minNum
)
}
// 基本方法(成功,失败)
const createDelay = ({willResolve}) =>(ms,{value}={})=>{
return new Promise((resolve, reject)=>{
setTimeout(()=>{
if(willResolve){
resolve(`${value}:${ms}`)
}else{
reject(`${value}:${ms}`)
}
},ms)
})
}
// 相关功能
const createWithTimers = ()=>{
// 成功
const delay = createDelay({willResolve:true})
// 失败
delay.reject = createDelay({willResolve:false})
// 随机时间-成功的基础上增加
delay.range = (minNum,maxNum,option)=>delay(ramdomMs(minNum,maxNum),option)
return delay
}
const delay = createWithTimers()
async function demo(){
let res = await delay(1000,{value:'梦想总是有的'});
console.log('延迟输出:',res);
try{
await delay.reject(1000,{value:'失败是正常的'});
}catch(err){
console.log('err:',err)
}
let res2 =await delay.range(30,3000,{value:'你只管努力,其他的交给时间'})
console.log('随机时间:',res2)
}
demo()
提前返回结果
// --- 包含功能
// 延迟输出
// 加value参数做结果
// 加失败 willResolve
// 成功、失败封装成一个函数
// 随机数封装一个函数
// 提前清除(提前返回结果)
//---
// 随机数
ramdomMs = (minNum, maxNum) => {
return Math.floor(
(maxNum - minNum) * Math.random() + 1 + minNum
)
}
// 基本方法(成功,失败)
const createDelay = ({willResolve}) =>(ms,{value}={})=>{
let timeoutId = null;
let settle = null
const delayPromise = new Promise((resolve, reject)=>{
settle = ()=>{
if(willResolve){
resolve(`${value}:${ms}`)
}else{
reject(`${value}:${ms}`)
}
}
timeoutId = setTimeout( settle ,ms)
})
// 取消继续执行
delayPromise.clear = ()=>{
// 清除倒计时后就不会执行了
clearTimeout(timeoutId)
timeoutId = null
// 清除后执行
settle()
}
return delayPromise
}
// 相关功能
const createWithTimers = ()=>{
// 成功
const delay = createDelay({willResolve:true})
// 失败
delay.reject = createDelay({willResolve:false})
// 随机时间-成功的基础上增加
delay.range = (minNum,maxNum,option)=>delay(ramdomMs(minNum,maxNum),option)
return delay
}
const delay = createWithTimers()
async function demo(){
let res3Promise = delay(3000,{value:'任何挫折都是纸老虎'})
setTimeout(()=>{
res3Promise.clear()
},300)
console.log(await res3Promise)
}
demo()
增加取消功能
// --- 包含功能
// 延迟输出
// 加value参数做结果
// 加失败 willResolve
// 成功、失败封装成一个函数
// 随机数封装一个函数
// 提前清除
// 取消功能
// 1. 添加监听事件 signal.addEventListener('abort', signalListener, {once: true})
// 2. signalListener这个方法需要包含清除请求(清除倒计时),reject抛错
// 3. settle执行,清除监听事件signal.removeEventListener('abort', signalListener)
// 4. 完善流程,初始化值的判段{aborted: false},建立报错信息
//---
// 建立报错信息
const createAbortError = () => {
const error = new Error('Delay aborted');
error.name = 'AbortError';
return error;
};
// 随机数
ramdomMs = (minNum, maxNum) => {
return Math.floor(
(maxNum - minNum) * Math.random() + 1 + minNum
)
}
// 基本方法(成功,失败)
const createDelay = ({willResolve}) =>(ms,{value, signal}={})=>{
if (signal && signal.aborted) {
return Promise.reject(createAbortError());
}
let timeoutId = null;
let settle = null
let rejectFn;
const signalListener = () => {
clearTimeout(timeoutId);
rejectFn(createAbortError());
}
const cleanup = () => {
if (signal) {
signal.removeEventListener('abort', signalListener);
}
};
const delayPromise = new Promise((resolve, reject)=>{
//
settle = ()=>{
cleanup();
if(willResolve){
resolve(`${value}:${ms}`)
}else{
reject(`${value}:${ms}`)
}
}
// 拿到reject的功能
rejectFn = reject;
timeoutId = setTimeout( settle ,ms)
})
if (signal) {
signal.addEventListener('abort', signalListener, {once: true});
}
// 取消继续执行
delayPromise.clear = ()=>{
// 清除倒计时后就不会执行了
clearTimeout(timeoutId)
timeoutId = null
settle()
}
return delayPromise
}
// 相关功能
const createWithTimers = ()=>{
// 成功
const delay = createDelay({willResolve:true})
// 失败
delay.reject = createDelay({willResolve:false})
// 随机时间-成功的基础上增加
delay.range = (minNum,maxNum,option)=>delay(ramdomMs(minNum,maxNum),option)
return delay
}
const delay = createWithTimers()
async function demo(){
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, 5000);
try{
let res = await delay(10000,{value:'返回结果是我',signal: abortController.signal});
console.log(res)
}catch(err){
console.log('err:',err)
}
}
demo()
总结
AbortController
//AbortController 接口表示一个控制器对象,允许你根据需要终止 Web 请求。
// 属性
// - signal:{ 对事件进行标记
// aborted:boolean // 可用于检测当前标记状态
// }
// 方法
// - abort 终止事件执行
例: 终止fetch请求
fetchButton.onclick = async () => {
const controller = new AbortController();
// wire up abort button
abortButton.onclick = () => controller.abort();
try {
const r = await fetch('/json', { signal: controller.signal });
const json = await r.json();
// TODO: do something 🤷
} catch (e) {
const isUserAbort = (e.name === 'AbortError');
// TODO: show err 🧨
// this will be a DOMException named AbortError if aborted 🎉
}
};