await chỉ hợp lệ trong chức năng không đồng bộ


129

Tôi đã viết mã này trong lib/helper.js

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

và sau đó tôi đã cố gắng sử dụng nó trong một tệp khác

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

Tôi có một lỗi

"await chỉ hợp lệ trong hàm không đồng bộ"

Vấn đề là gì?


1
Vấn đề là nó awaitchỉ có thể được sử dụng bên trong một asynchàm. Đó là, awaitlàm cho một hàm không đồng bộ, vì vậy nó phải được khai báo như vậy.
Pointy

Lỗi hiện tại là gì?
acdcjunior

vẫn như nhau, Lỗi Cú pháp: chờ đợi chỉ có giá trị trong chức năng async
j.doe

Bạn cần chia sẻ thêm ngữ cảnh về mã của mình.
Ele

Câu trả lời:


158

Lỗi không liên quan đến myfunctionmà là 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();



Tôi sử dụng cơ hội của câu hỏi này để tư vấn cho bạn về một chất chống mẫu nổi tiếng sử dụng awaitđó là: return await.


SAI LẦM

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


CHÍNH XÁC

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


Ngoài ra, hãy biết rằng có một trường hợp đặc biệt return awaitđúng và quan trọng: (sử dụng try / catch)

Có lo ngại về hiệu suất với `` sự trở lại đang chờ đợi '' không?


Nhưng điều này không hoạt động, tôi đã cập nhật mã của mình. Tôi vẫn gặp lỗi tương tự
j.doe 22/03/18

@ j.doe Tôi đã thêm một đoạn mã
Grégory NEUT

2
Cảm ơn, tôi đã tìm thấy vấn đề của mình. Tôi đã cố gắng thực hiện điều đó bên trong một hàm gọi lại là hàm start (). Giải pháp là: const start = async function (a, b) {task.get (options, async function (error, result1) {const result = await my Chức năng ('test', 'test');
j.doe

Coi Node là một luồng đơn. Nó không làm giảm yêu cầu mỗi phút và cũng làm tăng độ trễ giữa các yêu cầu điền đầy đủ.
Rishabh Dhiman

1
Điều đáng nói là trong ví dụ "ĐÚNG", không cần thiết phải khai báo startdưới dạng một asynchàm (mặc dù một số sẽ chọn làm như vậy, để rõ ràng hơn)
Gershom

11

Khi tôi gặp lỗi này, hóa ra là tôi đã gọi hàm bản đồ bên trong hàm "không đồng bộ" của mình, vì vậy thông báo lỗi này thực sự đề cập đến việc hàm bản đồ không được đánh dấu là "không đồng bộ". Tôi đã giải quyết vấn đề này bằng cách loại bỏ lệnh gọi "await" ra khỏi chức năng bản đồ và tìm ra một số cách khác để nhận được hành vi mong đợi.

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

2
Đây là vấn đề đối với tôi. Tôi đã thay thế hàm bản đồ bằng một vòng lặp for, đó là một giải pháp dễ dàng cho tôi. Tuy nhiên, giải pháp này có thể không hiệu quả với bạn tùy thuộc vào mã của bạn.
Thomas

6
FYI bạn cũng có thể làmsomeArray.map(async (someVariable) => { return await someFunction(someVariable)})
ptim

1
awaittrong mã của bạn gây hiểu lầm, vì Array.mapsẽ không xử lý hàm như một hàm không đồng bộ. Để hoàn toàn rõ ràng, sau khi mapchức năng kết thúc, someFunctiontất cả sẽ đang chờ xử lý. Nếu bạn muốn thực sự đợi các hàm hoàn thành, bạn phải viết: await Promise.all(someArray.map(someVariable => someFunction(someVariable)))hoặc await Promise.all(someArray.map(someFunction))).
Grégory NEUT

9

Để sử dụng await, ngữ cảnh thực thi của nó cần phải asyncvề bản chất

Như đã nói, bạn cần xác định bản chất của bạn là executing contextnơi bạn sẵn sàng thực hiện awaitmột nhiệm vụ trước bất cứ việc gì.

Chỉ cần đặt asynctrước fnkhai báo mà asynctác vụ của bạn sẽ thực thi.

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

Giải trình:

Trong câu hỏi của bạn, bạn sẽ nhập một methodmà là asynchronoustrong tự nhiên và sẽ thực hiện song song. Nhưng nơi bạn đang cố gắng thực thi asyncphương thức đó nằm bên trong một phương thức khác execution contextmà bạn cần xác định asyncđể sử dụng await.

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

Tự hỏi điều gì đang diễn ra dưới mui xe

awaitsử dụng các phương thức / chức năng trả về hứa hẹn / tương lai / nhiệm vụ và asyncđánh dấu một phương thức / chức năng có khả năng sử dụng await.

Ngoài ra, nếu bạn quen thuộc promises,await thực sự đang thực hiện cùng một quy trình hứa hẹn / giải quyết. Tạo một chuỗi lời hứa và thực hiện nhiệm vụ tiếp theo của bạn trong resolvecuộc gọi lại.

Để biết thêm thông tin, bạn có thể tham khảo MDN DOCS .


Ngay cả với async trong hàm start Tôi nhận lỗi
j.doe

Tôi không chắc bạn đang thiếu ở đâu và gặp lỗi này, không có lời giải thích phức tạp như vậy để giải quyết lỗi này.
Satyam Pathak

đây là một câu trả lời thích hợp và thực sự giải thích lý do gạch chân. lên bình chọn.
linehrr

3

Việc triển khai hiện tại async/ awaitchỉ hỗ trợ awaittừ khóa bên trong các asynchàm Thay đổi startchữ ký hàm của bạn để bạn có thể sử dụng awaitbên trong start.

 var start = async function(a, b) {

 }

Đối với những người quan tâm, đề xuất cho cấp cao nhất awaithiện đang ở Giai đoạn 2: https://github.com/tc39/proposal-top-level-await


1
Thật không may, điều này về cơ bản có nghĩa là bạn sẽ phải làm cho TẤT CẢ các chức năng của bạn không đồng bộ, trên toàn bộ cơ sở mã của bạn. Bởi vì nếu bạn muốn sử dụng await, bạn phải thực hiện nó trong một hàm không đồng bộ, có nghĩa là bạn phải chờ phản hồi của hàm đó trong hàm gọi nó - một lần nữa, điều đó có nghĩa là TẤT CẢ các hàm của bạn sẽ cần trở thành không đồng bộ. Đối với tôi, điều này có nghĩa là async chờ đợi chưa sẵn sàng để sử dụng. Khi bạn có thể sử dụng await để gọi một phương thức không đồng bộ, bất kể hàm hiện tại là đồng bộ hay không đồng bộ, thì nó sẽ sẵn sàng cho thời gian chính.
Rodney P. Barbati

1
Mọi chức năng thông qua bất kỳ mức độ điều hướng nào phụ thuộc vào kết quả của một quá trình bên ngoài đều phải, và phải được định nghĩa async- đó là toàn bộ điểm của async.
Gershom

Bạn hiện có thể sử dụng nó trong --experimental-repl-awaittùy chọn sử dụng nút repl .
lodz

3

Tôi đã gặp sự cố tương tự và khối mã sau đưa ra cùng một thông báo lỗi:

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

Vấn đề là phương thức getCommits () không đồng bộ nhưng tôi đã chuyển cho nó repo đối số cũng được tạo ra bởi Promise. Vì vậy, tôi phải thêm từ không đồng bộ vào nó như thế này: async (repo) và nó bắt đầu hoạt động:

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

0

async / await là cơ chế xử lý lời hứa, có hai cách chúng ta có thể thực hiện

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

            });

