中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

async是es7的嗎

發布時間:2023-01-30 14:28:53 來源:億速云 閱讀:113 作者:iii 欄目:web開發

這篇文章主要介紹“async是es7的嗎”,在日常操作中,相信很多人在async是es7的嗎問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”async是es7的嗎”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

async是es7的。async和await是ES7中新增內容,是對于異步操作的解決方案;async/await可以說是co模塊和生成器函數的語法糖,用更加清晰的語義解決js異步代碼。async顧名思義是“異步”的意思,async用于聲明一個函數是異步的;async和await有一個嚴格規定,兩者都離不開對方,且await只能寫在async函數中。

ES7(ES2017)中提出的前端異步特性:async、await。

async/await是什么

async和await是ES7中新增內容,對于異步操作的解決方案,async/await可以說是co模塊和生成器函數的語法糖。用更加清晰的語義解決js異步代碼。

async顧名思義是“異步”的意思,async用于聲明一個函數是異步的。而await從字面意思上是“等待”的意思,就是用于等待異步完成。

async和await它們兩有一個嚴格規定,兩者都離不開對方,但是,await只能寫在async函數中。

熟悉co模塊的同學應該都知道,co模塊是TJ大神寫的一個使用生成器函數來解決異步流程的模塊,可以看做是生成器函數的執行器。而async/await則是對co模塊的升級,內置生成器函數的執行器,不再依賴co模塊。同時,async返回的是Promise。

從上面來看,不管是co模塊還是async/await,都是將Promise作為最基礎的單元,對Promise不很了解的同學可以先深入了解一下Promise。

對比Promise,co,async/await

下面我們使用一個簡單的例子,來對比一下三種方式的異同,以及取舍。

我們采用mongodb的nodejs驅動,查詢mongodb數據庫作為例子,原因是mongodb的js驅動已經默認實現了返回Promise,而不用我們單獨去包裝Promise了。

使用Promise鏈

MongoClient.connect(url + db_name).then(db => {
    return db.collection('blogs');
}).then(coll => {
    return coll.find().toArray();
}).then(blogs => {
    console.log(blogs.length);
}).catch(err => {
    console.log(err);
})

Promise的then()方法可以返回另一個Promise,也可以返回一個同步的值,如果返回的是一個同步值,將會被包裝成一個Promise。上面的例子中,db.collection()將返回一個同步的值,即集合對象,但是被包裝成Promise,將會透傳到下一個then()方法。上面一個例子,是使用的Promise鏈。先連接數據庫MongoClient.connect()返回一個Promise,然后在then()方法里獲得數據庫對象db,然后再獲取到coll對象再返回。在下一個then()方法獲得coll對象,然后進行查詢,查詢結果返回,逐層調用then()方法,形成一個Promise鏈。在這個Promise鏈上,如果任何一個環節出現異常,都會被最后的catch()捕捉到。可以說,這個使用Promise鏈寫的代碼,比層層調用回調函數更優雅,流程也更明確。先獲得數據庫對象,再獲得集合對象,最后查詢數據。但是這里有個不怎么“優雅”的問題,在于,每一個then()方法獲取的對象,都是上一個then()方法返回的數據。而不能跨層訪問。什么意思,就是說在第三個then(blogs => {})中我們只能獲取到查詢的結果blogs,而不能使用上面的db對象和coll對象。這個時候,如果要打印出blogs列表后,要關閉數據庫db.close()怎么辦?這個時候,可以兩種解決方法:

第一種是,使用then()嵌套。我們將Promise鏈打斷,使之嵌套,猶如使用回調函數的嵌套一般:

MongoClient.connect(url + db_name).then(db => {
    let coll = db.collection('blogs');
    coll.find().toArray().then(blogs => {
        console.log(blogs.length);
        db.close();
    }).catch(err => {
        console.log(err);
    });
}).catch(err => {
    console.log(err);
})

這里我們將兩個Promise嵌套,這樣在最后一個查詢操作里面,就可以調用外面的db對象了。但是這中方式,并不推薦。原因很簡單,我們從一種回調函數地獄走向了另一種Promise回調地獄。
而且,我們要對每個Promise的異常進行捕捉,因為Promise沒有形成鏈。

還有一種方式, 是在每個then()方法里都將db傳過來:

