1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-03-01 00:35:28 +08:00

修改promise内存布局,提高了安全性,减少了内存占用

This commit is contained in:
lee
2023-11-17 19:24:55 +08:00
parent 31c618c187
commit 731be48b30

View File

@@ -8,6 +8,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"sync" "sync"
"sync/atomic"
"github.com/duke-git/lancet/v2/internal" "github.com/duke-git/lancet/v2/internal"
) )
@@ -16,14 +17,15 @@ import (
// ref : chebyrash/promise (https://github.com/chebyrash/promise) // ref : chebyrash/promise (https://github.com/chebyrash/promise)
// see js promise: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise // see js promise: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
type Promise[T any] struct { type Promise[T any] struct {
*p_[T]
}
type p_[T any] struct {
runnable func(resolve func(T), reject func(error)) runnable func(resolve func(T), reject func(error))
result T result T
err error err error
wait sync.WaitGroup
pending bool pending atomic.Bool
mu *sync.Mutex
wg *sync.WaitGroup
} }
// New create a new promise instance. // New create a new promise instance.
@@ -32,12 +34,13 @@ func New[T any](runnable func(resolve func(T), reject func(error))) *Promise[T]
panic("runnable function should not be nil") panic("runnable function should not be nil")
} }
p := &Promise[T]{ p := &Promise[T]{&p_[T]{
runnable: runnable, runnable: runnable,
pending: true, wait: sync.WaitGroup{},
mu: &sync.Mutex{}, pending: atomic.Bool{},
wg: &sync.WaitGroup{}, }}
}
p.pending.Store(true)
defer p.run() defer p.run()
@@ -45,11 +48,11 @@ func New[T any](runnable func(resolve func(T), reject func(error))) *Promise[T]
} }
func (p *Promise[T]) run() { func (p *Promise[T]) run() {
p.wg.Add(1) p.p_.wait.Add(1)
go func() { go func() {
defer func() { defer func() {
if !p.pending { if !p.pending.Load() {
return return
} }
@@ -64,50 +67,42 @@ func (p *Promise[T]) run() {
// Resolve returns a Promise that has been resolved with a given value. // Resolve returns a Promise that has been resolved with a given value.
func Resolve[T any](resolution T) *Promise[T] { func Resolve[T any](resolution T) *Promise[T] {
return &Promise[T]{ return &Promise[T]{&p_[T]{
result: resolution, result: resolution,
pending: false, wait: sync.WaitGroup{},
mu: &sync.Mutex{}, pending: atomic.Bool{},
wg: &sync.WaitGroup{}, }}
}
} }
func (p *Promise[T]) resolve(value T) { func (p *Promise[T]) resolve(value T) {
p.mu.Lock() if !p.pending.Load() {
defer p.mu.Unlock()
if !p.pending {
return return
} }
p.result = value p.result = value
p.pending = false p.pending.Store(false)
p.wg.Done() p.wait.Done()
} }
// Reject returns a Promise that has been rejected with a given error. // Reject returns a Promise that has been rejected with a given error.
func Reject[T any](err error) *Promise[T] { func Reject[T any](err error) *Promise[T] {
return &Promise[T]{ return &Promise[T]{&p_[T]{
err: err, err: err,
pending: false, wait: sync.WaitGroup{},
mu: &sync.Mutex{}, pending: atomic.Bool{},
wg: &sync.WaitGroup{}, }}
}
} }
func (p *Promise[T]) reject(err error) { func (p *Promise[T]) reject(err error) {
p.mu.Lock() if !p.pending.Load() {
defer p.mu.Unlock()
if !p.pending {
return return
} }
p.err = err p.err = err
p.pending = false p.pending.Store(false)
p.wg.Done() p.wait.Done()
} }
// Then allows chain calls to other promise methods. // Then allows chain calls to other promise methods.
@@ -149,18 +144,18 @@ func Catch[T any](promise *Promise[T], rejection func(err error) error) *Promise
// Catch chain an existing promise with an intermediate reject function. // Catch chain an existing promise with an intermediate reject function.
func (p *Promise[T]) Catch(reject func(error) error) *Promise[T] { func (p *Promise[T]) Catch(reject func(error) error) *Promise[T] {
return New(func(resolve func(T), rej func(error)) { return New(func(resolve func(T), rej func(error)) {
resutl, err := p.Await() result, err := p.Await()
if err != nil { if err != nil {
rej(reject(err)) rej(reject(err))
return return
} }
resolve(resutl) resolve(result)
}) })
} }
// Await blocks until the 'runable' to finish execution. // Await blocks until the 'runable' to finish execution.
func (p *Promise[T]) Await() (T, error) { func (p *Promise[T]) Await() (T, error) {
p.wg.Wait() p.wait.Wait()
return p.result, p.err return p.result, p.err
} }