hoặc chúng ta có thể sử dụng await để đợi lời hứa nộp đầy đủ trước, có nghĩa là nó bị từ chối hoặc được giải quyết.

Bây giờ nếu chúng ta muốn sử dụng await (chờ một lời hứa thực hiện) bên trong một hàm, thì bắt buộc hàm chứa phải là một hàm không đồng bộ vì chúng ta đang chờ một lời hứa để hoàn thành một cách không đồng bộ || có lý phải không ?.

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 chỉ hợp lệ trong hàm không đồng bộ"

Nhưng tại sao? 'await' biến một cách rõ ràng một cuộc gọi không đồng bộ thành một cuộc gọi đồng bộ và do đó người gọi không thể không đồng bộ (hoặc không thể chuyển đổi) - ít nhất, không phải vì cuộc gọi được thực hiện vào lúc 'await'.


1
Trên thực tế, await không chờ đợi kết quả - nó ngay lập tức trả về một lời hứa. Đây chính xác là những gì tôi đã cố gắng truyền đạt. Nếu await thực sự đã đợi và không trả lại quyền điều khiển cho người gọi, thì bất kỳ hàm nào có chứa từ khóa await sẽ không thể được đánh dấu là không đồng bộ theo nghĩa đen. Nhưng thay vào đó, chúng ta có bất kỳ hàm nào chứa await hoặc gọi một hàm mà cuối cùng gọi một hàm chứa await phải là không đồng bộ. Về cơ bản, nếu bạn gọi await dù chỉ một lần - tất cả các chức năng của bạn phải được đánh dấu là không đồng bộ.
Rodney P. Barbati

-5

Vâng, await / async là một khái niệm tuyệt vời, nhưng việc triển khai hoàn toàn bị hỏng.

