Eşzamansız işlevim neden bir değer yerine Promise {<pending>} döndürüyor?


130

Kodum:

let AuthUser = data => {
  return google.login(data.username, data.password).then(token => { return token } )
}

Ve böyle bir şeyi çalıştırmayı denediğimde:

let userToken = AuthUser(data)
console.log(userToken)

Ben alıyorum:

Promise { <pending> }

Ama neden?

Ana hedefim, google.login(data.username, data.password)bir sözden dönen jetonu bir değişkene almaktır. Ve ancak o zaman bazı eylemleri önceden gerçekleştirin.


1
@ LoïcFaure-Lacroix, bu makaleye bakın: medium.com/@bluepnume/…
Src

@ LoïcFaure-Lacroix getFirstUserfonksiyona bak
Src

Peki ne olacak? Bir söz veren bir işlevdir.
Loïc Faure-Lacroix

1
@ LoïcFaure-Lacroix yani bu örnekte bile getFirstUser işlevinde dönen verilere erişmek için kullanmamız gerektiğini mi söylüyorsunuz?
Src

Bu örnekte evet, diğer tek yol, sözün sonucunu beklemek için mevcut bağlamın yürütülmesini durdurmayı çözen ES7 sözdizimini "bekle" kullanmaktır. Makaleyi okursanız görürsünüz. Ancak ES7 muhtemelen henüz hiçbir yerde desteklenmediğinden, evet. "O zaman" aşağı yukarı öyle.
Loïc Faure-Lacroix

Yanıtlar:


177

Söz, sonuçları henüz çözülmediği sürece her zaman beklemede olacaktır. .thenVaat edilen durumdan bağımsız olarak (çözüldü veya hala beklemede) sonuçları alma sözünü çağırmalısınız :

let AuthUser = function(data) {
  return google.login(data.username, data.password).then(token => { return token } )
}

let userToken = AuthUser(data)
console.log(userToken) // Promise { <pending> }

userToken.then(function(result) {
   console.log(result) // "Some User token"
})

Neden?

Sözler yalnızca ileriye yöneliktir; Bunları yalnızca bir kez çözebilirsiniz. A'nın çözümlenmiş değeri veya yöntemlerine Promiseaktarılır ..then.catch

ayrıntılar

Sözler / A + özelliklerine göre:

Vaat çözüm prosedürü, girdi olarak bir vaadi ve değeri [[Çöz]] (vaat, x) olarak ifade ettiğimiz soyut bir işlemdir. Eğer x bir uygunsa, x'in en azından bir şekilde bir vaat gibi davrandığı varsayımı altında, x durumunu benimsemeye söz vermeye çalışır. Aksi takdirde x değeri ile verilen sözü yerine getirir.

Söz konusu ürünlerin bu şekilde ele alınması, Promises / A + uyumlu bir yöntemi ortaya koydukları sürece, sözlü uygulamaların birlikte çalışmasına izin verir. Ayrıca, Promises / A + uygulamalarının, uygun olmayan uygulamaları makul yöntemlerle "özümsemesine" olanak tanır.

Bu spesifikasyonu ayrıştırmak biraz zor, bu yüzden onu parçalayalım. Kural şudur:

.thenİşleyicideki işlev bir değer döndürürse, o değerle Promiseçözümlenir. İşleyici başka bir tane döndürürse Promise, orijinal Promisezincirleme çözümlenmiş değeri ile çözümlenir Promise. Bir sonraki .thenişleyici her zaman bir önceki bölümde döndürülen zincirleme vaadin çözümlenmiş değerini içerecektir .then.

Gerçekte çalışma şekli aşağıda daha ayrıntılı olarak açıklanmaktadır:

1. .thenFonksiyonun geri dönüşü , vaadin çözümlenmiş değeri olacaktır.

function initPromise() {
  return new Promise(function(res, rej) {
    res("initResolve");
  })
}

