await ใช้ได้ในฟังก์ชัน async เท่านั้น


131

ฉันเขียนรหัสนี้ใน lib/helper.js

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

จากนั้นฉันก็ลองใช้มันในไฟล์อื่น

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

ฉันได้รับข้อผิดพลาด

"await ใช้ได้เฉพาะในฟังก์ชัน async"

ปัญหาคืออะไร?


1
ปัญหาคือawaitสามารถใช้ได้ภายในasyncฟังก์ชันเท่านั้น นั่นคือawaitทำให้ฟังก์ชันเป็นแบบอะซิงโครนัสดังนั้นจึงต้องมีการประกาศเช่นนี้
Pointy

ข้อผิดพลาดปัจจุบันคืออะไร?
acdcjunior

ยังคงเหมือนเดิม SyntaxError: await ใช้ได้เฉพาะในฟังก์ชัน async
j.doe

คุณต้องแชร์บริบทเพิ่มเติมเกี่ยวกับโค้ดของคุณ
Ele

คำตอบ:


162

ข้อผิดพลาดที่ไม่ได้หมายถึงแต่myfunctionstart

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();



ฉันจะใช้โอกาสของคำถามนี้จะให้คำแนะนำคุณเกี่ยวกับรูปแบบการป้องกันที่รู้จักกันโดยใช้ซึ่งเป็น:awaitreturn await


ไม่ถูกต้อง

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');
})();


แก้ไข

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');
})();


นอกจากนี้โปรดทราบว่ามีกรณีพิเศษที่return awaitถูกต้องและสำคัญ: (ใช้ลอง / จับ)

มีข้อกังวลด้านประสิทธิภาพของ "return await" หรือไม่


แต่ไม่ได้ผลฉันอัปเดตรหัสของฉัน ฉันยังคงได้รับข้อผิดพลาดเดิม
j.doe

@ j.doe ฉันได้เพิ่มตัวอย่าง
Grégory NEUT