MongoClient.connect(url + db_name).then(db => {
    return {db:db,coll:db.collection('blogs')};
}).then(result => {
    return {db:result.db,blogs:result.coll.find().toArray()};
}).then(result => {
    return result.blogs.then(blogs => {   //注意這里,result.coll.find().toArray()返回的是一個Promise,因此這里需要再解析一層
        return {db:result.db,blogs:blogs}
    })
}).then(result => {
    console.log(result.blogs.length);
    result.db.close();
}).catch(err => {
    console.log(err);
});

我們在每個then()方法的返回中,都將db及其每次的其他結果組成一個對象返回。請注意,如果每次的結果都是一個同步的值還好說,但是如果是一個Promise值,每一個Promise都需要多做一層解析。
例如上面的一個例子,第二個then()方法返回的{db:result.db,blogs:result.coll.find().toArray()}對象中,blogs是一個Promise,在下一個then()方法中,我們無法直接引用博客列表數組值,因此需要先調用then()方法解析一層,然后將兩個同步值db和blogs返回。注意,這里涉及到了Promise的嵌套,不過一個Promise只嵌套一層then()。

這種方式,也是很蛋疼的一個方式,因為如果遇到then()方法中返回的不是同步的值,而是Promise的話,我們需要多做很多工作。而且,每次都透傳一個“多余”的db對象,在邏輯上也有點冗余。

但除此之外,對于Promise鏈的使用,如果遇到上面的問題,好像也沒其他更好的方法解決了。我們只能根據場景去選擇一種“最優”的方案,如果要使用Promise鏈的話。

鑒于Promise上面蛋疼的問題,TJ大神將ES6中的生成器函數,用co模塊包裝了一下,以更優雅的方式來解決上面的問題。

co搭配生成器函數

如果使用co模塊搭配生成器函數,那么上面的例子可以改寫如下:

const co = require('co');
co(function* (){
    let db = yield MongoClient.connect(url + db_name);
    let coll = db.collection('blogs');
    let blogs = yield coll.find().toArray();
    console.log(blogs.length);
    db.close();
}).catch(err => {
    console.log(err);
});

co是一個函數,將接受一個生成器函數作為參數,去執行這個生成器函數。生成器函數中使用yield關鍵字來“同步”獲取每個異步操作的值。
上面代碼在代碼形式上,比上面使用Promise鏈要優雅,我們消滅了回調函數,代碼看起來都是同步的。除了使用co和yield有點怪之外。

使用co模塊,我們要將所有的操作包裝成一個生成器函數,然后使用co()去調用這個生成器函數。看上去也還可以接受,但是ES的進化是不滿足于此的,于是async/await被提到了ES7的提案。

async/await

我們先看一下使用async/await改寫上面的代碼:

(async function(){
    let db = await MongoClient.connect(url + db_name);
    let coll = db.collection('blogs');
    let blogs = await coll.find().toArray();
    console.log(blogs.length);
    db.close();
})().catch(err => {
    console.log(err);
});

我們對比代碼可以看出,async/await和co兩種方式代碼極為相似。co換成了async,yield換成了await。同時生成器函數變成了普通函數。這種方式在語義上更加清晰明了,async表明這個函數是異步的,同時await表示要“等待”異步操作返回值。

async函數返回一個Promise,上面的代碼其實是這樣:

let getBlogs = async function(){
    let db = await MongoClient.connect(url + db_name);
    let coll = db.collection('blogs');
    let blogs = await coll.find().toArray();
    db.close();
    return blogs;
};
getBlogs().then(result => {
    console.log(result.length);
}).catch(err => {
    console.log(err);
})

我們定義getBlogs為一個async函數,最后返回得到的博客列表最終會被包裝成一個Promise返回,如上,我們直接調用getBlogs().then()方法可獲取async函數返回值。

好了,上面我們簡單對比了一下三種解決異步方案,下面我們來深入了解一下async/await。

深入async/await

async返回值

async用于定義一個異步函數,該函數返回一個Promise。
如果async函數返回的是一個同步的值,這個值將被包裝成一個理解resolve的Promise,等同于return Promise.resolve(value)
await用于一個異步操作之前,表示要“等待”這個異步操作的返回值。await也可以用于一個同步的值。

