PromiseCapability and Then method for Value

I wanted a clean way to return/await promises without global state or parsing code.

I am wondering what your thoughts are on a Go-side queue that would execute tasks in ExecutePendingJobs.

In my prototype, I had something like this:

func (vm *VM) EventLoop() error {
	for {
		n, err := vm.ExecutePendingJobs()
		if err != nil {
			return fmt.Errorf("ExecutePendingJobs: %w", err)
		}
		if n > 0 {
			continue
		}
		if vm.pending == 0 {
			return nil
		}
		(<-vm.tasks)()
		vm.pending--
	}
}

func (vm *VM) schedule(fn func()) {
	vm.tasks <- fn
}

One pending task per Promise:

func (vm *VM) NewPromise() (*Promise, error) {
	p, resolve, reject, err := NewPromise(vm.VM)
	if err != nil {
		return nil, err
	}
	vm.pending++
	return &Promise{vm: vm, promise: p, resolve: resolve, reject: reject}, nil
}

func (p *Promise) Resolve(value any) {
	p.vm.schedule(func() {
		p.resolve.Call(quickjs.UndefinedValue, value)
		p.Free()
	})
}

In order to solve this in a generic way, maybe we could generalize a Promise (or task) as a goroutine. As long as there is a goroutine running, we would await more tasks, roughly:

vm.RegisterFunc("startAsync", func(args ...any) quickjs.Value {
	vm.Go(func() {
		time.Sleep(time.Millisecond * 200)
		promise.Resolve("async result")
	})
	return promise
}, false)

I'm looking forward to your take on it.

Next, I want to look at async generators.

Merge request reports

Loading