async / await örtük olarak döndürür promise


111

asyncAnahtar kelimeyle işaretlenen eşzamansız işlevlerin örtük olarak bir söz verdiğini okudum :

async function getVal(){
 return await doSomethingAync();
}

var ret = getVal();
console.log(ret);

ama bu tutarlı ... varsayarak değil doSomethingAsync()bir söz döner ve bekliyoruz kelime vaadi değeri dönecektir, sonra benim getVal fonksiyonu, itsef vaat should bu değeri değil, örtük bir söz döner.

Peki durum tam olarak nedir? Async anahtar kelimesiyle işaretlenen işlevler dolaylı olarak vaatleri mi döndürür yoksa geri döneceklerini biz mi kontrol ederiz?

Belki de bir şeyi açıkça iade etmezsek, dolaylı olarak bir söz verirler ...?

Daha açık olmak gerekirse, yukarıdakiler ile

function doSomethingAync(charlie) {
    return new Promise(function (resolve) {
        setTimeout(function () {
            resolve(charlie || 'yikes');
        }, 100);
    })
}

async function getVal(){
   var val = await doSomethingAync();  // val is not a promise
   console.log(val); // logs 'yikes' or whatever
   return val;  // but this returns a promise
}

var ret = getVal();
console.log(ret);  //logs a promise

Benim özetime göre, davranış gerçekten de geleneksel dönüş ifadeleriyle tutarsız. Görünüşe göre, bir asyncişlevden taahhüt edilmeyen bir değeri açık bir şekilde döndürdüğünüzde , onu bir sözde sarmaya zorlayacaktır. Bununla ilgili büyük bir sorunum yok, ancak normal JS'ye meydan okuyor.


1
Ne console.loggösteriyor?
Barmar

bu sözün kendisi değil, sözün çözümleme işlevi tarafından iletilen değerdir
Alexander Mills

Belki de sözün sonucunun çözülmesini beklersiniz.
Hamlet Hakobyan

aslında, yanılmışım, bir söz
Alexander Mills

2
JavaScript'in vaatleri, c # 'nin eşzamansız bekleme davranışını taklit etmeye çalışıyor. Bununla birlikte, geçmişte bunu c # ile desteklemek için pek çok yapı vardı ve JavaScript'te yok. Bu nedenle, birçok kullanım durumunda çok benzer görünse de, bir şekilde yanlış bir isimdir.
Travis J

Yanıtlar:


138

Dönüş değeri her zaman bir vaat olacaktır. Bir sözü açıkça iade etmezseniz, iade ettiğiniz değer otomatik olarak bir sözle sarılır.

async function increment(num) {
  return num + 1;
}

// Even though you returned a number, the value is
// automatically wrapped in a promise, so we call
// `then` on it to access the returned value.
//
// Logs: 4
increment(3).then(num => console.log(num));

Aynı şey olsa bile await.

function defer(callback) {
  return new Promise(function(resolve) {
    setTimeout(function() {
      resolve(callback());
    }, 1000);
  });
}

async function incrementTwice(num) {
  const numPlus1 = await defer(() => num + 1);
  return numPlus1 + 1;
}

// Logs: 5
incrementTwice(3).then(num => console.log(num));

Otomatik olarak açılma sözü verir, bu nedenle bir asyncişlevin içinden bir değer için bir söz verirseniz, değer için bir söz alırsınız (değer için bir söz için bir söz değil).

function defer(callback) {
  return new Promise(function(resolve) {
    setTimeout(function() {
      resolve(callback());
    }, 1000);
  });
}

async function increment(num) {
  // It doesn't matter whether you put an `await` here.
  return defer(() => num + 1);
}

// Logs: 4
increment(3).then(num => console.log(num));

Benim özetime göre, davranış gerçekten de geleneksel dönüş ifadeleriyle tutarsız. Eşzamansız bir işlevden açık bir şekilde söz dışı bir değer döndürdüğünüzde, söz konusu değeri bir sözde sarmaya zorlayacağı anlaşılıyor. Bununla ilgili büyük bir sorunum yok, ancak normal JS'ye meydan okuyor.

ES6, .NET Framework ile tam olarak aynı değeri döndürmeyen işlevlere sahiptir return. Bu işlevlere jeneratörler denir.

function* foo() {
  return 'test';
}

// Logs an object.
console.log(foo());

// Logs 'test'.
console.log(foo().next().value);

3
Promise.resolve statik yöntemi ile "döndürdüğünüz değer otomatik olarak bir söze sarılacaktır", yani bir zaman uyumsuz işlevin dönüş ifadesi ise - return x; dolaylı olarak şu hale gelir - return Promise.resolve (x);
adnan2

Açıkça kendiniz oluşturmak yerine otomatik olarak oluşturulan sözü geri vermek kötü bir uygulama olarak kabul edilir mi? Her nasılsa, birçok durumda temiz yaklaşımı seviyorum.
marlar

24

