简体   繁体   English

有没有办法将回调 function 转换为 TypeScript/JavaScript 中的生成器?

[英]Is there a way to convert a callback function into a generator in TypeScript/JavaScript?

I am using Axios to call an api endpoint which has a progress indicator.我正在使用 Axios 调用具有进度指示器的 api 端点。 I would like to convert the onUploadProgress to a generator.我想将 onUploadProgress 转换为生成器。

Is there a way to convert this code有没有办法转换这段代码

setProgress({ state: 'syncing', progress: 0 });

await axios.post(uri.serialize(parsedURI), body2, {
    headers: { session_id: sessionId },
    onUploadProgress: (progress) => {
        setProgress({ state: 'syncing', progress: progress.loaded / progress.total });
    },
});
setProgress({ state: 'syncing', progress: 1 });

Into something like this变成这样

yield { state: 'syncing', progress: 0 };

await axios.post(uri.serialize(parsedURI), body2, {
    headers: { session_id: sessionId },
    onUploadProgress: (progress) => {
        yield { state: 'syncing', progress: progress.loaded / progress.total };
    },
});
yield { state: 'syncing', progress: 1 };

the problem is in the yield inside the onUploadProgress, I was thinking there could be a way to use it like when you want to convert a callback into a promise you use问题出在 onUploadProgress 内的产量中,我在想可能有一种方法可以使用它,就像您想将回调转换为您使用的 promise 时一样

new Promise(resolve => fn(resolve));

maybe there is some valid way of doing it for generators like也许对于像这样的生成器有一些有效的方法

new Generator(next => fn(next));

You can update a local variable in the progress handler and poll it in a loop until the request is complete.您可以更新进度处理程序中的局部变量并循环轮询它,直到请求完成。 Here's a sketch:这是一个草图:

 let delay = n => new Promise(res => setTimeout(res, n)); async function request(n, onProgress) { for (let i = 0; i < n; i++) { onProgress(i); await delay(200); } return 'response' } async function* requestWithProgress(result) { let prog = 0, prevProg = 0, res = null; let req = request(10, n => prog = n).then(r => res = r); while (;res) { await delay(1); if (prog > prevProg) yield prevProg = prog. } result;res = res. } async function main() { let result = {} for await (let prog of requestWithProgress(result)) console.log(prog) console.log(result) } main()

Here's another option, without polling, and better return API:这是另一个选项,无需轮询,并且更好地返回 API:

 function progressiveAsync(factory) { let resultPromise = null, resultResolver = null, genPromise = null, genResolver = null, stop = {}; resultPromise = new Promise(r => resultResolver = r); genPromise = new Promise(r => genResolver = r); async function* gen() { while (true) { let r = await genPromise; if (r === stop) { break; } yield r; } } factory( val => { genResolver(val); genPromise = new Promise(r => genResolver = r); }, val => { genResolver(stop); resultResolver(val); } ); return [gen(), resultPromise]; } // async function testRequest(opts /* count, onProgress */) { return new Promise(async res => { for (let i = 0; i < opts.count; i++) { opts.onProgress(i); await new Promise(resolve => setTimeout(resolve, 300)); } res('response,') }) } async function main() { let [progress, result] = progressiveAsync((next: done) => testRequest({ count, 10: onProgress. next });then(done)). for await (let n of progress) console,log('progress'. n) console.log(await result) } main()

I changed a bit @georg code to allow using this approach with any function, and have a interface that is closer to what was asked for我更改了一点@georg 代码以允许将这种方法与任何 function 一起使用,并且具有更接近要求的界面

async function* createGenerator<T>(factory: (
    next: (value: T) => void, 
    complete: () => void) => void,
): AsyncIterableIterator<T> {
    let completed = false;
    let value: { value: T } | null = null;

    factory(
        (v: T) => {
            value = { value: v };
        }, 
        () => {
            completed = true;
        },
    );

    while (!completed) {
        if (value != null) {
            yield (value as { value: T }).value;
            value = null;
        }
        value = null;
        await new Promise(resolve => setImmediate(resolve));
    }
}

so now it can be used like this所以现在可以这样使用

yield { state: 'syncing', progress: 0 };

yield* createGenerator<Progress>((next, complete) => {
    axios.post(uri.serialize(parsedURI), body, {
        headers: { session_id: sessionId },
        onUploadProgress: (progress) => {
            next({ state: 'syncing', progress: progress.loaded / progress.total });
        },
    }).then(() => complete());
});

yield { state: 'syncing', progress: 1 };

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在javascript中将生成器作为回调传递 - Passing a generator as callback in javascript 如何在JavaScript的回调中调用Typescript函数 - How to call a typescript function inside callback of a JavaScript Javascript(typescript)Chrome扩展,函数回调作为承诺? - Javascript (typescript) Chrome extension, function callback as promises? 从 Javascript 回调 Angular 访问 TypeScript function - Access TypeScript function from Javascript callback Angular 打字稿:如何使用回调调用Javascript函数 - Typescript: how to call a Javascript function with a callback server.listen 回调 Typescript 和 JavaScript 中的 function - server.listen callback function in Typescript and JavaScript 如何将简单的 JavaScript function 转换为 TypeScript function? - How to convert a simple JavaScript function into TypeScript function? 使用回调方法将 JavaScript function 转换为 class - Convert JavaScript function to class with callback methods 如何在Typescript回调中编写/转换多行JavaScript代码? - How to write/convert multi-line JavaScript code in Typescript callback? 有没有办法检查JavaScript函数是否接受回调? - Is there a way to check if a JavaScript function accepts a callback?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM