await hanya valid dalam fungsi async

130

Saya menulis kode ini di lib/helper.js

var myfunction = async function(x,y) {
   ....
   reutrn [variableA, variableB]
}
exports.myfunction = myfunction;

dan kemudian saya mencoba menggunakannya di file lain

 var helper = require('./helper.js');   
 var start = function(a,b){
     ....
     const result = await helper.myfunction('test','test');
 }
 exports.start = start;

Saya mendapat kesalahan

"await hanya valid dalam fungsi async"

Apa masalahnya?

j.doe
sumber
1
Nah, masalahnya adalah itu awaithanya bisa digunakan di dalam suatu asyncfungsi. Artinya, awaitmembuat fungsi menjadi asinkron, jadi harus dideklarasikan seperti itu.
Pointy
Apa kesalahan saat ini?
acdcjunior
masih sama, SyntaxError: await hanya valid dalam fungsi async
j.doe
Anda perlu membagikan lebih banyak konteks tentang kode Anda.
Ele

Jawaban:

160

Kesalahannya tidak mengacu pada, myfunctiontetapi pada start.

async function start() {
   ....

   const result = await helper.myfunction('test', 'test');
}

// My function
const myfunction = async function(x, y) {
  return [
    x,
    y,
  ];
}

// Start function
const start = async function(a, b) {
  const result = await myfunction('test', 'test');
  
  console.log(result);
}

// Call start
start();



Saya menggunakan kesempatan dari pertanyaan ini untuk memberitahu Anda tentang anti pola dikenal menggunakan awaityaitu: return await.


SALAH

async function myfunction() {
  console.log('Inside of myfunction');
}

// Here we wait for the myfunction to finish
// and then returns a promise that'll be waited for aswell
// It's useless to wait the myfunction to finish before to return
// we can simply returns a promise that will be resolved later

// useless async here
async function start() {
  // useless await here
  return await myfunction();
}

// Call start
(async() => {
  console.log('before start');

  await start();
  
  console.log('after start');
})();


BENAR

async function myfunction() {
  console.log('Inside of myfunction');
}

// Here we wait for the myfunction to finish
// and then returns a promise that'll be waited for aswell
// It's useless to wait the myfunction to finish before to return
// we can simply returns a promise that will be resolved later

// Also point that we don't use async keyword on the function because
// we can simply returns the promise returned by myfunction
function start() {
  return myfunction();
}

// Call start
(async() => {
  console.log('before start');

  await start();
  
  console.log('after start');
})();


Juga, ketahuilah bahwa ada kasus khusus di mana return awaitbenar dan penting: (menggunakan coba / tangkap)

Apakah ada masalah kinerja dengan `kembali menunggu`?