2
ขอบคุณฉันพบปัญหาของฉัน ฉันพยายามทำภายใน callback คือฟังก์ชัน start () วิธีแก้ปัญหาคือ: const start = async function (a, b) {task.get (options, async function (error, result1) {const result = await myfunction ('test', 'test');
j.doe

พิจารณาว่า Node เป็นเธรดเดียว จะไม่ลดคำขอต่อนาทีและยังเพิ่มความล่าช้าระหว่างคำขอเติมเต็ม
Rishabh Dhiman

1
เป็นที่น่าสังเกตว่าในตัวอย่าง "CORRECT" ไม่จำเป็นต้องประกาศstartเป็นasyncฟังก์ชัน (แม้ว่าบางคนจะเลือกทำเช่นนั้นก็ตามเพื่อให้ชัดเจนยิ่งขึ้น)
Gershom

11

เมื่อฉันได้รับข้อผิดพลาดนี้ปรากฎว่าฉันมีการเรียกใช้ฟังก์ชันแผนที่ภายในฟังก์ชัน "async" ของฉันดังนั้นข้อความแสดงข้อผิดพลาดนี้หมายถึงฟังก์ชันแผนที่ไม่ได้ถูกทำเครื่องหมายเป็น "async" ฉันแก้ไขปัญหานี้ได้โดยการเรียก "รอ" ออกจากฟังก์ชันแผนที่แล้วหาวิธีอื่น ๆ ในการทำให้เกิดพฤติกรรมที่คาดหวัง

var myfunction = async function(x,y) {
    ....
    someArray.map(someVariable => { // <- This was the function giving the error
        return await someFunction(someVariable);
    });
}

2
นี่คือปัญหาสำหรับฉัน ฉันแทนที่ฟังก์ชันแผนที่ด้วย for loop ซึ่งเป็นวิธีที่ง่ายสำหรับฉัน อย่างไรก็ตามวิธีนี้อาจไม่ได้ผลสำหรับคุณทั้งนี้ขึ้นอยู่กับรหัสของคุณ
โทมัส

6
FYI คุณสามารถทำได้ด้วยsomeArray.map(async (someVariable) => { return await someFunction(someVariable)})
ptim

1
awaitในรหัสของคุณเป็นความเข้าใจผิดเพราะArray.mapจะได้จัดการกับฟังก์ชั่นในฐานะที่เป็นฟังก์ชั่นไม่ตรงกัน เพื่อความชัดเจนอย่างสมบูรณ์แบบหลังจากmapฟังก์ชั่นเสร็จสิ้นsomeFunctionจะรอดำเนินการทั้งหมด หากคุณต้องการรอให้ฟังก์ชันเสร็จสิ้นคุณต้องเขียน: await Promise.all(someArray.map(someVariable => someFunction(someVariable)))หรือawait Promise.all(someArray.map(someFunction))).
Grégory NEUT

9

ในการใช้งานawaitบริบทการดำเนินการต้องเป็นไปasyncตามธรรมชาติ

ตามที่กล่าวไว้คุณต้องกำหนดลักษณะของคุณexecuting contextว่าคุณเต็มใจที่จะawaitทำงานก่อนสิ่งใด

เพียงวางasyncก่อนการfnประกาศที่asyncงานของคุณจะดำเนินการ

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')
}

คำอธิบาย:

ในคำถามของคุณคุณกำลังนำเข้าสิ่งmethodที่มีอยู่asynchronousในธรรมชาติและจะดำเนินการควบคู่กันไป แต่ที่คุณกำลังพยายามที่จะดำเนินการว่าasyncวิธีการที่อยู่ภายในที่แตกต่างกันexecution contextซึ่งคุณจำเป็นต้องกำหนดที่จะใช้asyncawait

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

สงสัยว่ามีอะไรอยู่ใต้ฝากระโปรง

awaitใช้วิธีการ / ฟังก์ชันของสัญญา / อนาคต / การส่งคืนงานและasyncทำเครื่องหมายวิธีการ / ฟังก์ชันว่าสามารถใช้ await ได้

นอกจากนี้ถ้าคุณมีความคุ้นเคยกับpromises, awaitเป็นจริงทำกระบวนการเดียวกันของสัญญา / แก้ไข สร้างห่วงโซ่แห่งคำสัญญาและดำเนินงานต่อไปในการresolveติดต่อกลับ

สำหรับข้อมูลเพิ่มเติมคุณสามารถดูMDN DOCS


แม้จะมี async ในฟังก์ชัน start ฉันก็ยังได้รับข้อผิดพลาด
j.doe

ฉันไม่แน่ใจว่าคุณหายไปไหนและได้รับข้อผิดพลาดนี้ไม่มีคำอธิบายที่ซับซ้อนเพื่อแก้ไขข้อผิดพลาดนี้
Satyam Pathak

นี่เป็นคำตอบที่เหมาะสมและอธิบายเหตุผลที่ขีดเส้นใต้ได้จริง โหวตขึ้น
linehrr

3

การใช้งานปัจจุบันของasync/ awaitสนับสนุนเฉพาะawaitคำสำคัญภายในasyncฟังก์ชันเปลี่ยนstartลายเซ็นฟังก์ชันของคุณเพื่อให้คุณสามารถใช้awaitภายในstartได้

 var start = async function(a, b) {

 }

สำหรับผู้ที่สนใจข้อเสนอสำหรับระดับบนสุดawaitอยู่ในขั้นตอนที่ 2: https://github.com/tc39/proposal-top-level-await


1
น่าเสียดายที่สิ่งนี้หมายความโดยทั่วไปคือคุณจะต้องทำให้ฟังก์ชันทั้งหมดของคุณเป็นแบบ async ในฐานรหัสทั้งหมดของคุณ เพราะถ้าคุณต้องการใช้ await คุณต้องทำในฟังก์ชัน async ซึ่งหมายความว่าคุณต้องรอการตอบสนองของฟังก์ชันนั้นในฟังก์ชันที่เรียกมันอีกครั้งนั่นหมายความว่าฟังก์ชันทั้งหมดของคุณจะต้องกลายเป็น async สำหรับฉันนี่หมายความว่า await async ไม่พร้อมใช้งาน เมื่อคุณสามารถใช้ await เพื่อเรียกเมธอด async ได้ไม่ว่าฟังก์ชันปัจจุบันจะซิงโครนัสหรืออะซิงโครนัสฟังก์ชันนั้นจะพร้อมสำหรับไพรม์ไทม์
Rodney P. Barbati

1
ทุกฟังก์ชั่นที่จะผ่านระดับของความร้ายใด ๆ ขึ้นอยู่กับผลของการเป็นขั้นตอนที่ต้องภายนอกและควรจะถูกกำหนดด้วยasync- ที่จุดทั้งหมดasyncของ
Gershom

ขณะนี้คุณสามารถใช้ใน node repl โดยใช้--experimental-repl-awaitตัวเลือก
lodz

3

ฉันมีปัญหาเดียวกันและบล็อกรหัสต่อไปนี้ให้ข้อความแสดงข้อผิดพลาดเดียวกัน:

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

ปัญหาคือเมธอด getCommits () เป็นแบบ async แต่ฉันส่งผ่านอาร์กิวเมนต์ repo ซึ่งสร้างโดย Promise ด้วย ดังนั้นฉันต้องเพิ่มคำว่า async ลงไปดังนี้: async (repo) และมันก็เริ่มทำงาน:

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

0

async / await เป็นกลไกของการจัดการคำสัญญาซึ่งมีสองวิธีที่เราสามารถทำได้

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

            });

