async 函數(shù)是 Generator 函數(shù)的語法糖京腥。
Generator 函數(shù)船老,依次讀取兩個文件
const fs = require('fs');
const readFile = function (fileName) {
return new Promise(function (resolve, reject) {
fs.readFile(fileName, function(error, data) {
if (error) return reject(error);
resolve(data);
});
});
};
const gen = function* () {
const f1 = yield readFile('/e/f');
const f2 = yield readFile('/e/s');
console.log(f1.toString());
console.log(f2.toString());
};
寫成async函數(shù)
const asyncReadFile = async function () {
const f1 = await readFile('/etc/fstab');
const f2 = await readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
Generator 函數(shù)與async函數(shù)的區(qū)別;
Generator 函數(shù)的執(zhí)行必須靠執(zhí)行器裕循,async函數(shù)自帶執(zhí)行器时迫;
async和await,比起星號和yield惫搏,語義更清楚了具温。async表示函數(shù)里有異步操作,await表示緊跟在后面的表達(dá)式需要等待結(jié)果
yield命令后面只能是 Thunk 函數(shù)或 Promise 對象筐赔,而async函數(shù)的await命令后面铣猩,可以是 Promise 對象和原始類型的值
async函數(shù)的返回值是 Promise 對象,這比 Generator 函數(shù)的返回值是 Iterator 對象
async 函數(shù)讓異步任務(wù)編程寫成類似同步任務(wù)茴丰,可讀性再次提升达皿;
function timeout(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function asyncPrint(value, ms) {
await timeout(ms);
console.log(value);
}
asyncPrint('hello world', 50);
注意事項
- async函數(shù)內(nèi)部拋出錯誤,會導(dǎo)致返回的 Promise 對象變?yōu)閞eject狀態(tài)贿肩。拋出的錯誤對象會被catch方法回調(diào)函數(shù)接收到峦椰。所以盡量把a(bǔ)wait命令放在try...catch代碼塊中
async function myFunction() {
try {
await somethingThatReturnsAPromise();
} catch (err) {
console.log(err);
}
}
- async函數(shù)返回的 Promise 對象,必須等到內(nèi)部所有await命令后面的 Promise 對象執(zhí)行完汰规,才會發(fā)生狀態(tài)改變汤功,除非遇到return語句或者拋出錯誤
async function getTitle(url) {
let response = await fetch(url);
let html = await response.text();
return html.match(/<title>([\s\S]+)<\/title>/i)[1];
}
getTitle('https://tc39.github.io/ecma262/').then(console.log)
// "ECMAScript 2017 Language Specification"
- await命令只能用在async函數(shù)之中,如果用在普通函數(shù)溜哮,就會報錯
async function dbFuc(db) {
let docs = [{}, {}, {}];
// 報錯
docs.forEach(function (doc) {
await db.post(doc);
});
}
作用可以用async/await將Promise的鏈?zhǔn)秸{(diào)用優(yōu)化滔金,使看起來像同步代碼
function delay (time){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(time);
},time)
})
}
async function fn(){
console.log("start");
let time1 = await delay(1000);
console.log(`${time1}ms passed`);
let time2 = await delay(3000);
console.log(`${time2}ms passed`);
}
fn().catch(err=>{
console.log(err)
})
function getIp() {
var promise = new Promise(function(resolve, reject){
var xhr = new XMLHttpRequest()
xhr.open('GET', 'https://easy-mock.com/mock/5ac2f80c3d211137b3f2843a/promise/getIp', true)
xhr.onload = function(){
var retJson = JSON.parse(xhr.responseText) // {"ip":"58.100.211.137"}
resolve(retJson.ip)
}
xhr.onerror = function(){
reject('獲取IP失敗')
}
xhr.send()
})
return promise
}
function getCityFromIp(ip) {
var promise = new Promise(function(resolve, reject){
var xhr = new XMLHttpRequest()
xhr.open('GET', 'https://easy-mock.com/mock/5ac2f80c3d211137b3f2843a/promise/getCityFromIp?ip='+ip, true)
xhr.onload = function(){
var retJson = JSON.parse(xhr.responseText) // {"city": "hangzhou","ip": "23.45.12.34"}
resolve(retJson.city)
}
xhr.onerror = function(){
reject('獲取city失敗')
}
xhr.send()
})
return promise
}
function getWeatherFromCity(city) {
var promise = new Promise(function(resolve, reject){
var xhr = new XMLHttpRequest()
xhr.open('GET', 'https://easy-mock.com/mock/5ac2f80c3d211137b3f2843a/promise/getWeatherFromCity?city='+city, true)
xhr.onload = function(){
var retJson = JSON.parse(xhr.responseText) //{"weather": "晴天","city": "beijing"}
resolve(retJson)
}
xhr.onerror = function(){
reject('獲取天氣失敗')
}
xhr.send()
})
return promise
}
async function start(){
let ip = await getIp();
console.log(ip);
let cityInfo = await getCityFromIp(ip);
console.log(cityInfo);
let weatherInfo = await getWeatherFromCity(cityInfo.city);
console.log(weatherInfo.weather)
}
start()