2017-12-13 94 views
13

Tôi đã thử đọc hướng dẫn và hướng dẫn để không đồng bộ/chờ đợi, nhưng tôi dường như không thể tìm thấy địa chỉ này ở bất cứ đâu.Tại sao mã async/await JavaScript này không hoạt động như mong đợi?

Đây là mã trong câu hỏi:

var func1 = new Promise((resolve, reject) => { 
 
     console.log("Func1"); 
 
     setTimeout(() => { 
 
     resolve(10); 
 
     }, 100); 
 
    }); 
 
    
 
    var func2 = new Promise((resolve, reject) => { 
 
     console.log("Func2"); 
 
     setTimeout(() => { 
 
     resolve(20); 
 
     }, 5000); 
 
    }) 
 
    
 
    let run = async() => { 
 
     let var1 = await func1; 
 
     let var2 = await func2; 
 
     console.log(var1); 
 
     console.log(var2); 
 
    } 
 

 
    run();

Chúng ta thấy "Func1" và "Func2" được in ngay lập tức, một sau khi khác. 5 giây sau, thời gian chờ được chỉ định trong func2, chúng tôi nhận được bản in "10" và "20". Càng xa càng tốt.

Nhưng nếu tôi thay đổi các bit cuối cùng của mã này:

let run = async() => { 
    let var1 = await func1; 
    console.log(var1); 
    let var2 = await func2; 
    console.log(var2); 
} 

Sau đó, tôi nhìn thấy "Func1" ngay lập tức in, nhưng "Func2" là tốt, mặc dù console.log(var1) đứng trước nó. Sau 100ms đến "10", sau đó sau 5 giây đến "20".

Từ MDN:

Các chờ đợi biểu hiện gây ra chức năng async thực hiện tạm dừng cho đến khi một Promise được hoàn thành hoặc bị từ chối, và để tiếp tục thực hiện các chức năng async sau khi hoàn thành.

Nhưng có vẻ như đây không phải là những gì đang xảy ra. Nếu nó được, chúng ta sẽ không thấy "Func1", sau đó "10", THEN func2 được thực hiện, do đó in "Func2" và 5 giây sau, chúng tôi nhận được "20"? func1 nên được thực hiện, và một khi nó được giải quyết (trong 100 ms), console.log (var1) sẽ kích hoạt. Tôi đang thiếu gì ở đây?

+8

Nó bắt đầu giải quyết khi bạn tạo nó, không phải khi bạn chờ đợi nó –

+0

có thể trùng lặp của [Sử dụng nhiều setTimeout trong cùng một chức năng async/Timer reset ] (https://stackoverflow.com/q/47751923/1048572) – Bergi

Trả lời

7

Lý do cho điều này là bạn đã chạy các nhà quản trị lời hứa trước đây. Chấp hành viên Promise được đánh giá ngay lập tức khi truyền cho constructor Promise, do đó bạn sẽ nhận được như sau:

var func1 = new Promise((resolve, reject) => ...); // Logs "Func1" 
var func2 = new Promise((resolve, reject) => ...); // Logs "Func2" 

let run = async() => { 
    let var1 = await func1; 
    console.log(var1); // Logs 10 
    let var2 = await func2; 
    console.log(var2); // Logs 20 
} 

run(); 
2

Vấn đề chính ở đây là func1func2 không chức năng; Họ là những lời hứa. Giống như Jonas W. nói, lời hứa sẽ gọi lại cho họ ngay lập tức, và chờ đợi họ chỉ khiến họ đợi cho đến khi họ được giải quyết.

Bạn có thể thấy kết quả mong muốn của bạn ở đây:

var func1 =() => { 
 
    return new Promise((resolve, reject) => { 
 
    console.log("Func1"); 
 
    setTimeout(() => { 
 
     resolve(10); 
 
    }, 100); 
 
    }); 
 
} 
 
     
 
var func2 =() => { 
 
    return new Promise((resolve, reject) => { 
 
    console.log("Func2"); 
 
    setTimeout(() => { 
 
     resolve(20); 
 
    }, 5000); 
 
    }); 
 
} 
 
     
 
let run = async() => { 
 
    let var1 = await func1(); 
 
    let var2 = await func2(); 
 
    console.log(var1); 
 
    console.log(var2); 
 
} 
 

 
run();

+1

Tốt nhất thậm chí không nói về những lời hứa "bắt đầu" bất cứ điều gì. * Timeouts * là những gì bắt đầu ngay lập tức, những lời hứa chỉ được tạo ra (chúng sẽ được giải quyết sau). – Bergi

+0

@Bergi Chức năng được chuyển đến Lời hứa được gọi ngay lập tức, để cố gắng giải quyết nó. Lớp Promise về cơ bản bắt đầu giải quyết bằng cách bắn gọi lại được cung cấp cho hàm tạo. – FrankerZ

+0

Vâng, lời hứa * constructor * bắt đầu gọi lại của người thực thi, và do đó quá trình sẽ kết thúc ở độ phân giải của lời hứa (thông báo nó không giải quyết bất cứ điều gì cho đến khi 'giải quyết' được gọi). Tuy nhiên nhiều người nhận được ý tưởng rằng một ví dụ * lời hứa * có thể bắt đầu một nhiệm vụ lúc rảnh rỗi (hoặc thậm chí nhiều lần), điều này rõ ràng là sai. – Bergi

0

await về cơ bản có nghĩa là enshure rằng giá trị sau đây có sẵn trước khi tiếp tục. Lời hứa bắt đầu giải quyết khi bạn tạo ra nó, nó không quan trọng khi nó được chờ đợi.

0

Chức năng chạy theo thứ tự đồng bộ, ví dụ: mã sẽ thực hiện từng bước:

  1. gọi func1() và đợi cho đến khi có thư trả lời.
  2. gọi func2() và đợi cho đến khi có thư trả lời.
  3. nhật ký var1.
  4. nhật ký var2.

Vì vậy, 2 bước cuối cùng sẽ chỉ chạy khi lệnh gọi hàm func2() đã hoàn thành lời hứa, ví dụ: dữ liệu sau thời gian chờ. Vì vậy, nó sẽ chờ đợi đầy đủ 5 giây cho đến khi đăng nhập cả var1 và var2.

Cách khác là khá khác nhau 1. gọi func1() và chờ cho đến khi có thư trả lời. 2. đăng nhập var1. 3. gọi func2() và đợi cho đến khi có trả lời. 4. log var2.

Bước 2 sẽ đợi cho đến khi bước một đã trả về dữ liệu, ví dụ: sau 100ms và sau đó sẽ chuyển sang làm tương tự cho bước 3 và 4.

Các vấn đề liên quan