如何组合可P-Cantoleable和P-Progress NPM软件包以获得可取消的进度报告承诺

发布于 2025-02-11 18:05:29 字数 1958 浏览 1 评论 0原文

我想有一个可取消的承诺,同时报告报告。类似于 p-progress p-cancelable 。尽管它们中的任何一个都很简单,但我正在努力将它们兼而有之。

这是我到目前为止尝试的方法,它成功地报告了进度,但抛出custablePromise.cancel不是函数错误。

import PCancelable from 'p-cancelable';
import PProgress  from 'p-progress';

const cancelablePromise = doJobWithProgress();

try {
    cancelablePromise.onProgress((progress) => {
        console.log('progress: ' + progress);
    });

    await sleep(500);

    cancelablePromise.cancel();

    const result = await cancelablePromise;

    console.log("result", result);
}
catch (error) {
    console.log("Main catch error: " + error);
}

function sleep(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

function doJobWithProgress() {
    return PProgress((progressCallback) => {
        return new PCancelable((resolve, reject, onCancel) => {
            try {
                let progress = 0;

                const interval = setInterval(() => {
                    progress += 0.1;
                    progressCallback(progress);
                }, 100);

                const timeout = setTimeout(() => {
                    const result = 1;
                    clearTimeout(timeout);
                    clearInterval(interval);
                    resolve(result);
                }, 1000);
    
                onCancel(() => {
                    console.log('canceled');
                    clearTimeout(timeout);
                    clearInterval(interval);
                });
            }
            catch (error) {
                console.log('Promise catch error: ' + error);
                reject(error);
            }
        });
    });
}

I would like to have a cancelable promise that reports progress at the same time. Something like a combination of p-progress and p-cancelable. And while usage of any of them separately is simple I'm struggling a bit to combine them both.

This is what I tried so far which successfully reports progress but throws cancelablePromise.cancel is not a function error.

import PCancelable from 'p-cancelable';
import PProgress  from 'p-progress';

const cancelablePromise = doJobWithProgress();

try {
    cancelablePromise.onProgress((progress) => {
        console.log('progress: ' + progress);
    });

    await sleep(500);

    cancelablePromise.cancel();

    const result = await cancelablePromise;

    console.log("result", result);
}
catch (error) {
    console.log("Main catch error: " + error);
}

function sleep(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

function doJobWithProgress() {
    return PProgress((progressCallback) => {
        return new PCancelable((resolve, reject, onCancel) => {
            try {
                let progress = 0;

                const interval = setInterval(() => {
                    progress += 0.1;
                    progressCallback(progress);
                }, 100);

                const timeout = setTimeout(() => {
                    const result = 1;
                    clearTimeout(timeout);
                    clearInterval(interval);
                    resolve(result);
                }, 1000);
    
                onCancel(() => {
                    console.log('canceled');
                    clearTimeout(timeout);
                    clearInterval(interval);
                });
            }
            catch (error) {
                console.log('Promise catch error: ' + error);
                reject(error);
            }
        });
    });
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

久而酒知 2025-02-18 18:05:29

为了使这个完成 - 我最终以@bergi的建议,使用不同的方法,使用abortController并扩展了eventEmitter class(我正在nodejs中编码 - 用于编码 - 您可以继承eventtarget)。

也许有人会对回答原来的问题感兴趣 - 尝试结合两个库时,我最终创建了一个新的casufableprogressprogrespromise类,并从p-progress中复制最必要的部分库并扩展PCANCELABLE

import PCancelable from "p-cancelable";

export default class CancelableProgressPromise extends PCancelable {
    constructor(executor) {
        const setProgress = progress => {
            if (progress > 1 || progress < 0) {
                throw new TypeError('The progress percentage should be a number between 0 and 1');
            }

            (async () => {
                // We wait for the next microtask tick so `super` is called before we use `this`
                await Promise.resolve();

                // Note: we don't really have guarantees over
                // the order in which async operations are evaluated,
                // so if we get an out-of-order progress, we'll just discard it.
                if (progress <= this._progress) {
                    return;
                }

                this._progress = progress;

                for (const listener of this._listeners) {
                    listener(progress);
                }
            })();
        };

        super((resolve, reject, onCancel) => {
            executor(
                value => {
                    setProgress(1);
                    resolve(value);
                },
                reject,
                onCancel,
                progress => {
                    if (progress !== 1) {
                        setProgress(progress);
                    }
                },
            );
        });

        this._listeners = new Set();
        this._setProgress = setProgress;
        this._progress = 0;
    }

    get progress() {
        return this._progress;
    }

    onProgress(callback) {
        if (typeof callback !== 'function') {
            throw new TypeError(`Expected a \`Function\`, got \`${typeof callback}\``);
        }

        this._listeners.add(callback);
        return this;
    }
}

用法示例:

import CancelableProgressPromise from './cancelableProgressPromise.js';

const progressablePromise = doJobWithProgress();

try {
    progressablePromise.onProgress((progress) => {
        console.log('progress: ' + progress);
    });

    await sleep(500);

    progressablePromise.cancel();

    const result = await progressablePromise;

    console.log("result", result);
}
catch (error) {
    console.log("Main catch error: " + error);
}

function sleep(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

function doJobWithProgress() {
    return new CancelableProgressPromise((resolve, reject, onCancel, progressCallback) => {
        try {
            let progress = 0;

            const interval = setInterval(() => {
                progress += 0.1;
                progressCallback(progress);
            }, 100);

            const timeout = setTimeout(() => {
                const result = 1;

                clearTimeout(timeout);
                clearInterval(interval);

                resolve(result);
            }, 1000);

            onCancel(() => {
                console.log('canceled');
                clearTimeout(timeout);
                clearInterval(interval);
            });
        } catch (error) {
            reject(error);
        }
    });
}

// Output:
// progress: 0.1
// progress: 0.2
// progress: 0.30000000000000004
// progress: 0.4
// canceled
// Main catch error: CancelError: Promise was canceled

To make this complete - I ended up, as @Bergi suggested, with a different approach i.e., using AbortController and extending the EventEmitter class (I'm coding in NodeJS - for the web you can inherit EventTarget).

Maybe someone will be interested in answer to the original question - when trying to combine the two libraries I ended up creating a new CancelableProgressPromise class and copy-pasting the most necessary parts from the p-progress library to it and extending the PCancelable:

import PCancelable from "p-cancelable";

export default class CancelableProgressPromise extends PCancelable {
    constructor(executor) {
        const setProgress = progress => {
            if (progress > 1 || progress < 0) {
                throw new TypeError('The progress percentage should be a number between 0 and 1');
            }

            (async () => {
                // We wait for the next microtask tick so `super` is called before we use `this`
                await Promise.resolve();

                // Note: we don't really have guarantees over
                // the order in which async operations are evaluated,
                // so if we get an out-of-order progress, we'll just discard it.
                if (progress <= this._progress) {
                    return;
                }

                this._progress = progress;

                for (const listener of this._listeners) {
                    listener(progress);
                }
            })();
        };

        super((resolve, reject, onCancel) => {
            executor(
                value => {
                    setProgress(1);
                    resolve(value);
                },
                reject,
                onCancel,
                progress => {
                    if (progress !== 1) {
                        setProgress(progress);
                    }
                },
            );
        });

        this._listeners = new Set();
        this._setProgress = setProgress;
        this._progress = 0;
    }

    get progress() {
        return this._progress;
    }

    onProgress(callback) {
        if (typeof callback !== 'function') {
            throw new TypeError(`Expected a \`Function\`, got \`${typeof callback}\``);
        }

        this._listeners.add(callback);
        return this;
    }
}

Usage example:

import CancelableProgressPromise from './cancelableProgressPromise.js';

const progressablePromise = doJobWithProgress();

try {
    progressablePromise.onProgress((progress) => {
        console.log('progress: ' + progress);
    });

    await sleep(500);

    progressablePromise.cancel();

    const result = await progressablePromise;

    console.log("result", result);
}
catch (error) {
    console.log("Main catch error: " + error);
}

function sleep(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

function doJobWithProgress() {
    return new CancelableProgressPromise((resolve, reject, onCancel, progressCallback) => {
        try {
            let progress = 0;

            const interval = setInterval(() => {
                progress += 0.1;
                progressCallback(progress);
            }, 100);

            const timeout = setTimeout(() => {
                const result = 1;

                clearTimeout(timeout);
                clearInterval(interval);

                resolve(result);
            }, 1000);

            onCancel(() => {
                console.log('canceled');
                clearTimeout(timeout);
                clearInterval(interval);
            });
        } catch (error) {
            reject(error);
        }
    });
}

// Output:
// progress: 0.1
// progress: 0.2
// progress: 0.30000000000000004
// progress: 0.4
// canceled
// Main catch error: CancelError: Promise was canceled
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文