initPromise()
  .then(function(result) {
    console.log(result); // "initResolve"
    return "normalReturn";
  })
  .then(function(result) {
    console.log(result); // "normalReturn"
  });

2. .thenİşlev a döndürürse Promise, zincirleme sözün çözümlenmiş değeri aşağıdakine iletilir .then.

function initPromise() {
  return new Promise(function(res, rej) {
    res("initResolve");
  })
}

initPromise()
  .then(function(result) {
    console.log(result); // "initResolve"
    return new Promise(function(resolve, reject) {
       setTimeout(function() {
          resolve("secondPromise");
       }, 1000)
    })
  })
  .then(function(result) {
    console.log(result); // "secondPromise"
  });

İlki çalışmıyor. Uncaught SyntaxError: Unexpected token .. İkincisinin iadesi gerekiyorPromise
zamil

@zamil, ikinci örnekteki gibi işlevi çağırmalısınız. sen cant .thenbir uninvoked fonksiyonu üzerine. cevabı güncelledi
Bamieh

1
Bunu sonsuza kadar saklayabilmek için işaretliyorum. Vaatlerin gerçekte nasıl oluşturulacağına dair gerçekten açık ve okunabilir kurallar bulmak için ÇOK uzun süredir çalışıyorum. Promises / A + spec bloğunuz, vaatleri kendi kendine öğretmenin neden bir PITA olduğuna dair mükemmel bir örnektir. Aynı zamanda setTimeout'un dersin kendisini karıştırmadığı yerde kullanıldığını gördüğüm YALNIZCA zamandır. Ve mükemmel referans, teşekkürler.
Monsto

21

Bu sorunun 2 yıl önce sorulduğunu biliyorum, ancak ben de aynı sorunla karşılaştım ve sorunun cevabı ES6'dan beri, basitçe awaitişlevlerin değerini döndürebilirsiniz, örneğin:

let AuthUser = function(data) {
  return google.login(data.username, data.password).then(token => { return token } )
}

let userToken = await AuthUser(data)
console.log(userToken) // your data

3
İhtiyacınız yok .then(token => return token), bu sadece gereksiz bir geçiş. Google giriş aramasına geri dönmeniz yeterlidir.
Soviut

Bu yanıtın soruyla ilgisi yoktur. Orijinal posterin probleminin ES6 'async / await ile ilgisi yoktur. Bu yeni sözdizimsel şeker ECMAScript 2017'de tanıtılmadan önce vaatler vardı ve Promises "başlık altında" kullanılıyordu. Zaman uyumsuz / beklemede MDN'ye bakın .
try-catch-nihayet

ES8 / Nodejs için, zaman awaituyumsuz bir işlevin dışında kullanırsanız hatalar atılır . Belki burada daha iyi örnek yapmak olacaktır AuthUserfonksiyonu asyncile daha sonra uçları, oreturn await google.login(...);
Jon L.

4

thenYöntem çağrısına kayıtlı bir sonuç işleyici dönüş değeri asenkron çözülebilir bekleyen bir söz verir thendenilen işleyicisi içinde bir hata atarak veya geri çevirdi.

Bu nedenle arama AuthUser, kullanıcının aniden eşzamanlı olarak oturum açmasına neden olmaz, ancak oturum açma başarılı olduktan (veya başarısız olduktan) sonra kaydedilen işleyicileri çağrılacak olan bir söz verir. Tüm giriş işlemlerinin thengiriş vaadinin bir maddesi ile tetiklenmesini öneririm . EG, akış sırasını vurgulamak için adlandırılmış işlevleri kullanarak:

let AuthUser = data => {   // just the login promise
  return google.login(data.username, data.password);
};

AuthUser(data).then( processLogin).catch(loginFail);

function processLogin( token) {
      // do logged in stuff:
      // enable, initiate, or do things after login
}
function loginFail( err) {
      console.log("login failed: " + err);
}

1

