Imagine we have an async generator function:
async f * (connection) {
    while (true) {
        ...
        await doStuff()
        yield value
    }
}
Suppose that this function is virtually endless and gives us results of some async actions. We want to iterate these results:
for await (const result of f(connection)) {
    ...
}
Now imagine we want to break out of this for-await loop when some timeout ends and clean things up:
async outerFunc() {
    setTimeout(() => connection.destroy(), TIMEOUT_MS)
    for await (const result of f(connection)) {
        ...
        if (something) {
            return 'end naturally'
        }
    }
}
Assume that connection.destroy() ends the execution of f and ends the for-await loop. Now it would be great to return some value from the outerFunc when we end by timeout. The first thought is wrapping in a Promise:
async outerFunc() {
    return await new Promise((resolve, reject) => {
        setTimeout(() => {
            connection.destroy()
            resolve('end by timeout')
        }, TIMEOUT_MS)
        for await (const result of f(connection)) { // nope
            ...
            if (something) {
                resolve('end naturally')
            }
        }
    })
}
But we cannot use awaits inside Promise and we cannot make the function async due to this antipattern
The question is: how do we return by timeout the right way?
 
     
    