//返回一個Promise
let timer = async function timer(){
    return new Promise((resolve,reject) => {
        setTimeout(() => {
            resolve('500');
        },500);
    });
}
timer().then(result => {
  console.log(result);  //500
}).catch(err => {
    console.log(err.message);
});
//返回一個同步的值
let sayHi = async function sayHi(){
  let hi = await 'hello world';   
  return hi;  //等同于return Promise.resolve(hi);
}
sayHi().then(result => {
  console.log(result);
});

上面這個例子返回是一個同步的值,字符串’hello world’,sayHi()是一個async函數,返回值被包裝成一個Promise,可以調用then()方法獲取返回值。對于一個同步的值,可以使用await,也可以不使用await。效果效果是一樣的。具體用不用,看情況。

比如上面使用mongodb查詢博客那個例子,let coll = db.collection('blogs');,這里我們就沒有用await,因為這是一個同步的值。當然,也可以使用await,這樣會顯得代碼統一。雖然效果是一樣的。

async函數的異常

let sayHi = async function sayHi(){
    throw new Error('出錯了');
}
sayHi().then(result => {
  console.log(result);
}).catch(err => {
    console.log(err.message);   //出錯了
});

我們直接在async函數中拋出一個異常,由于返回的是一個Promise,因此,這個異常可以調用返回Promise的catch()方法捕捉到。

和Promise鏈的對比:
我們的async函數中可以包含多個異步操作,其異常和Promise鏈有相同之處,如果有一個Promise被reject()那么后面的將不會再進行。

let count = ()=>{
    return new Promise((resolve,reject) => {
        setTimeout(()=>{
            reject('故意拋出錯誤');
        },500);
    });
}
let list = ()=>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve([1,2,3]);
        },500);
    });
}
let getList = async ()=>{
    let c = await count();
    let l = await list();
    return {count:c,list:l};
}
console.time('begin');
getList().then(result => {
    console.log(result);
}).catch(err => {
    console.timeEnd('begin');
    console.log(err);
});
//begin: 507.490ms
//故意拋出錯誤

如上面的代碼,定義兩個異步操作,count和list,使用setTimeout延時500毫秒,count故意直接拋出異常,從輸出結果來看,count()拋出異常后,直接由catch()捕捉到了,list()并沒有繼續執行。

并行

使用async后,我們上面的例子都是串行的。比如上個list()和count()的例子,我們可以將這個例子用作分頁查詢數據的場景。先查詢出數據庫中總共有多少條記錄,然后再根據分頁條件查詢分頁數據,最后返回分頁數據以及分頁信息。

我們上面的例子count()和list()有個“先后順序”,即我們先查的總數,然后又查的列表。其實,這兩個操作并無先后關聯性,我們可以異步的同時進行查詢,然后等到所有結果都返回時再拼裝數據即可。

let count = ()=>{
    return new Promise((resolve,reject) => {
        setTimeout(()=>{
            resolve(100);
        },500);
    });
}
let list = ()=>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve([1,2,3]);
        },500);
    });
}
let getList = async ()=>{
    let result = await Promise.all([count(),list()]);
    return result;
}
console.time('begin');
getList().then(result => {
    console.timeEnd('begin');  //begin: 505.557ms
    console.log(result);       //[ 100, [ 1, 2, 3 ] ]
}).catch(err => {
    console.timeEnd('begin');
    console.log(err);
});

我們將count()和list()使用Promise.all()“同時”執行,這里count()和list()可以看作是“并行”執行的,所耗時間將是兩個異步操作中耗時最長的耗時。最后得到的結果是兩個操作的結果組成的數組。我們只需要按照順序取出數組中的值即可。

到此,關于“async是es7的嗎”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

曲周县| 赣榆县| 什邡市| 育儿| 万州区| 民权县| 广丰县| 方山县| 乌恰县| 开阳县| 南阳市| 高邑县| 于都县| 新乡市| 湖北省| 申扎县| 岗巴县| 临邑县| 平安县| 星子县| 蕉岭县| 金沙县| 威远县| 奉节县| 始兴县| 朝阳区| 饶阳县| 台中市| 正宁县| 绥德县| 枣庄市| 辽中县| 墨脱县| 克什克腾旗| 开封县| 黄平县| 邓州市| 聂拉木县| 泗洪县| 铜梁县| 辽宁省|