หรือเราสามารถใช้คำว่า waiting เพื่อรอให้คำสัญญานั้นเต็มฟ้องก่อนซึ่งหมายความว่าจะถูกปฏิเสธหรือได้รับการแก้ไข

ตอนนี้ถ้าเราต้องการใช้await (รอคำสัญญาที่จะตอบสนอง) ภายในฟังก์ชันจำเป็นที่ฟังก์ชัน container จะต้องเป็นฟังก์ชัน async เนื่องจากเรากำลังรอคำสัญญาที่จะทำให้เป็นจริงแบบอะซิงโครนัส || เข้าท่าใช่มั้ย..

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);
        });

-2

"await ใช้ได้เฉพาะในฟังก์ชัน async"

แต่ทำไม? 'await' จะเปลี่ยนการโทรแบบ async เป็นการโทรแบบซิงโครนัสอย่างชัดเจนดังนั้นผู้โทรจึงไม่สามารถ async (หรือ asyncable ได้) - อย่างน้อยก็ไม่ใช่เพราะการโทรที่ 'await'


1
อันที่จริงการรอคอยไม่ได้รอผลลัพธ์ - มันกลับคำสัญญาทันที นี่คือสิ่งที่ฉันพยายามจะสื่อ หากรอคอยจริงๆและไม่ส่งคืนการควบคุมไปยังผู้เรียกฟังก์ชันใด ๆ ที่มีคีย์เวิร์ดรอคอยจะไม่สามารถทำเครื่องหมายเป็น async ได้อย่างแท้จริง แต่แทนที่จะเป็นเช่นนั้นเรามีฟังก์ชันใด ๆ ที่มีการรอหรือเรียกใช้ฟังก์ชันที่ในที่สุดการเรียกฟังก์ชันที่มีการรอคอยจะต้องไม่ตรงกัน โดยทั่วไปหากคุณโทรรอแม้แต่ครั้งเดียวฟังก์ชันทั้งหมดของคุณจะต้องถูกทำเครื่องหมายว่าไม่ตรงกัน
Rodney P. Barbati

-5

ใช่ await / async เป็นแนวคิดที่ยอดเยี่ยม แต่การนำไปใช้งานนั้นไม่สมบูรณ์

ไม่ว่าด้วยเหตุผลใดก็ตามคำหลัก await จึงถูกนำมาใช้เพื่อให้สามารถใช้ได้เฉพาะในวิธีการ async เท่านั้น นี่เป็นข้อผิดพลาดจริงๆแม้ว่าคุณจะไม่เห็นมันอ้างถึงในที่ใดก็ตาม แต่ที่นี่ การแก้ไขข้อบกพร่องนี้คือการใช้คีย์เวิร์ด await เพื่อให้สามารถใช้เพื่อเรียกฟังก์ชัน async เท่านั้นไม่ว่าฟังก์ชันการโทรจะเป็นแบบซิงโครนัสหรืออะซิงโครนัส

เนื่องจากข้อผิดพลาดนี้หากคุณใช้การรอเพื่อเรียกใช้ฟังก์ชันอะซิงโครนัสจริงที่ใดที่หนึ่งในโค้ดของคุณฟังก์ชันทั้งหมดของคุณจะต้องถูกทำเครื่องหมายเป็น async และการเรียกฟังก์ชันทั้งหมดของคุณจะต้องรอ

ซึ่งโดยพื้นฐานแล้วหมายความว่าคุณต้องเพิ่มค่าใช้จ่ายของสัญญาให้กับฟังก์ชันทั้งหมดในแอปพลิเคชันทั้งหมดของคุณซึ่งส่วนใหญ่ไม่ใช่และจะไม่เป็นแบบอะซิงโครนัส

หากคุณคิดเกี่ยวกับเรื่องนี้การใช้ await ในฟังก์ชันควรต้องการฟังก์ชันที่มีคีย์เวิร์ด await TO NOT BE ASYNC เนื่องจากคีย์เวิร์ด await กำลังจะหยุดการประมวลผลชั่วคราวในฟังก์ชันที่พบคีย์เวิร์ด await หากการประมวลผลในฟังก์ชั่นนั้นหยุดชั่วคราวแสดงว่าไม่ตรงกันอย่างแน่นอน

