Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

Support for returning promises, and async/await functions.

Aperta
#25 6 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
5/5
Tempo stimato
Più di una settimana
Idoneità per principianti
25/100
Tipo di issue
Funzionalità
Chiarezza
Da chiarire
Stato di attività
Ferma
Stack tecnologico
javascript
Ambito
backend

Direzione di ricerca

Inizia con la normalizzazione async/sync di ambi e con i livelli Task e TaskGroup descritti nell'issue. Confronta le API proposte per il consumo e la produzione di promises, inclusi i callback che restituiscono promises e la gestione degli errori, prima di restringere le alternative irrisolte a un ambito definito. Il lavoro è completato quando è stata concordata una direzione di implementazione e convalidato il comportamento di interop selezionato.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Promises run immediately, and thus all at once, do not catch/isolate uncaught async errors, and can lose errors if .catch was not specified pedantically. Tasks run when you tell them too and using domains can catch/isolate uncaught errors within a task, and will throw errors if not handled. TaskGroup can thus control the concurrency, and be configured on how to deal with error situations - continue, pause, or by default abort and clear - and again, will throw errors if not handled. These factors alone provide why TaskGroup is superior to Promises, however, nevertheless, Promises are popular, and we should provide ways of supporting them to make integration, and perhaps conversion, with that scene easier.

The relevant layers of TaskGroup are:

  • ambi for async/sync method signature normalisation, used by Task, to wrap execute methods
  • Task and TaskGroup

Here are the options I can determine.

Consumption

Add promise consumption to ambi, such that one can do this:

// note the promise runs when the task runs
Task.create(function () {
    return new Promise(function(resolve, reject) {
        setTimeout(function () {
            const result = Math.floor(Math.random() * 1000)
                if ( result % 2 ) {
                    resolve(result)
            }
            else {
                reject(new Error('result did not become an even number'))
            }
        }, 1000)
    })
})

Add promise consumption support to Task, such that one can do this:

// note the promise runs immediately, and will not support things such as task arguments
Task.create(new Promise(function(resolve, reject) {
    setTimeout(function () {
        const result = Math.floor(Math.random() * 1000)
        if ( result % 2 ) {
            resolve(result)
        }
        else {
            reject(new Error('result did not become an even number'))
        }
    }, 1000)
})

Add promise consumption support to TaskGroup, such that one can do this:

// note the promise runs immediately, and will not support things such as task arguments
tasks.addPromise(new Promise(function(resolve, reject) {
    setTimeout(function () {
        const result = Math.floor(Math.random() * 1000)
        if ( result % 2 ) {
            resolve(result)
        }
        else {
            reject(new Error('result did not become an even number'))
        }
    }, 1000)
})

Production

Exposing promises could be done via providing a .promise getter instead of .done(callback):

// Task
Task.create(someTaskMethod).run().promise
    .then(console.log)
    .catch(console.error)

// TaskGroup
TaskGroup.create({storeResult: true}).addTasks(someTasks).run().promise
    .then(console.log)
    .catch(console.error)

I lean towards the above over having Task and TaskGroup extend the Promise class, as the promise API is an ever expanding glob or crap trying to workaround their inherent shortcomings - hence the introduction of their proposed done method and other official and non-official spec modifications implemented by the vast array of promise scene implementations.

However, the above requires the consumer to be aware that what they are consuming is a Task or TaskGroup, rather than just a promise, which if you are writing a simple library, may not be ideal. Once could write a wrapper around Task and TaskGroup, that could swap out their excellent API for the wrose Promise API. Such as:

// Include special versions
const {Task, TaskGroup} = require('taskgroup-promise')

// Task
Task.create((x, y) => x * y).run().promise
    .then(console.log)
    .catch(console.error)

// TaskGroup
TaskGroup.create({storeResult: true}).addTasks(someTasks).run().promise
    .then(console.log)
    .catch(console.error)

However, I am not sure fragmenting the TaskGroup ecosystem makes sense in this way, hence why I still lean towards a .promise getter.

Conclusions

Other ideas and discussion are welcome.

For consumption, seems adding promise consumption to ambi makes the most sense, as adding support to Task and TaskGroup means promises fire immediately, and there will be no support for things like task args. To make things easier, such that Task.create(new Promise(...)) is supported, ambi could check if the method is already a promise, before executing it and checking the return result. A question here, is what if a method returns a promise and accepts a callback as many interop libraries do.

For production, seems doing .promise is the best idea. Perhaps even with a getter for .then and .catch to alias .promise.then and .promise.catch for easier interop - however I am not sure if implementing such things will pass the promise scene's isPromise checks:

// note the promise runs when the task runs
Task.create(function (complete) {
    const p = new Promise(function(resolve, reject) {
        setTimeout(function () {
            const result = Math.floor(Math.random() * 1000)
                if ( result % 2 ) {
                    resolve(result)
            }
            else {
                reject(new Error('result did not become an even number'))
            }
        }, 1000)
    })
        if ( complete ) p.then((result) => complete(null, result)).catch(complete)
        return p  // could be `else return p` but that would not have any problem
})

Would be interesting to see how ambi or Task handles the above case, in terms of what error or enforcement it should produce, or whether it should discard the callback or the promise.

It is also worth mentioning our Chainy project, that provides the chaining abilities of promises to the TaskGroup ecosystem, in a microjs way.

Lingua principale
JavaScript
Stelle
50
Fork
12
Merge medio
2m
PR unite (30g)
2

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di bevry/taskgroup

Tutte le issue di bevry/taskgroup

Issue simili

Altre issue su JavaScript

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.