mirror of
https://github.com/duke-git/lancet.git
synced 2026-03-01 00:35:28 +08:00
修改promise内存布局,提高了安全性,减少了内存占用
This commit is contained in:
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user