ดังนั้นสำหรับผู้พัฒนาจาวาสคริปต์และ ECMAScript โปรดแก้ไขการใช้งาน await / async ดังนี้ ...

  • await สามารถใช้ได้กับฟังก์ชัน CALL async เท่านั้น
  • await สามารถปรากฏในฟังก์ชันประเภทใดก็ได้ซิงโครนัสหรืออะซิงโครนัส
  • เปลี่ยนข้อความแสดงข้อผิดพลาดจาก "await ใช้ได้เฉพาะในฟังก์ชัน async" เป็น "await ใช้ได้เฉพาะในการเรียกฟังก์ชัน async"

คุณสามารถเรียกมันว่าจุดบกพร่องถ้าคุณต้องการ แต่ฉันไม่เห็นด้วย ไม่มีสิ่งที่เรียกว่ารหัสที่ "หยุดชั่วคราว" - แต่มีโค้ดที่ไม่สามารถดำเนินการให้เสร็จสมบูรณ์ได้หากไม่มีผลลัพธ์ของกระบวนการภายนอกบางอย่าง (โดยปกติคือ io) โค้ดดังกล่าวควรเรียกว่า "อะซิงโครนัส" เนื่องจากกระบวนการภายนอกจำนวนมากควรสามารถรันได้ในเวลาเดียวกัน (ไม่ใช่แบบซิงโครนัส) ตรงกันข้ามกับ javascript VM ซึ่งเป็นเธรดเดียว หากคุณมีฟังก์ชันมากมายที่ต้องปรับโครงสร้างใหม่เพื่อasyncสะท้อนให้เห็นว่าฟังก์ชันจำนวนมากของคุณต้องการผลลัพธ์ของกระบวนการภายนอก นั่นเป็นเรื่องที่ยอมรับได้อย่างสมบูรณ์ในความคิดของฉัน
Gershom

นอกจากนี้ยังควรค่าแก่การกล่าวถึงข้อเสียเปรียบอย่างมากในการ จำกัดawaitให้ใช้งานได้เฉพาะกับการเรียกใช้ฟังก์ชันเท่านั้น: สำหรับกระบวนการภายนอกเดียวสามารถแจ้งเตือนเพียงจุดเดียวในรหัสจาวาสคริปต์เมื่อกระบวนการนั้นเสร็จสิ้น ตัวอย่างเช่นหากต้องการเนื้อหาของไฟล์เพื่อวัตถุประสงค์อิสระ 3 อย่างแต่ละวัตถุประสงค์จะต้องทำอย่างอิสระlet content = await readTheFile();เนื่องจากไม่สามารถรอ "คำมั่นสัญญาเกี่ยวกับเนื้อหาของไฟล์" ได้มีเพียง "การอ่านไฟล์และดำเนินการต่อเมื่อได้รับ อ่าน".
Gershom

โอเคอย่าเรียกมันว่ารหัสที่หยุดชั่วคราวหรือรหัสที่ไม่สามารถดำเนินการให้เสร็จสมบูรณ์ได้ แต่วิธีการเกี่ยวกับการรอที่ถูกบล็อก นี่คือการถู - ฟังก์ชั่นที่ถูกบล็อกรอหรือไม่สามารถดำเนินการให้เสร็จสมบูรณ์ได้คือฟังก์ชันที่มีคีย์เวิร์ด await ไม่ใช่ฟังก์ชัน async ที่ถูกเรียกด้วยคีย์เวิร์ด await ดังนั้นฟังก์ชันที่มีคีย์เวิร์ด await ไม่ควรถูกทำเครื่องหมายเป็น async อย่างแน่นอน - มันถูกบล็อกการรอซึ่งตรงข้ามกับ asynchronous
Rodney P. Barbati

เพื่อให้สิ่งนี้ชัดเจนที่สุดให้พิจารณาสิ่งต่อไปนี้ - การรอคอยมีจุดมุ่งหมายเพื่อลดความซับซ้อนของการใช้ฟังก์ชันอะซิงโครนัสโดยการทำให้ดูเหมือนเป็นซิงโครนัส (กล่าวคือทำให้ฉันสามารถทำสิ่งต่างๆตามลำดับที่ระบุได้) การบังคับให้ฟังก์ชันที่มี await เป็น async เป็นการเรียกชื่อผิดโดยสมบูรณ์ - คุณใช้การรอเพื่อให้ฟังก์ชันนั้นกลายเป็นซิงโครนัส ฟังก์ชันที่มีการรอคอยนั้นเป็นไปได้ในทุก ๆ ลักษณะที่เป็นไปได้ไม่ใช่ฟังก์ชัน async !!!
Rodney P. Barbati

1
@Gershom - ฟังดูมีเหตุผล ขอบคุณ!
Rodney P. Barbati
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.