Các chức năng async , một tính năng trong ES2017 , làm cho mã async trông đồng bộ hóa bằng cách sử dụng các lời hứa (một dạng mã async cụ thể) và await
từ khóa. Cũng lưu ý trong các ví dụ mã bên dưới từ khóa async
phía trước function
từ khóa biểu thị chức năng async / await. Các await
từ khóa sẽ không hoạt động mà không bị trong một chức năng trước cố định với các async
từ khóa. Vì hiện tại không có ngoại lệ cho điều này có nghĩa là không có sự chờ đợi cấp cao nhất sẽ hoạt động (cấp cao nhất đang chờ có nghĩa là chờ đợi bên ngoài bất kỳ chức năng nào). Mặc dù có một đề xuất cho cấp cao nhấtawait
.
ES2017 được phê chuẩn (tức là đã quyết toán) như là tiêu chuẩn cho JavaScript trên 27 tháng 6, 2017. Async chờ đợi có thể đã làm việc trong trình duyệt của bạn, nhưng nếu không bạn vẫn có thể sử dụng các chức năng sử dụng một transpiler javascript như babel hoặc Traceur . Chrome 55 có hỗ trợ đầy đủ các chức năng không đồng bộ. Vì vậy, nếu bạn có một trình duyệt mới hơn, bạn có thể thử mã bên dưới.
Xem bảng tương thích es2017 của kangax để biết khả năng tương thích trình duyệt.
Dưới đây là một ví dụ về chức năng chờ đồng bộ được gọi là doAsync
tạm dừng ba giây và in chênh lệch thời gian sau mỗi lần tạm dừng từ thời gian bắt đầu:
function timeoutPromise (time) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(Date.now());
}, time)
})
}
function doSomethingAsync () {
return timeoutPromise(1000);
}
async function doAsync () {
var start = Date.now(), time;
console.log(0);
time = await doSomethingAsync();
console.log(time - start);
time = await doSomethingAsync();
console.log(time - start);
time = await doSomethingAsync();
console.log(time - start);
}
doAsync();
Khi từ khóa await được đặt trước một giá trị lời hứa (trong trường hợp này, giá trị lời hứa là giá trị được trả về bởi hàm doS SomethingAsync), từ khóa await sẽ tạm dừng thực hiện lệnh gọi hàm, nhưng nó sẽ không tạm dừng bất kỳ chức năng nào khác và nó sẽ tiếp tục thực thi mã khác cho đến khi lời hứa được giải quyết. Sau khi lời hứa được giải quyết, nó sẽ mở ra giá trị của lời hứa và bạn có thể nghĩ đến biểu hiện chờ đợi và lời hứa như bây giờ được thay thế bằng giá trị chưa được tiết lộ đó.
Vì vậy, vì chờ đợi chỉ tạm dừng chờ đợi để mở ra một giá trị trước khi thực hiện phần còn lại của dòng, bạn có thể sử dụng nó cho các vòng lặp và bên trong các lệnh gọi như trong ví dụ dưới đây thu thập sự khác biệt về thời gian chờ trong một mảng và in ra mảng.
function timeoutPromise (time) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(Date.now());
}, time)
})
}
function doSomethingAsync () {
return timeoutPromise(1000);
}
// this calls each promise returning function one after the other
async function doAsync () {
var response = [];
var start = Date.now();
// each index is a promise returning function
var promiseFuncs= [doSomethingAsync, doSomethingAsync, doSomethingAsync];
for(var i = 0; i < promiseFuncs.length; ++i) {
var promiseFunc = promiseFuncs[i];
response.push(await promiseFunc() - start);
console.log(response);
}
// do something with response which is an array of values that were from resolved promises.
return response
}
doAsync().then(function (response) {
console.log(response)
})
Chính hàm async trả về một lời hứa để bạn có thể sử dụng lời hứa đó với chuỗi như tôi thực hiện ở trên hoặc trong một hàm chờ async khác.
Hàm trên sẽ đợi từng phản hồi trước khi gửi yêu cầu khác nếu bạn muốn gửi yêu cầu đồng thời, bạn có thể sử dụng Promise.all .
// no change
function timeoutPromise (time) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(Date.now());
}, time)
})
}
// no change
function doSomethingAsync () {
return timeoutPromise(1000);
}
// this function calls the async promise returning functions all at around the same time
async function doAsync () {
var start = Date.now();
// we are now using promise all to await all promises to settle
var responses = await Promise.all([doSomethingAsync(), doSomethingAsync(), doSomethingAsync()]);
return responses.map(x=>x-start);
}
// no change
doAsync().then(function (response) {
console.log(response)
})
Nếu lời hứa có thể từ chối, bạn có thể gói nó trong một thử bắt hoặc bỏ qua thử bắt và để lỗi lan truyền đến hàm async / await các chức năng bắt cuộc gọi. Bạn nên cẩn thận để không xử lý các lỗi hứa hẹn, đặc biệt là trong Node.js. Dưới đây là một số ví dụ cho thấy cách làm việc lỗi.
function timeoutReject (time) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
reject(new Error("OOPS well you got an error at TIMESTAMP: " + Date.now()));
}, time)
})
}
function doErrorAsync () {
return timeoutReject(1000);
}
var log = (...args)=>console.log(...args);
var logErr = (...args)=>console.error(...args);
async function unpropogatedError () {
// promise is not awaited or returned so it does not propogate the error
doErrorAsync();
return "finished unpropogatedError successfully";
}
unpropogatedError().then(log).catch(logErr)
async function handledError () {
var start = Date.now();
try {
console.log((await doErrorAsync()) - start);
console.log("past error");
} catch (e) {
console.log("in catch we handled the error");
}
return "finished handledError successfully";
}
handledError().then(log).catch(logErr)
// example of how error propogates to chained catch method
async function propogatedError () {
var start = Date.now();
var time = await doErrorAsync() - start;
console.log(time - start);
return "finished propogatedError successfully";
}
// this is what prints propogatedError's error.
propogatedError().then(log).catch(logErr)
Nếu bạn đến đây, bạn có thể thấy các đề xuất đã hoàn thành cho các phiên bản ECMAScript sắp tới.
Một thay thế cho điều này có thể được sử dụng chỉ với ES2015 (ES6) là sử dụng một chức năng đặc biệt bao bọc một chức năng của trình tạo. Các hàm tạo có một từ khóa năng suất có thể được sử dụng để sao chép từ khóa đang chờ với một hàm xung quanh. Từ khóa năng suất và chức năng tạo là mục đích chung hơn rất nhiều và có thể làm nhiều việc khác sau đó chỉ là chức năng chờ đợi không đồng bộ. Nếu bạn muốn có một chức năng máy phát điện wrapper mà có thể được sử dụng để async lặp chờ đợi tôi sẽ kiểm tra co.js . Bằng cách này, chức năng của co giống như async đang chờ các hàm trả lại một lời hứa. Thành thật mà nói, tại thời điểm này khả năng tương thích của trình duyệt gần giống nhau cho cả chức năng trình tạo và chức năng không đồng bộ, vì vậy nếu bạn chỉ muốn chức năng chờ đồng bộ, bạn nên sử dụng các chức năng Async mà không có co.js.
Hiện tại, hỗ trợ trình duyệt thực sự khá tốt đối với các chức năng Async (kể từ năm 2017) trong tất cả các trình duyệt chính hiện tại (Chrome, Safari và Edge) ngoại trừ IE.