Grégory NEUT
sumber
Tapi ini tidak berhasil, saya memperbarui kode saya. Saya masih mendapatkan kesalahan yang sama
j.doe
@ j.doe Saya telah menambahkan potongan
Grégory NEUT
2
Terima kasih, saya menemukan masalah saya. Saya mencoba melakukannya di dalam callback adalah fungsi start (). Solusinya adalah: const start = async function (a, b) {task.get (options, async function (error, result1) {const result = await myfunction ('test', 'test');
j.doe
Mengingat Node adalah single threaded. Bukankah itu mengurangi permintaan per menit dan juga meningkatkan penundaan di antara permintaan pemenuhan.
Rishabh Dhiman
1
Perlu disebutkan bahwa dalam contoh "BENAR", tidak perlu mendeklarasikan startsebagai asyncfungsi (meskipun beberapa akan memilih untuk melakukannya, agar lebih eksplisit)
Gershom
11

Ketika saya mendapatkan kesalahan ini, ternyata saya memiliki panggilan ke fungsi peta di dalam fungsi "async" saya, jadi pesan kesalahan ini sebenarnya merujuk ke fungsi peta yang tidak ditandai sebagai "asinkron". Saya mengatasi masalah ini dengan mengambil panggilan "menunggu" dari fungsi peta dan menemukan cara lain untuk mendapatkan perilaku yang diharapkan.

var myfunction = async function(x,y) {
    ....
    someArray.map(someVariable => { // <- This was the function giving the error
        return await someFunction(someVariable);
    });
}
John Langford
sumber
2
Ini adalah masalah bagi saya. Saya mengganti fungsi peta dengan for loop, yang merupakan solusi mudah bagi saya. Namun, solusi ini mungkin tidak berfungsi untuk Anda tergantung pada kode Anda.
Thomas
6
FYI, Anda juga dapat melakukannyasomeArray.map(async (someVariable) => { return await someFunction(someVariable)})
ptim
1
Dalam awaitkode Anda menyesatkan, karena Array.maptidak akan menangani fungsi sebagai fungsi asinkron. Untuk lebih jelasnya, setelah mapfungsi selesai, someFunctionsemua akan tertunda. Jika Anda ingin benar-benar menunggu fungsinya selesai Anda harus menulis: await Promise.all(someArray.map(someVariable => someFunction(someVariable)))atau await Promise.all(someArray.map(someFunction))).
Grégory NEUT
9

Untuk menggunakannya await, konteks pelaksanaannya harus bersifat asyncalami

Seperti yang dikatakan, Anda perlu menentukan sifat di executing contextmana Anda bersedia awaitmelakukan tugas sebelum apa pun.

Letakkan saja asyncsebelum fndeklarasi di mana asynctugas Anda akan dieksekusi.

var start = async function(a, b) { 
  // Your async task will execute with await
  await foo()
  console.log('I will execute after foo get either resolved/rejected')
}

Penjelasan:

Dalam pertanyaan Anda, Anda mengimpor a methodyang ada asynchronousdi alam dan akan dieksekusi secara paralel. Tetapi di mana Anda mencoba untuk mengeksekusi asyncmetode itu di dalam yang berbeda execution contextyang perlu Anda tentukan asyncuntuk digunakan await.

 var helper = require('./helper.js');   
 var start = async function(a,b){
     ....
     const result = await helper.myfunction('test','test');
 }
 exports.start = start;

Ingin tahu apa yang terjadi di balik terpal

await menggunakan metode / fungsi yang menjanjikan / masa depan / pengembalian tugas dan async menandai metode / fungsi yang mampu menggunakan await.

Juga jika Anda terbiasa promises, awaitsebenarnya melakukan proses janji / ketetapan hati yang sama. Membuat rantai janji dan menjalankan tugas Anda berikutnya diresolve callback untuk Anda.

Untuk info lebih lanjut, Anda dapat merujuk ke MDN DOCS .

Satyam Pathak
sumber
Bahkan dengan async di fungsi start saya mendapatkan kesalahan
j.doe
Saya tidak yakin di mana Anda hilang dan mendapatkan kesalahan ini, tidak ada penjelasan yang rumit untuk mengatasi kesalahan ini.
Satyam Pathak
ini adalah jawaban yang tepat dan benar-benar menjelaskan alasan yang digarisbawahi. up memilih.
linehrr
3

Implementasi saat ini dari async/ awaithanya mendukung awaitkata kunci di dalam asyncfungsi Ubah starttanda tangan fungsi Anda sehingga Anda dapat menggunakan awaitdi dalamnya start.

 var start = async function(a, b) {

 }

Bagi yang berminat, proposal untuk level teratas awaitsaat ini berada di Tahap 2: https://github.com/tc39/proposal-top-level-await

pengguna835611
sumber
1
Sayangnya, pada dasarnya ini berarti bahwa Anda harus membuat SEMUA fungsi Anda asinkron, di seluruh basis kode Anda. Karena jika Anda ingin menggunakan await, Anda harus melakukannya dalam fungsi async, yang berarti Anda harus menunggu respons dari fungsi tersebut dalam fungsi yang memanggilnya - sekali lagi, ini berarti SEMUA fungsi Anda harus menjadi async. Bagi saya ini berarti async await belum siap digunakan. Jika Anda bisa menggunakan await untuk memanggil metode async, terlepas dari apakah fungsi saat ini sinkron atau asinkron, maka itu akan siap untuk prime time.
Rodney P. Barbati
1
Setiap fungsi yang melalui tingkat tipuan tergantung pada hasil dari proses keharusan eksternal, dan seharusnya untuk didefinisikan dengan async- itulah seluruh titik dari async.
Gershom
Anda saat ini dapat menggunakannya di repl menggunakan --experimental-repl-awaitopsi.
lodz
3

Saya memiliki masalah yang sama dan blok kode berikut memberikan pesan kesalahan yang sama:

repositories.forEach( repo => {
        const commits = await getCommits(repo);
        displayCommit(commits);
});

Masalahnya adalah bahwa metode getCommits () adalah async tetapi saya meneruskannya ke repo argumen yang juga dihasilkan oleh Promise. Jadi, saya harus menambahkan kata async ke dalamnya seperti ini: async (repo) dan itu mulai berfungsi:

repositories.forEach( async(repo) => {
        const commits = await getCommits(repo);
        displayCommit(commits);
});
Emil
sumber
0

async / await adalah mekanisme penanganan promise, dua cara kita dapat melakukannya

functionWhichReturnsPromise()
            .then(result => {
                console.log(result);
            })
            .cathc(err => {
                console.log(result);

            });

atau kita dapat menggunakan menunggu untuk menunggu janji untuk mengajukannya secara penuh terlebih dahulu, yang berarti ditolak atau diselesaikan.

Sekarang jika kita ingin menggunakan await (menunggu janji untuk dipenuhi) di dalam suatu fungsi, fungsi container harus berupa fungsi async karena kita menunggu janji untuk dipenuhi secara asinkron || masuk akal kan ?.

async function getRecipesAw(){
            const IDs = await getIds; // returns promise
            const recipe = await getRecipe(IDs[2]); // returns promise
            return recipe; // returning a promise
        }

        getRecipesAw().then(result=>{
            console.log(result);
        }).catch(error=>{
            console.log(error);
        });
Tuan
sumber
-2

"await hanya valid dalam fungsi async"

Tapi kenapa? 'await' secara eksplisit mengubah panggilan async menjadi panggilan sinkron, dan oleh karena itu pemanggil tidak dapat asinkron (atau asinkron) - setidaknya, bukan karena panggilan dilakukan di 'await'.

mn_test347
sumber
1
Sebenarnya, menunggu tidak menunggu hasil - itu segera mengembalikan janji. Inilah yang sebenarnya ingin saya sampaikan. Jika await benar-benar menunggu dan tidak mengembalikan kontrol ke pemanggil, maka fungsi apa pun yang berisi kata kunci await secara harfiah tidak akan dapat ditandai sebagai async. Tetapi alih-alih itu, kita memiliki fungsi yang berisi await atau panggilan fungsi yang pada akhirnya memanggil fungsi yang berisi await harus async. Pada dasarnya, jika Anda memanggil await bahkan satu kali - semua fungsi Anda harus ditandai sebagai async.
Rodney P. Barbati
-5

Ya, await / async adalah konsep yang bagus, tetapi implementasinya benar-benar rusak.

Untuk alasan apa pun, kata kunci await telah diterapkan sedemikian rupa sehingga hanya dapat digunakan dalam metode async. Ini sebenarnya bug, meskipun Anda tidak akan melihatnya disebut seperti itu di mana pun kecuali di sini. Perbaikan untuk bug ini adalah dengan mengimplementasikan kata kunci await sedemikian rupa sehingga hanya dapat digunakan UNTUK MEMANGGIL fungsi asinkron, terlepas dari apakah fungsi pemanggil itu sendiri sinkron atau asinkron.

Karena bug ini, jika Anda menggunakan await untuk memanggil fungsi asynchronous nyata di suatu tempat dalam kode Anda, maka SEMUA fungsi Anda harus ditandai sebagai async dan SEMUA panggilan fungsi Anda harus menggunakan await.

Ini pada dasarnya berarti bahwa Anda harus menambahkan overhead promise ke semua fungsi di seluruh aplikasi Anda, yang sebagian besar tidak dan tidak akan pernah asinkron.

Jika Anda benar-benar memikirkannya, menggunakan await dalam suatu fungsi harus memerlukan fungsi yang berisi kata kunci await TO NOT BE ASYNC - ini karena kata kunci await akan menghentikan pemrosesan dalam fungsi di mana kata kunci await ditemukan. Jika pemrosesan dalam fungsi itu dihentikan sementara, maka sudah pasti BUKAN asinkron.

Jadi, bagi para pengembang javascript dan ECMAScript - perbaiki implementasi await / async sebagai berikut ...

  • await hanya dapat digunakan untuk memanggil fungsi asinkron.
  • await dapat muncul dalam berbagai jenis fungsi, sinkron atau asinkron.
  • Ubah pesan error dari "await is only valid in async function" menjadi "await hanya dapat digunakan untuk memanggil fungsi async".
Rodney P. Barbati
sumber
Anda bisa menyebutnya bug jika Anda suka, tapi saya tidak setuju. Tidak ada yang namanya kode yang "berhenti" - sebaliknya, ada kode yang tidak dapat diselesaikan tanpa hasil dari beberapa proses eksternal (biasanya io). Kode semacam itu harus disebut "asynchronous" karena banyak proses eksternal harus dapat berjalan pada waktu yang sama (tidak sinkron), berbeda dengan VM javascript yang berulir tunggal. Jika Anda memiliki banyak fungsi yang perlu difaktorkan ulang asyncsehingga mencerminkan fakta bahwa banyak fungsi Anda memerlukan hasil dari proses eksternal. Itu sepenuhnya kanonik menurut saya.
Gershom
Perlu juga disebutkan kekurangan yang mengerikan dari pembatasan awaithanya dapat digunakan dengan pemanggilan fungsi: untuk satu proses eksternal, hanya satu titik dalam kode javascript yang dapat diberitahukan ketika proses tersebut selesai. Misalnya, jika konten file diperlukan untuk 3 tujuan independen, masing-masing tujuan perlu dilakukan secara independen let content = await readTheFile();- ini karena "janji konten file" tidak dapat ditunggu, hanya "tindakan membaca file dan melanjutkan setelah file tersebut selesai. Baca".
Gershom
Ok, jangan sebut itu kode yang berhenti, atau kode yang tidak bisa diselesaikan, tapi bagaimana dengan menunggu yang diblokir. Begini intinya - fungsi yang diblokir menunggu atau yang tidak bisa diselesaikan adalah fungsi yang berisi kata kunci await. Ini bukanlah fungsi async yang dipanggil dengan kata kunci await. Oleh karena itu, fungsi yang berisi kata kunci await seharusnya TIDAK harus ditandai sebagai async - fungsi tersebut diblokir menunggu, yang merupakan kebalikan dari asynchronous.
Rodney P. Barbati
Untuk memperjelas hal ini, pertimbangkan hal berikut - await dimaksudkan untuk menyederhanakan penggunaan fungsi asinkron dengan membuatnya tampak sinkron (yaitu memungkinkan saya melakukan berbagai hal dalam urutan tertentu). Memaksa fungsi yang berisi await untuk menjadi async adalah keliru total - Anda menggunakan await sehingga menjadi sinkron. Sebuah fungsi yang mengandung await benar-benar, dengan segala cara yang dapat dibayangkan, BUKAN fungsi async !!!
Rodney P. Barbati
1
@ Gershom - kedengarannya masuk akal. Terima kasih!
Rodney P. Barbati