Sử dụng await bên ngoài một chức năng không đồng bộ


85

Tôi đang cố gắng liên kết hai hàm không đồng bộ với nhau, vì hàm đầu tiên có tham số trả về có điều kiện khiến hàm thứ hai chạy hoặc thoát khỏi mô-đun. Tuy nhiên, tôi đã tìm thấy hành vi kỳ lạ mà tôi không thể tìm thấy trong thông số kỹ thuật.

async function isInLobby() {
    //promise.all([chained methods here])
    let exit = false;
    if (someCondition) exit = true;
}

Đây là một đoạn mã bị lỗi của tôi (bạn có thể xem toàn bộ phạm vi tại đây ), chỉ đơn giản là kiểm tra xem một người chơi đã ở trong sảnh hay chưa, nhưng điều đó không liên quan.

Tiếp theo chúng ta có chức năng không đồng bộ này.

async function countPlayer() {
    const keyLength = await scardAsync(game);
    return keyLength;
}

Hàm này không cần chạy nếu exit === true.

Tôi đã cố gắng làm

const inLobby = await isInLobby();

Điều này tôi hy vọng sẽ chờ đợi kết quả, vì vậy tôi có thể sử dụng inLobbyđể chạy có điều kiện countPlayer, tuy nhiên tôi đã nhận được lỗi gõ không có chi tiết cụ thể.

Tại sao bạn không thể awaitmột asyncchức năng bên ngoài phạm vi của chức năng? Tôi biết đó là một lời hứa đường nên phải xâu chuỗi thennó nhưng tại sao trong countPlayertôi có thể chờ đợi một lời hứa khác, còn bên ngoài thì tôi không thể await isInLobby?


Bạn có thể cho chúng tôi biết bạn đã làm ở đâuawait isInLobby()inLobbyđược sử dụng như thế nào không? Ngoài ra, ở đâu / như thế nào được countPlayergọi là?
Bergi

@Bergi Tôi đã liên kết repo của mình cho ngữ cảnh thực tế. Quá nhiều mã để đưa vào câu hỏi
Sterling Archer

