简介: JavaScript是一门灵活而强大的编程语言,它允许开发人员使用各种技巧来创建功能强大且有趣的代码。本文将深入探讨与梳理createPromise/createRetryPromise 的工具函数实现思路。
1. 理解createPromise函数
createPromise函数是一个JavaScript函数,它接受一个包含多个参数的对象作为输入,并返回一个具有cancel和getResult方法的对象。该函数的主要功能是创建一个可重试的Promise。
2. 实现一个
2.1 简单易用版
typescript
export function createPromise<T = void>(): [Promise<T>, (value: T) => void, (reason?: unknown) => void] {
let resolve: (value: T) => void = () => {
// init resolve
};
let reject: (reason?: unknown) => void = () => {
// init reject
};
const promise = new Promise<T>((res, rej) => {
resolve = res;
reject = rej;
});
return [promise, resolve, reject];
}
下面是分步的解析
- 首先,这段代码是一个用于创建 Promise 的函数。它返回一个包含 Promise 及其 resolve 和 reject 函数的数组。让我们一步步来理解它。
typescript
export function createPromise<T = void>(): [Promise<T>, (value: T) => void, (reason?: unknown) => void] {
这是一个导出的函数,可以通过 createPromise()
调用。它使用了泛型 <T>
,其中 T
是 Promise 的值的类型,默认为 void
,也就是没有返回值。
- 接下来,我们定义了两个变量
resolve
和reject
,它们是函数类型并具有相应的参数和返回值类型。这些函数将用于解决(resolve)或拒绝(reject)Promise。
typescript
let resolve: (value: T) => void = () => {
// init resolve
};
let reject: (reason?: unknown) => void = () => {
// init reject
};
在这里,我们只是为这些函数提供了空的初始实现。我们稍后将在 Promise 构造函数中重新赋值这些函数,以便在需要时调用它们。
- 接下来,我们创建了一个新的 Promise,并将其赋值给变量
promise
。
typescript
const promise = new Promise<T>((res, rej) => {
resolve = res;
reject = rej;
});
在 Promise 构造函数中,我们接收两个参数 res
和 rej
,它们分别是用于解决和拒绝 Promise 的函数。
在这里,我们将外部的 resolve
函数赋值为 res
,将外部的 reject
函数赋值为 rej
。这样做是为了将这些函数与新创建的 Promise 关联起来,以便在需要时调用它们。
- 最后,我们返回一个包含 Promise 及其相应的
resolve
和reject
函数的数组。
typescript
return [promise, resolve, reject];
}
现在,您可以使用这个函数来创建一个 Promise,并使用返回的数组中的函数来解决或拒绝该 Promise。
- 以下是一个示例用法:
typescript
const [myPromise, myResolve, myReject] = createPromise<number>();
myPromise.then((value) => {
console.log('Promise resolved with value:', value);
}).catch((reason) => {
console.log('Promise rejected with reason:', reason);
});
// 解决 Promise
myResolve(42);
// 拒绝 Promise
myReject('Something went wrong.');
2.2 chromium 源码扩展版
实现一个自己的util : createPromise.ts
typescript
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview PromiseResolver is a helper class that allows creating a
* Promise that will be fulfilled (resolved or rejected) some time later.
*
* Example:
* const resolver = new PromiseResolver();
* resolver.promise.then(function(result) {
* console.log('resolved with', result);
* });
* ...
* ...
* resolver.resolve({hello: 'world'});
*/
export class PromiseResolver<T> {
private resolve_: (arg: T) => void = () => {};
private reject_: (arg: any) => void = () => {};
private isFulfilled_: boolean = false;
private promise_: Promise<T>;
constructor() {
this.promise_ = new Promise((resolve, reject) => {
this.resolve_ = (resolution: T) => {
resolve(resolution);
this.isFulfilled_ = true;
};
this.reject_ = (reason: any) => {
reject(reason);
this.isFulfilled_ = true;
};
});
}
/** Whether this resolver has been resolved or rejected. */
get isFulfilled(): boolean {
return this.isFulfilled_;
}
get promise(): Promise<T> {
return this.promise_;
}
get resolve(): ((arg: T) => void) {
return this.resolve_;
}
get reject(): ((arg?: any) => void) {
return this.reject_;
}
}
export function createPromise<T>(){
return new PromiseResolver<T>();
}
2.3 createRetryPromise 增加任务状态标识与重试机制
2.3.1 先给出完整的实现
typescript
export const createRetryPromise = <T = any>(opt: {
runTask: () => Promise<T>;
checkSuccess: (info: T, time: number) => boolean;
time: number;
delayTime?: number;
onTry?: (time: number) => void;
}) => {
const maxTime = Math.max(1, opt.time);
const delayTime = Math.max(0, opt.delayTime || 0);
let time = 0;
let isCancel = false;
let reject: (reason?: any) => void = () => {};
let resolve: (value?: T) => void = () => {};
let isFinish = false;
const isNeedRetry = () => time < maxTime && !isCancel && !isFinish;
const run = () => {
if (isCancel) return;
opt.onTry?.(time);
opt.runTask()
.then(message => {
if (isCancel) return;
if (opt.checkSuccess(message, time)) {
time = maxTime;
resolve(message);
} else {
time++;
}
})
.catch(() => {
time++;
})
.finally(() => {
if (isNeedRetry()) {
setTimeout(run, delayTime);
} else {
reject('timeout');
}
});
};
const cancel = () => {
isCancel = true;
reject('cancel');
};
return {
cancel,
getResult: () => new Promise<T>((res, rej) => {
reject = rej;
resolve = res;
run();
}).finally(() => {
isFinish = true;
}),
};
};
2.3.2 逐步解析
- 定义函数的签名和参数:
typescript
export const createRetryPromise = <T = any>(opt: {
runTask: () => Promise<T>;
checkSuccess: (info: T, time: number) => boolean;
time: number;
delayTime?: number;
onTry?: (time: number) => void;
}) => {
这个函数名为 createRetryPromise
,它接收一个 opt
参数,该参数是一个对象,包含以下属性:
runTask
:一个返回 Promise 的函数,表示要执行的任务。checkSuccess
:一个函数,用于判断任务返回值是否需要继续执行。它接收两个参数,info
表示任务返回的信息,time
表示当前重试的次数。time
:重试的次数。delayTime
(可选):延迟时间。onTry
(可选):一个函数,表示在每次重试时要执行的操作。它接收一个参数time
,表示当前重试的次数。
- 我们定义一些变量和函数:
typescript
const maxTime = Math.max(1, opt.time);
const delayTime = Math.max(0, opt.delayTime || 0);
let time = 0;
let isCancel = false;
let reject: (reason?: any) => void = () => {};
let resolve: (value?: T) => void = () => {};
let isFinish = false;
const isNeedRetry = () => time < maxTime && !isCancel && !isFinish;
在这里,我们使用 Math.max
函数来确保 maxTime
和 delayTime
的值不小于 0 或 1。我们还声明了一些变量,包括 time
(当前重试的次数),isCancel
(是否取消重试),reject
(用于拒绝 Promise 的函数),resolve
(用于解决 Promise 的函数),isFinish
(是否已完成重试)。
我们还定义了一个名为 isNeedRetry
的函数,用于判断是否需要继续重试。它检查 time
是否小于 maxTime
,isCancel
是否为 false,以及 isFinish
是否为 false。
- 我们定义了
run
函数:
typescript
const run = () => {
if (isCancel) {
return;
}
opt.onTry?.(time);
opt.runTask()
.then(message => {
if (isCancel) {
return;
}
if (opt.checkSuccess(message, time)) {
time = maxTime;
resolve(message);
} else {
time++;
}
})
.catch(() => {
time++;
})
.finally(() => {
if (isNeedRetry()) {
setTimeout(run, delayTime);
} else {
reject('timeout');
}
});
};
在 run
函数中,我们首先检查是否已取消重试,如果是,则直接返回。然后,如果定义了 onTry
函数,则调用它并传递当前的重试次数 time
。
接下来,我们调用 opt.runTask()
执行任务,并处理返回的 Promise。在 then
方法中,我们检查是否已取消重试,如果是,则直接返回。然后,我们使用 opt.checkSuccess
函数判断任务返回值是否满足成功的条件。如果满足条件,我们将 time
设置为 maxTime
,并使用 resolve
函数解决 Promise,传递任务的返回值 message
。否则,我们增加 time
的值。
在 catch
方法中,我们增加 time
的值,以捕获可能的错误。
最后,在 finally
块中,我们检查是否需要继续重试。如果是,我们使用 setTimeout
函数延迟一段时间后再次调用 run
函数。否则,我们使用 reject
函数拒绝 Promise,并传递 'timeout' 作为拒绝的原因。
- 接着我们定义了
cancel
和getResult
函数的其余部分:
typescript
const cancel = () => {
isCancel = true;
reject('cancel');
};
return {
cancel,
getResult: () => new Promise<T>((res, rej) => {
reject = rej;
resolve = res;
run();
}).finally(() => {
isFinish = true;
}),
};
};
cancel
函数用于取消重试。它将 isCancel
设置为 true,并使用 reject
函数拒绝 Promise,传递 cancel
作为拒绝的原因。
- 后,我们返回一个对象,包含
cancel
和getResult
方法。getResult
方法返回一个 Promise,用于获取重试的结果。在getResult
方法内部,我们重新定义了reject
和resolve
函数,然后调用run
函数开始执行重试。最后,我们使用finally
方法,在 Promise 完成后将isFinish
设置为 true。
3. 实用案例
为了更好地理解createPromise函数的实际应用,我们将以一个场景为例:网络请求的重试机制。 在现代的Web应用程序中,网络请求往往是必不可少的一部分。然而,由于网络不稳定或服务器响应缓慢等原因,请求可能会失败。为了提高可靠性,我们经常需要实现一个网络请求的重试机制。 使用createPromise函数,我们可以轻松地实现这样的重试机制。以下是一个示例代码:
typescript
const fetchWithRetry = createRetryPromise({
runTask: () => fetch('https://api.example.com/data'), // 发起网络请求
checkSuccess: (response, time) => response.ok || time >= 3, // 判断请求是否成功
time: 5, // 最大重试次数
delayTime: 1000, // 每次重试之间的延迟时间(1秒)
onTry: (time) => console.log(`Retrying... (attempt ${time})`), // 输出重试信息
});
fetchWithRetry.getResult()
.then(response => response.json())
.then(data => console.log('Data:', data))
.catch(error => console.error('Error:', error));
在这个例子中,我们使用createRetryPromise函数创建了一个具有重试功能的网络请求。如果请求成功(response.ok为true),或者重试次数超过3次,请求将被视为成功完成。否则,将在1秒后进行下一次重试。
通过使用createPromise函数,我们可以更好地处理网络请求的失败情况,并在必要时进行重试,提高应用程序的可靠性和用户体验,这点在AI时代会更加突出。
写在最后
很久没在掘金输出过内容了,平时工作真的是特别忙,但是也是想和五湖四海的朋友多多交流,于是想开个自己的小专栏,会不定期的分享一些自己觉得有意思的小知识,或者小感悟吧 嗯,青春可以逝去,我们永远热烈 ❤️🔥❤️🔥🥤😎