Vì bất kỳ lý do gì, từ khóa await đã được triển khai để nó chỉ có thể được sử dụng trong một phương thức không đồng bộ. Đây thực tế là một lỗi, mặc dù bạn sẽ không thấy nó được gọi như vậy ở bất kỳ đâu nhưng ngay tại đây. Bản sửa lỗi cho lỗi này sẽ là triển khai từ khóa await sao cho nó chỉ có thể được sử dụng ĐỂ GỌI hàm không đồng bộ, bất kể hàm gọi là đồng bộ hay không đồng bộ.

Do lỗi này, nếu bạn sử dụng await để gọi một hàm không đồng bộ thực ở đâu đó trong mã của mình, thì TẤT CẢ các hàm của bạn phải được đánh dấu là không đồng bộ và TẤT CẢ các lệnh gọi hàm của bạn phải sử dụng await.

Điều này về cơ bản có nghĩa là bạn phải thêm chi phí của các lời hứa vào tất cả các chức năng trong toàn bộ ứng dụng của bạn, hầu hết các chức năng này không và sẽ không bao giờ là không đồng bộ.

Nếu bạn thực sự nghĩ về nó, việc sử dụng await trong một hàm nên yêu cầu hàm chứa từ khóa await ĐỂ KHÔNG ĐƯỢC ASYNC - điều này là do từ khóa await sẽ tạm dừng xử lý trong hàm nơi tìm thấy từ khóa await. Nếu quá trình xử lý trong hàm đó bị tạm dừng, thì chắc chắn nó KHÔNG đồng bộ.

Vì vậy, gửi tới các nhà phát triển javascript và ECMAScript - vui lòng sửa lỗi triển khai await / async như sau ...

  • await chỉ có thể được sử dụng để GỌI các hàm không đồng bộ.
  • await có thể xuất hiện trong bất kỳ loại chức năng nào, đồng bộ hoặc không đồng bộ.
  • Thay đổi thông báo lỗi từ "await chỉ hợp lệ trong hàm không đồng bộ" thành "await chỉ có thể được sử dụng để gọi các hàm không đồng bộ".

Bạn có thể gọi nó là lỗi nếu bạn thích, nhưng tôi không đồng ý. Không có cái gọi là mã "tạm dừng" - đúng hơn, có mã không thể hoàn thành nếu không có kết quả của một số quá trình bên ngoài (thường là io). Mã như vậy nên được gọi là "không đồng bộ" vì nhiều quy trình bên ngoài có thể chạy cùng một lúc (không đồng bộ), trái ngược với máy ảo javascript là một luồng. Nếu bạn có nhiều chức năng cần được cấu trúc lại để asyncphản ánh thực tế là nhiều chức năng của bạn yêu cầu kết quả của các quy trình bên ngoài. Đó là hoàn toàn kinh điển theo quan điểm của tôi.
Gershom

Cũng cần đề cập đến một nhược điểm khủng khiếp của việc hạn chế awaitchỉ sử dụng được với các lệnh gọi hàm: đối với một quy trình bên ngoài, chỉ một điểm trong mã javascript có thể được thông báo khi quy trình đó hoàn tất. Ví dụ: nếu nội dung của tệp là cần thiết cho 3 mục đích độc lập, mỗi mục đích sẽ cần thực hiện độc lập let content = await readTheFile();- điều này là do không thể chờ "lời hứa về nội dung của tệp", chỉ "hành động đọc tệp và tiếp tục khi nó đã được đọc".
Gershom

Ok, chúng ta đừng gọi nó là mã tạm dừng, hay mã không thể hoàn thành, nhưng còn về việc chờ bị chặn thì sao. Đây là phần chà - chức năng bị chặn chờ hoặc không thể hoàn thành là chức năng có chứa từ khóa await. Nó không phải là hàm async đang được gọi với từ khóa await. Do đó, hàm chứa từ khóa await chắc chắn KHÔNG phải được đánh dấu là không đồng bộ - nó bị chặn chờ đợi, điều này ngược lại với không đồng bộ.
Rodney P. Barbati

Để làm cho điều này hoàn toàn rõ ràng, hãy xem xét điều sau - await nhằm mục đích đơn giản hóa việc sử dụng các hàm không đồng bộ bằng cách làm cho chúng có vẻ đồng bộ (nghĩa là nó cho phép tôi làm mọi thứ theo một thứ tự cụ thể). Buộc hàm chứa await không đồng bộ là một cách hiểu sai hoàn toàn - bạn đã sử dụng await để nó trở nên đồng bộ. Một hàm chứa một await hoàn toàn, theo mọi cách có thể hình dung được, KHÔNG PHẢI là một hàm không đồng bộ !!!
Rodney P. Barbati

1
@Gershom - nghe có vẻ hợp lý. Cảm ơn!
Rodney P. Barbati
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.