Vaatler hakkındaki MDN bölümüne bakın . Özellikle, then () dönüş türüne bakın .

Oturum açmak için, kullanıcı aracısının sunucuya bir istek göndermesi ve bir yanıt almayı beklemesi gerekir. Uygulamanızı bir istek gidiş dönüşü sırasında yürütmeyi tamamen durdurmanız genellikle kötü bir kullanıcı deneyimine yol açtığından, oturumunuzu açan (veya başka herhangi bir sunucu etkileşimi gerçekleştiren) hemen hemen her JS işlevi bir Söz veya buna çok benzer bir şey kullanacaktır. , sonuçları eşzamansız olarak sunmak için.

Şimdi, returnifadelerin her zaman içinde göründükleri işlev bağlamında değerlendirildiğine dikkat edin . Yani şunu yazdığınızda:

let AuthUser = data => {
  return google
    .login(data.username, data.password)
    .then( token => {
      return token;
    });
};

ifadesi return token;anonim işlev iletilmek anlamına geliyordu then(), jeton döndürmez o gerektiğini AuthUser, fonksiyon. Geri AuthUserdönen, google.login(username, password).then(callback);bir Söz olan çağırmanın sonucudur .

Sonuçta geri token => { return token; }aramanız hiçbir şey yapmaz; bunun yerine, then()girdinizin jetonu bir şekilde işleyen bir işlev olması gerekir.


@Src Cevabımı, soruyu soran kişi eşzamanlı olarak bir değer döndürmenin bir yolunu aradıklarını açıklamadan önce ve geliştirici ortamları veya dil sürümleri hakkında kod pasajından çıkarılabileceklerin ötesinde varsayımlar yapmadan yazdım - yani güvenli ES6 varsayılır, ancak ES7 olması gerekmez.
Jesse Amano

@AhmadBamieh Pekala, yapacağız. Sorunun, returnyeni (ish) kapanma sözdizimi ile nasıl ele alındığını yanlış anladığımı varsayıyorum, bu durumda - bunu kesinlikle onaylamıyorum, ancak hata hala benim ve bunun için özür dilerim.
Jesse Amano

2
@AhmadBamieh Er, aslında o kısmı biliyordum, bu yüzden bunun ters etki yaptığını iddia etmek yerine token => { return token; } hiçbir şey yapmadığını iddia ettim. google.login(username, password).then(token=>{return token;}).then(token=>{return token;})Sonsuza kadar ve benzeri şeyler söyleyebilirsiniz , ancak yalnızca bir jetonla çözülen bir döndürmeyi Promisebaşarırsınız - aynen bırakmışsınız gibi google.login(username, password);. Bunun neden "çok yanlış" olduğunu düşündüğünden emin değilim.
Jesse Amano

1
@AhmadBamieh: Bu metinde neyin yanlış olduğu konusunda daha net olabilir misiniz? Hiçbir şey görmüyorum, sadece neden return tokenOP'nin beklediği gibi çalışmadığını açıklıyor .
Bergi

3
@AhmadBamieh: Gerçekten bir yanlış anlaşılma var. Üçümüz de vaatlerin nasıl işlediğini çok iyi biliyoruz, ifade promise.then(result => { return result; })tam olarak eşdeğerdir promise, bu nedenle yöntem çağrısı hiçbir şey yapmaz ve kodu basitleştirmek ve okunabilirliği artırmak için bırakılmalıdır - tamamen doğru bir ifade.
Bergi

1

Kişisel Promise kadar tamamlayıp, beklemede

userToken.then(function(result){
console.log(result)
})

kalan kodunuzdan sonra. Bu kodun yaptığı tek şey .then(), sözünüzü tamamlamak ve sonuç değişkeni ile sonuç değişkenini ve konsolda çıktıyı yazdırmaktır. Unutmayın, sonucu global değişkende saklayamazsınız. Umarım bu açıklama size yardımcı olabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.