Giter Club home page Giter Club logo

promise's Introduction

PROMISE

Go Report Card Build Status Go Reference

Introduction

promise allows you to write async code in sync fashion

Install

$ go get github.com/chebyrash/promise

Quickstart

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/chebyrash/promise"
)

func main() {
	p1 := promise.New(func(resolve func(int), reject func(error)) {
		factorial := findFactorial(20)
		resolve(factorial)
	})
	p2 := promise.New(func(resolve func(string), reject func(error)) {
		ip, err := fetchIP()
		if err != nil {
			reject(err)
		} else {
			resolve(ip)
		}
	})

	factorial, _ := p1.Await(context.Background())
	fmt.Println(*factorial)

	IP, _ := p2.Await(context.Background())
	fmt.Println(*IP)
}

func findFactorial(n int) int {
	if n == 1 {
		return 1
	}
	return n * findFactorial(n-1)
}

func fetchIP() (string, error) {
	resp, err := http.Get("https://httpbin.org/ip")
	if err != nil {
		return "", err
	}

	defer resp.Body.Close()

	type Response struct {
		Origin string `json:"origin"`
	}
	var response Response

	err = json.NewDecoder(resp.Body).Decode(&response)
	return response.Origin, err
}

Pool

  • Promise execution can be dispatched to distinct pools, providing granular control over task distribution and concurrency.

  • Better performance can be achieved by allowing different stages of a Promise chain to be executed on different goroutine pools, optimizing for the specific requirements of each task.

package main

import (
	"context"

	"github.com/chebyrash/promise"
)

func main() {
	ctx := context.Background()

	// fetches data from API, runs on ioOptimizedPool
	dataPromise := promise.NewWithPool(func(resolve func(string), reject func(error)) {
		data, err := fetchDataFromAPI()
		if err != nil {
			reject(err)
		} else {
			resolve(data)
		}
	}, ioOptimizedPool)

	// computes result based on the fetched data, runs on cpuOptimizedPool
	resultPromise := promise.ThenWithPool(dataPromise, ctx, func(data string) (string, error) {
		result, err := computeResult(data)
		return result, err
	}, cpuOptimizedPool)
}

promise's People

Contributors

asmyasnikov avatar chebyrash avatar creker avatar cristaloleg avatar elycruz avatar kochurovro avatar mike-dax avatar theodesp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

promise's Issues

Promise Branching

Hello,

One of the powerful features of Promises in a JS context is the ability to 'branch' the 'then' functions.

One promise can provide data to multiple other promises that do independent things with it.

In Go, take this example code:

		p1 := promise.New(func(resolve func(interface{}), reject func(error)) {
			time.Sleep(time.Millisecond * 1000)
      
			fmt.Println("1 resolved")
			resolve(uint8(1))
		})

		p1doubled := p1.Then(func(data interface{}) interface{} {
			num := data.(uint8)

			time.Sleep(time.Millisecond * 2000)
			fmt.Println("double resolved")

			return num * 2
		})

		p1tripled := p1.Then(func(data interface{}) interface{} {
			num := data.(uint8)

			time.Sleep(time.Millisecond * 500)
			fmt.Println("triple resolved")

			return num * 3
		})

		oneD, _ := p1.Await()
		one := oneD.(uint8)

		twoD, _ := p1doubled.Await()
		two := twoD.(uint8)

		threeD, _ := p1tripled.Await()
		three := threeD.(uint8)

		fmt.Println(one)
		fmt.Println(two)
		fmt.Println(three)

The expected behaviour would be for it to print:

1 resolved
triple resolved (500ms later)
double resolved (1500ms after that)
1 (all at once)
2 (^)
3 (^)

However the current behaviour assumes all promises exist as 'chains' with no branches. This also causes 'waterfall' behaviour with its execution.

1 resolved
double resolved (2000ms later)
triple resolved (500ms after that)
6 (all at once)
6 (^)
6 (^)

I assume the former would actually be the intended behaviour for the library given the comments for the Then function:

	// Appends fulfillment to the promise,
	// and returns a new promise.

The Then function distinctly does not return a new promise, it returns the same promise, adding the fulfilment function to the list.

The fix is relatively simple, copy the Promise every time the Then function is called to branch it off, actually returning a new Promise.

The Catch function should not return a new promise, but the old promise, it should not copy it.

Essentially this:

// Then appends a fulfillment handler to the Promise, and returns a new promise.
func (promise *Promise) Then(fulfillment func(data interface{}) interface{}) *Promise {
	promise.mutex.Lock()
	defer promise.mutex.Unlock()

	promiseCopy := promise.copy()

	switch promiseCopy.state {
	case pending:
		promiseCopy.wg.Add(1)
		promiseCopy.then = append(promiseCopy.then, fulfillment)
	case fulfilled:
		promiseCopy.result = fulfillment(promiseCopy.result)
	}

	return promiseCopy
}

// copy creates a copy of a Promise that resolves when it does, it returns the new Promise.
func (promise *Promise) copy() *Promise {
	p := New(func(resolve func(interface{}), reject func(error)) {
		data, err := promise.Await()

		if err != nil {
			reject(err)
			return
		}

		resolve(data)
	})

	return p
}

This obviously changes the behaviour of the library in a breaking manner.

Would a PR like this be accepted? I would assume a major version bump to v2 would have to be done?

Alternatively I can just create a fork with the different behaviour.

What are your thoughts?

Thanks.

Any plans to add remainder of JS promise interface to this implementation?

The specification for javascript promises has evolved by a couple of methods since this library was created and was just wondering if we should start hacking up the remaining JS promise methods into the lib?

MDN reference:

Also I started hacking them up here: https://github.com/elycruz/promise/tree/issue-%23-js_promise_interface (for my own benefit :-D).

Thanks 👍

The error return bug in promise.All function

Problem: When there are more than two rejected promises in promise.All function. The returned error value is not stable。

Please infer blow image: the println err.Error() output maybe error1 or error2, in js promise. it is error1.

image

Add `AllSettled` method to package.

Spec Reference:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled

Example reference:
https://github.com/tc39/proposal-promise-allSettled#examples

Example reference:
https://github.com/tc39/proposal-promise-allSettled#real-world-scenarios

Method

  • - AllSettled

Tests

  • - With nil promises.
  • - With an empty list of promises (same as above just explicit).
  • - With only one passing promise.
  • - With only passing promises.
  • - With only one failing promise.
  • - With only failing promises.
  • - With a mix of passing and failing promises.

Promise.all slice

Hi,

Is there a way to perform promise.All() on a slice? Something like this:

		for _, completedTransaction := range promises {
			completedTransaction.Await()
		}

but built in. I realize a workaround is available now by using reflection, but this doesn't work with too many values.

how to support timeout ?

your example is get ip from the remote
but if my network is poor that it'll last long time
i wanna to reject after 3 second if the ip does't get

promise.Any does not exist

In the README as well as in the examples, you use promise.Any for typing but it is not exported by the package.

Add `All` method to 'promise' package

Creating separate issue for each method we're working on adding into the lib (this one's just for the All method).

Methods:

  • - All

Tests:

  • - All
    • - With no promises.
    • - With resolved promises (1 or more).
    • - With only resolved promises (1 or more).
    • - With failing promises (1 or more).
    • - With only failing promises (1 or more).

Range over promise.All

So, i'm working on something like this:

artists, err := promise.All(promises...).Await()

for _, artist := range artists {
    doSomethingWith(artist)
}

But, because .Await() returns a interface{}, i can't range through it
image

I also tried to specify the type:

var artists []*structs.ArtistResponse
artists, _ = promise.All(promises...).Await()

for _, artist := range artists {
    doSomethingWith(artist)
}

But then, i receive this:
image

I'm using Go 1.15

Questions: run in parallel and stop

HI,

Few questions.

  1. Does each promise run in go routine ?
  2. in case each promise run in go-routine , is it possible to use timeout ?

e.g. in case you are running promise.all for promise A and promise B and you want to wait for 10 seconds for all the responses (time limit) ,but promise A continue to run (possible forever due to some issue), is it possible to kill promise A after the 10 seconds ? (when you want to get the results with the time limt)

Thanks!

Add `Race` method to the package

This is the only other method from the JS Ecmascript 2015 standard that is not implemented here (other than the All method (which has a pull request on the way)).

Link to 'race' docs on MDN:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race

This issue will be to track the work done on it:

Method:

  • - Race

Tests:

  • - With no promises.
  • - With one promise, a passing one.
  • - With multiple passing promises.
  • - With one promise, a failing one.
  • - With multiple promises and one failing.
  • - With multiple failing promises.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.