Tôi không hiểu vấn đề là ở đâu (có thể bạn đã cập nhật repo)? Nếu bạn tham khảo isInLobby().then( … countPlayer().then …phần này, giải pháp là nhỏ: chỉ cần tạo hàm chứa các lệnh gọi đó ( (req, res) =>một) async.
Bergi

@Bergi vấn đề không phải là nó đã bị hỏng, nó hoạt động như vậy. Tôi chỉ không hiểu tại sao việc chờ đợi cấp cao nhất lại không thành vấn đề. Lần lượt ra nó chỉ không tồn chưa mà không cần xác định phạm vi toàn bộ mô-đun của bạn như là một chức năng async
Sterling Archer

Nhưng bạn thậm chí không cần cấp cao nhất await cho mã của mình? Đó là lý do tại sao tôi tự hỏi rằng bạn đã chấp nhận câu trả lời không thực sự liên quan đến vấn đề trong câu hỏi.
Bergi

Câu trả lời:


73

Cấp cao nhất awaitkhông được hỗ trợ. Có một vài cuộc thảo luận của ủy ban tiêu chuẩn về lý do tại sao lại như vậy, chẳng hạn như vấn đề Github này .

Cũng có một suy nghĩ trên Github về lý do tại sao cấp cao nhất đang chờ đợi là một ý tưởng tồi. Cụ thể, anh ấy gợi ý rằng nếu bạn có mã như thế này:

// data.js
const data = await fetch( '/data.json' );
export default data;

Bây giờ, bất kỳ tệp nào nhập data.jssẽ không thực thi cho đến khi quá trình tìm nạp hoàn tất, vì vậy tất cả quá trình tải mô-đun của bạn hiện đã bị chặn. Điều này khiến rất khó để suy luận về thứ tự mô-đun ứng dụng, vì chúng ta đã quen với việc Javascript cấp cao nhất thực thi đồng bộ và dễ đoán. Nếu điều này được cho phép, việc biết khi nào một hàm được xác định sẽ trở nên khó khăn.

Quan điểm của tôi là thực tiễn không tốt khi mô-đun của bạn có tác dụng phụ chỉ đơn giản là tải nó. Điều đó có nghĩa là bất kỳ người tiêu dùng nào sử dụng mô-đun của bạn sẽ nhận được tác dụng phụ chỉ đơn giản bằng cách yêu cầu mô-đun của bạn. Điều này rất hạn chế nơi có thể sử dụng mô-đun của bạn. Cấp cao nhất awaitcó thể có nghĩa là bạn đang đọc từ một số API hoặc gọi đến một số dịch vụ tại thời điểm tải. Thay vào đó, bạn chỉ nên xuất các chức năng không đồng bộ mà người tiêu dùng có thể sử dụng theo tốc độ của riêng họ.


Đó là một liên kết tốt, cảm ơn bạn. Thật tiếc là không có hỗ trợ cấp cao nhất. Tôi hy vọng nó là. Hiện tại, tôi phải lồng những lời hứa của mình ở đây và đó là một thực hành rất tệ và tôi không thích nó. :( Cảm ơn bạn.
Sterling Archer,

@SterlingArcher cách khác, sử dụng một IIFE async:void async function() { const inLobby = await isInLobby() }()
robertklep

@robertklep không phải là phạm vi inLobbycủa hàm khiến nó không thể truy cập được?
Sterling Archer,

@SterlingArcher vâng, nó sẽ yêu cầu bạn di chuyển tất cả mã của mình đến đó (về cơ bản làm cho nó trở thành "cấp cao nhất"). Nó chỉ là một giải pháp thay thế cho việc sử dụng .then()(xin lỗi, đáng lẽ phải làm rõ hơn một chút).
robertklep 24/09/2016

không đồng ý, người dùng data.js bị 'chặn' trong khi tải bản thân data.js và tất cả các phần phụ thuộc của nó, bản thân khái niệm 'chặn' này không xấu. cấp cao nhất đang chờ đợi có thể được coi là tải một số phụ thuộc mà dường như chúng cần phải có trước khi việc sử dụng được 'phát hành'.
Ibrahim ben Salah

125

Tất nhiên luôn có điều này:

(async () => {
    await ...

    // all of the script.... 

})();
// nothing else

Điều này làm cho một chức năng nhanh chóng với async nơi bạn có thể sử dụng đang chờ đợi. Nó giúp bạn không cần phải tạo một hàm không đồng bộ, điều này thật tuyệt! // tín dụng Silve2611


3
Vui lòng giải thích thêm và giải thích tại sao nó hoạt động.
Paul Back

12
rất ngu ngốc khi phản đối câu trả lời này. Nó tạo ra một chức năng nhanh chóng với async nơi bạn có thể sử dụng đang chờ đợi. Nó giúp bạn không cần phải tạo một hàm không đồng bộ, điều này thật tuyệt!
Silve2611

55
Không giải quyết được vấn đề vì bạn vẫn cần awaithàm ẩn danh này, một lần nữa, hàm này không hoạt động bên ngoài các hàm.
Michael

vậy làm thế nào điều này sẽ xử lý một điều kiện lỗi? nó cũng hạ cánh bên trong mã chờ đợi?
Manuel Hernandez

Tks này là giúp đỡ Greate, đặc biệt để gọi lại lời hứa khi lấy API đăng nhập, đó là phản ứng lại một cách hoàn hảo để có được lưu trữ GetItem
tess hsu

9

Tốt hơn nữa là đặt thêm dấu chấm phẩy trước khối mã

;(async () => {
    await ...
})();

Điều này ngăn chặn trình định dạng tự động (ví dụ: trong vscode) di chuyển dấu ngoặc đơn đầu tiên đến cuối dòng trước đó.

Vấn đề có thể được chứng minh trên ví dụ sau:

const add = x => y => x+y
const increment = add(1)
(async () => {
    await ...
})();

Nếu không có dấu chấm phẩy, điều này sẽ được định dạng lại thành:

const add = x => y => x+y
const increment = add(1)(async () => {
  await Promise(1)
})()

điều này rõ ràng là sai vì nó gán hàm không đồng bộ làm ytham số và cố gắng gọi một hàm từ kết quả (thực ra là một chuỗi kỳ lạ '1async () => {...}')


20
Nó không phải là trình định dạng sai. Nếu không có dấu chấm phẩy, đó là cách hàm của bạn sẽ được phân tích cú pháp trong thời gian chạy và bạn sẽ gặp lỗi, ngắt dòng hoặc không có ngắt dòng. Giải pháp chính xác trong ví dụ của bạn sẽ là thêm dấu chấm phẩy vào sau add(1);chứ không phải trước hàm async.
Madara's Ghost

11
Ngoài ra, tôi thực sự không hiểu điều này liên quan như thế nào đến câu hỏi đang bàn.
Madara's Ghost

Vâng bạn đã đúng. Ngoài ra thời gian chạy cần dấu chấm phẩy.
Viliam Simko


1

bạn có thể thực hiện cấp cao nhất đang chờ đợi kể từ phiên bản 3,8
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#-top-level-await
Từ bài đăng:
Điều này là do trước đây trong JavaScript (cùng với hầu hết các ngôn ngữ khác có tính năng tương tự), await chỉ được phép trong nội dung của một hàm không đồng bộ. Tuy nhiên, với await cấp cao nhất, chúng ta có thể sử dụng await ở cấp cao nhất của mô-đun.

const response = await fetch("...");
const greeting = await response.text();
console.log(greeting);

// Make sure we're a module
export {};

Lưu ý rằng có một sự tinh tế: await cấp cao nhất chỉ hoạt động ở cấp cao nhất của mô-đun và các tệp chỉ được coi là mô-đun khi TypeScript tìm thấy một nhập hoặc xuất. Trong một số trường hợp cơ bản, bạn có thể cần viết xuất {} dưới dạng một số bản soạn sẵn để đảm bảo điều này.

Mức cao nhất đang chờ đợi có thể không hoạt động trong tất cả các môi trường mà bạn có thể mong đợi tại thời điểm này. Hiện tại, bạn chỉ có thể sử dụng mức cao nhất đang chờ đợi khi tùy chọn trình biên dịch đích là es2017 trở lên và mô-đun là esnext hoặc hệ thống. Hỗ trợ trong một số môi trường và bộ gói có thể bị hạn chế hoặc có thể yêu cầu bật hỗ trợ thử nghiệm.

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.