Obiekt thenable - jak to działa?

0
const thenable = {
	then: function(resolve, rejected) {
  	rejected("Odrzucono")
  }
}

const promise = Promise.resolve(thenable)
console.log(promise)

Jakim sposobem w resolve zostanie zwrócona wartość z obiektu thenable z funkcji then skoro tutaj Promise.resolve(thenable) odwołujemy się do całego obiektu thenable, a nie do metody then w ten sposób: Promise.resolve(thenable.then())?

1

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve#resolving_thenables_and_throwing_errors

Fragment kodu bezpośrednio z mdn:

var p1 = Promise.resolve({
  then: function(onFulfill, onReject) { onFulfill('fulfilled!'); }
});
console.log(p1 instanceof Promise) // true, object casted to a Promise

p1.then(function(v) {
    console.log(v); // "fulfilled!"
  }, function(e) {
    // not called
});

Metoda resolve może przyjąć then jako wartość i ją wywołać.

1

Jakim sposobem w resolve zostanie zwrócona wartość z obiektu thenable z funkcji then skoro tutaj Promise.resolve(thenable) odwołujemy się do całego obiektu thenable, a nie do metody then w ten sposób: Promise.resolve(thenable.then())?

Fundamentalnie chodzi o to, że Promise sam wywoła then(), kiedy przyjdzie odpowiednia pora - nazywa się to asynchroniczność, a w zasadzie leniwość (lazy, laziness). W drugiej wersji uzycie Promise jest bez sensu, bo zanim je zbudujesz już wyliczasz wartość z then().

Możesz myśleć o tym w ten sposób, że Promise przyjmuje jako parametr funkcje, która zawoła asynchronicznie. Musisz zrozumieć różnice między (pseudokod, bo ja z Javy):

Promise.from(foo())

a

Promise.from({() => foo()})
1

Wiem o co Ci chodzi, i masz rację.

Więc tak: gdyby Promise był idealną modaną, to masz rację, to nie powinno działać, i powinno być tak jak to opisałeś. Problem pojawia się, bo Promise nie jest idealną monadą.

I teraz co to dokładnie znaczy: otóż, w javie np możesz mieć Optional<Optional<Integer>>. Ale w JavaScript nie możesz mieć promise'a w promisie :/ Niestety. Innymi słowy, jak spróbujesz zwrócić Promise z promise'a, to dostaniesz jeden promise.

Dlatego np działa takie coś:

fetch('http://example.com/movies.json')
  .then(response => response.json()) // json() zwraca Promise, ale nie trzeba go "ręcznie" odpakować, bo JS sam zamienia Promise<Promise<?>> na Promise<?>
  .then(data => console.log(data));

Możesz to sobie zobrazować takim kodem.

// promise w promisie
const promiseWPromisie = new Promise(resolve => resolve(new Promise(a => a(2));

// jeden then
promiseWPromisie.then(result => console.log(result));

Teraz, Twój przykład z Promise.resolve() to jest po prostu szczególny przypadek tej zasady, tylko zamiast jawnego then() u Ciebie jest Promise.resolve().

0
Charles_Ray napisał(a):

Ale jest Promise<Thenable<?>>, wiec na jedno wychodzi modulo nazwa funkcji.

Jesteś pewien?

const thenable = {
    then: function(resolve, rejected) {
      rejected("Odrzucono")
    }
}

const promise = new Promise(resolve => resolve(thenable)); // powinien być `Promise<Thenable<?>>`
promise; // a jest Promise<?> (rejected)

Więc nie zrobisz Promise, który ma w środku Thenable, bo od razu ten Thenable jest resolwowany, nieważne czy przez chain, czy przez .then() czy przez Promise.resolve().

1 użytkowników online, w tym zalogowanych: 0, gości: 1