Spesifikasyona bir göz attım ve aşağıdaki bilgileri buldum. Kısa versiyon, s async functionveren bir jeneratöre bir desugars olmasıdır Promise. Yani, evet, eşzamansız işlevler söz verir .

Tc39 spesifikasyonuna göre aşağıdakiler doğrudur:

async function <name>?<argumentlist><body>

Desugars:

function <name>?<argumentlist>{ return spawn(function*() <body>, this); }

Nerede spawn "Aşağıdaki algoritmaya bir çağrıdır":

function spawn(genF, self) {
    return new Promise(function(resolve, reject) {
        var gen = genF.call(self);
        function step(nextF) {
            var next;
            try {
                next = nextF();
            } catch(e) {
                // finished with failure, reject the promise
                reject(e);
                return;
            }
            if(next.done) {
                // finished with success, resolve the promise
                resolve(next.value);
                return;
            }
            // not finished, chain off the yielded promise and `step` again
            Promise.resolve(next.value).then(function(v) {
                step(function() { return gen.next(v); });
            }, function(e) {
                step(function() { return gen.throw(e); });
            });
        }
        step(function() { return gen.next(undefined); });
    });
}

"Kısa versiyon, zaman uyumsuz bir işlevin Promises'i veren bir oluşturucunun şekerini çözmesidir." Sana kafa karıştırıcı olabilir düşünüyorum async functionile async function*. İlki basitçe bir söz verir. İkincisi, vaatler veren bir jeneratör döndürür.
cdhowie

Bu cevap büyük ölçüde spesifikasyona bir göndermedir ve gözden geçirdikten sonra herhangi bir karışıklık olduğuna inanmıyorum. Doğru, eşzamansız işlevler vaatleri geri döndürür, ancak bunu yapmak için, vaatler veren üreticilerden şeker alırlar.
Jon Surrell

-1

Sadece çağırdığınızda işlevinizden önce await ekleyin:

var ret = await  getVal();
console.log(ret);

1
await yalnızca eşzamansız işlevde geçerlidir
Han Van Pham

-3

async sözünü geri getirmez, await anahtar sözcüğü sözün çözümlenmesini bekler. zaman uyumsuz gelişmiş bir jeneratör işlevidir ve await biraz verim gibi çalışır

Sanırım sözdizimi (% 100 emin değilim)

async function* getVal() {...}

ES2016 jeneratör fonksiyonları biraz böyle çalışır. Bu şekilde programladığınız sıkıcı işlere dayalı bir veritabanı işleyicisi yaptım

db.exec(function*(connection) {
  if (params.passwd1 === '') {
    let sql = 'UPDATE People SET UserName = @username WHERE ClinicianID = @clinicianid';
    let request = connection.request(sql);
    request.addParameter('username',db.TYPES.VarChar,params.username);
    request.addParameter('clinicianid',db.TYPES.Int,uid);
    yield connection.execSql();
  } else {
    if (!/^\S{4,}$/.test(params.passwd1)) {
      response.end(JSON.stringify(
        {status: false, passwd1: false,passwd2: true}
      ));
      return;
    }
    let request = connection.request('SetPassword');
    request.addParameter('userID',db.TYPES.Int,uid);
    request.addParameter('username',db.TYPES.NVarChar,params.username);
    request.addParameter('password',db.TYPES.VarChar,params.passwd1);
    yield connection.callProcedure();
  }
  response.end(JSON.stringify({status: true}));

}).catch(err => {
  logger('database',err.message);
  response.end(JSON.stringify({status: false,passwd1: false,passwd2: false}));
});

Nasıl normal senkron gibi programladığıma dikkat edin, özellikle de

yield connection.execSql ve yield connection.callProcedure

Db.exec işlevi oldukça tipik bir Promise tabanlı oluşturucudur

exec(generator) {
  var self = this;
  var it;
  return new Promise((accept,reject) => {
    var myConnection;
    var onResult = lastPromiseResult => {
      var obj = it.next(lastPromiseResult);
      if (!obj.done) {
        obj.value.then(onResult,reject);
      } else {
       if (myConnection) {
          myConnection.release();
        }
        accept(obj.value);
      }
    };
    self._connection().then(connection => {
      myConnection = connection;
      it = generator(connection); //This passes it into the generator
      onResult();  //starts the generator
    }).catch(error => {
      reject(error);
    });
  });
}

4
"zaman uyumsuz gelişmiş bir jeneratör işlevidir " - hayır, gerçekten değil.
Bergi

Yukarıda belirtildiği gibi - 'eşzamansız işlevler' gerçekten de bir Söz verir. En azından kavramsal olarak, 'eşzamansız' ifadesinin ana noktası, bu işlevin dönüş değerlerini bir sözde sarmalamaktır. Bir Promise döndüren düz eski bir işlevi bile 'bekleyebilirsiniz' ve hepsi çalışır, çünkü 'async function' === 'fonksiyonu Promise' döndürür.
2018

2
@bergi, aslında gelişmiş bir jeneratör işlevidir. her zaman bir vaat veya başka bir şey döndüren bir jeneratör işlevi.
Alexander Mills
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.