最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

ES6的異步操作之promise用法和async函數(shù)的具體使用

 更新時間:2019年12月06日 10:27:33   作者:Dora36  
這篇文章主要介紹了ES6的異步操作之promise用法和async函數(shù)的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

promise 基本用法

Promise 對象是一個構(gòu)造函數(shù),用來生成 Promise 實例。Promise 構(gòu)造函數(shù)接受一個函數(shù)作為參數(shù),該函數(shù)的兩個參數(shù)分別是 resolve 和 reject。

resolve 函數(shù)的作用是,在異步操作成功時調(diào)用(Promise 對象的狀態(tài)從 pending 變?yōu)?fulfilled),并將異步操作的結(jié)果,作為參數(shù)傳遞出去。

reject 函數(shù)的作用是,在異步操作失敗時調(diào)用(Promise對象的狀態(tài)從 pending 變?yōu)?rejected),并將異步操作報出的錯誤,作為參數(shù)傳遞出去。

const funPromise = function(options) {
 return new Promise(function(resolve, reject) {
  if (/* 異步操作成功 */){
   resolve(result);
  } else {
   reject(error);
  }
 });
}

resolve 函數(shù)的參數(shù)除了正常的值以外,還可能是另一個 Promise 實例,此時,初始 promise 的最終狀態(tài)根據(jù)傳入的新的 Promise 實例決定。

reject 方法的作用,相當于拋出錯誤。等同于 throw new Error('error')。

Promise.prototype.then()

Promise 實例具有 then 方法,它的作用是為 Promise 實例添加狀態(tài)改變時的回調(diào)函數(shù),即 Promise 實例生成以后,用 then 方法分別指定 fulfilled 狀態(tài)和 rejected 狀態(tài)的回調(diào)函數(shù)。

funPromise().then(function(result) {
 // fulfilled
}, function(error) {
 // rejected
})

then 方法可以接受兩個回調(diào)函數(shù)作為參數(shù)。第一個回調(diào)函數(shù)是 Promise 對象的狀態(tài)變?yōu)?fulfilled 時調(diào)用,第二個回調(diào)函數(shù)是 Promise 對象的狀態(tài)變?yōu)?rejected 時調(diào)用。其中,第二個函數(shù)是可選的,不一定要提供。這兩個函數(shù)都接受 Promise 對象傳出的值作為參數(shù)。

then 方法返回的是一個新的 Promise 實例(注意,不是原來那個 Promise 實例)。因此可以采用鏈式寫法,即 then 方法后面再調(diào)用另一個 then 方法來處理上一個 then 方法中 return 的結(jié)果。

funPromise().then(function(result) {
 return result.data;
}).then(function(data) {
 // fulfilled
});

上面的代碼使用 then 方法,依次指定了兩個回調(diào)函數(shù)。第一個回調(diào)函數(shù)完成以后,會將返回結(jié)果作為參數(shù),傳入第二個回調(diào)函數(shù)。并且,第一個 then 返回的結(jié)果也可以是另一個異步操作的 Promise 對象,這時后一個 then 函數(shù),就會等待該 Promise 對象的狀態(tài)發(fā)生變化,才會被調(diào)用。

funPromise().then(
 (result) => { return funPromise(result); }
).then(
 (data) => { /* fulfilled */ },
 (error) => { /* rejected */ }
);

上面代碼中,第一個 then 方法指定的回調(diào)函數(shù),返回的是另一個 Promise 對象。這時,第二個 then 方法指定的回調(diào)函數(shù),就會等待這個新的 Promise 對象狀態(tài)發(fā)生變化。如果變?yōu)?fulfilled,就調(diào)用第一個回調(diào)函數(shù),如果狀態(tài)變?yōu)?rejected,就調(diào)用第二個回調(diào)函數(shù)。

Promise.prototype.catch()

Promise 實例具有 catch 方法,它的作用是為 Promise 實例添加狀態(tài)改變?yōu)?rejected 狀態(tài)的回調(diào)函數(shù),也就是 then 方法的第二個函數(shù)的替代寫法。

funPromise().then(function(result) {
 // fulfilled
}).catch(function(error) {
 // 處理 funPromise 和之前 then 回調(diào)函數(shù)運行時發(fā)生的錯誤
});

Promise 對象的錯誤具有“冒泡”性質(zhì),會一直向后傳遞,直到被捕獲為止。也就是說,無論前面有多少個 then 函數(shù),其中的錯誤總是會被下一個 catch 語句捕獲。

funPromise().then(function(result) {
 return funPromise(result);
}).then(function(data) {
 // fulfilled
}).catch(function(error) {
 // 處理前面三個 Promise 產(chǎn)生的錯誤
});

一般來說,不要在 then 方法里面定義 rejected 狀態(tài)的回調(diào)函數(shù)(即 then 的第二個參數(shù)),總是使用 catch 方法,因為這種寫法可以捕獲前面 then 方法執(zhí)行中的錯誤。

catch 方法返回的還是一個 Promise 對象,并且 catch 中如果沒有拋出任何其它錯誤,那么該 Promise 對象則是 resolved 狀態(tài)。而且后面還可以接著調(diào)用 then 方法,但是前面的 catch 不能捕獲后面的 then 中的錯誤,所以盡量 catch 都寫在最后。

Promise.all()

Promise.all() 方法用于將多個 Promise 實例,包裝成一個新的 Promise 實例。其接受一個數(shù)組作為參數(shù),數(shù)組中的值都是 Promise 實例,如果不是,就會先調(diào)用 Promise.resolve() 方法,將參數(shù)轉(zhuǎn)為 Promise 實例,再進一步處理。

const p = Promise.all([funPromise(1), funPromise(2), funPromise(3)]);

p 的狀態(tài)由數(shù)組中的值決定,分成兩種情況。

  • 數(shù)組中 Primise 實例的狀態(tài)都變成 fulfilled,p 的狀態(tài)才會變成 fulfilled,此時數(shù)組中實例的返回值組成一個數(shù)組,傳遞給 p 的回調(diào)函數(shù)。
  • 只要數(shù)組的實例之中有一個被 rejected,p 的狀態(tài)就變成 rejected,此時第一個被 reject 的實例的返回值,也就是報錯信息,會傳遞給 p 的回調(diào)函數(shù)。
p.then(function (results) {
 // 全部 fulfilled,results 是個數(shù)組,里面是每個實例的返回結(jié)果
}).catch(function(error){
 // 其中有一個變?yōu)?rejected
});

注意,如果作為參數(shù)的 Promise 實例,自己定義了 catch 方法,那么它一旦被 rejected,并不會觸發(fā) Promise.all() 的 catch 方法。

應用

用 Promise 對象實現(xiàn) Ajax。

const getAjax = function(url) {
 const promise = new Promise(function(resolve, reject){
  const handler = function() {
   if (this.readyState === 4 && this.status === 200) {
    resolve(this.response);
   } else {
    reject(new Error(this.statusText));
   }
  };
  const xhr = new XMLHttpRequest();
  xhr.open("GET", url);
  xhr.onreadystatechange = handler;
  xhr.responseType = "json";
  xhr.setRequestHeader("Accept", "application/json");
  xhr.send();
 });
 return promise;
};

getAjax("/test.json").then(function(json) {
 console.log('Contents: ' + json);
}, function(error) {
 console.error('出錯了', error);
});

async / await 基本用法

當 async 函數(shù)執(zhí)行的時候,一旦遇到 await 就會先等到 await 后的異步操作完成,再接著執(zhí)行函數(shù)體內(nèi)之后的語句。

async 函數(shù)返回一個 Promise 對象,可以使用 then 方法添加回調(diào)函數(shù)。async 函數(shù)內(nèi)部 return 語句返回的值,會成為 then 方法回調(diào)函數(shù)的參數(shù)。

async function f() {
 return 'hello dora';
}

f().then(v => console.log(v))  // "hello dora"

async 函數(shù)內(nèi)部拋出錯誤,會導致返回的 Promise 對象變?yōu)?rejected 狀態(tài)。拋出的錯誤對象會被 catch 方法回調(diào)函數(shù)接收到。

async function f() {
 throw new Error('出錯了');
}

f().catch( e => console.log(e)) // Error: 出錯了

await 命令

正常情況下,await 命令后面是一個 Promise 對象,返回該對象的結(jié)果。如果不是 Promise 對象,就直接返回對應的值。

async function f() {
 return await 123;       // 等同于 return 123;
}

f().then(v => console.log(v)) // 123

await 命令后面的 Promise 對象如果變?yōu)?rejected 狀態(tài),則錯誤會被 catch 方法的回調(diào)函數(shù)接收到。

任何一個 await 語句后面的 Promise 對象變?yōu)?rejected 狀態(tài),那么整個 async 函數(shù)就會中斷執(zhí)行。

有時,我們希望即使前一個異步操作失敗,也不要中斷后面的異步操作,有兩個解決辦法:

第一種方法是可以將 await 放在 try...catch 結(jié)構(gòu)里面,這樣不管這個異步操作是否成功,后面的代碼都會執(zhí)行。

async function f() {
 try {
  await Promise.reject('出錯了');
 } catch(e) { }
 return await Promise.resolve('hello dora');
}

f().then(v => console.log(v))  // hello dora

另一種方法是 await 后面的 Promise 對象再跟一個 catch 方法,處理前面可能出現(xiàn)的錯誤。

async function f() {
 await Promise.reject('出錯了').catch(e => console.log(e));
 return await Promise.resolve('hello dora');
}

f().then(v => console.log(v))
// 出錯了
// hello dora

使用注意點

1. 錯誤處理

前面已經(jīng)說過,await 命令后面的 Promise 對象,運行結(jié)果可能是 rejected,所以防止出錯的方法,就是最好把 await 命令放在 try...catch 代碼塊中。如果有多個 await 命令,可以統(tǒng)一放在 try...catch 結(jié)構(gòu)中,如果只有一個 await,可以使用上例中的 catch 捕獲 await 后面的 promise 拋出的錯誤。

const superagent = require('superagent');
const NUM_RETRIES = 3;

async function test() {
 let i;
 for (i = 0; i < NUM_RETRIES; i++) {
  try {
   await superagent.get('/api/xxx');
   break;
  } catch(err) {}
 }
}

test();

上面代碼中,使用 try...catch 結(jié)構(gòu),實現(xiàn)多次重復嘗試。如果 await 操作成功,就會使用 break 語句退出循環(huán);如果失敗,會被 catch 語句捕捉,然后進入下一輪循環(huán)。

2. 多個 await 異步操作并發(fā)執(zhí)行

多個 await 命令后面的異步操作,如果不存在繼發(fā)關系(即互不依賴),最好讓它們同時觸發(fā),以縮短程序的執(zhí)行時間。

// 寫法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);

// 寫法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;

3. forEach 等數(shù)組遍歷方法的參數(shù)為 async 函數(shù)時是并發(fā)執(zhí)行的

只有 async 函數(shù)內(nèi)部是繼發(fā)執(zhí)行,外部不受影響,因此 forEach()、map() 等數(shù)組遍歷方法的參數(shù)改成 async 時是并發(fā)執(zhí)行的。

function dbFuc() { //這里不需要 async
 let docs = [{}, {}, {}];

 // 會得到錯誤結(jié)果
 docs.forEach(async (doc)=> {
  await funPromise(doc);
 });
}

上面代碼會得到錯誤結(jié)果,原因是這時三個 funPromise(doc) 操作是并發(fā)執(zhí)行的,也就是同時執(zhí)行,而不是繼發(fā)執(zhí)行。因此正確的寫法是采用 for 循環(huán)。

async function dbFuc() {
 let docs = [{}, {}, {}];

 for (let doc of docs) {
  await funPromise(doc);
 }
}

如果需要并發(fā)執(zhí)行,可使用 Promise.all() 方法。

async function dbFuc() {
 let docs = [{}, {}, {}];
 let promises = docs.map((doc) => funPromise(doc));

 let results = await Promise.all(promises);
 return results;
}

有一組異步操作,需要按照順序完成。

async function logInOrder(urls) {
 // 并發(fā)讀取遠程URL
 const textPromises = urls.map(async url => {
  const response = await fetch(url);
  return response.text();
 });

 // 按次序輸出
 for (const textPromise of textPromises) {
  console.log(await textPromise);
 }
}

上面代碼中,雖然 map 方法的參數(shù)是 async 函數(shù),但它是并發(fā)執(zhí)行的,因為只有 async 函數(shù)內(nèi)部是繼發(fā)執(zhí)行,外部不受影響。后面的 for..of 循環(huán)內(nèi)部使用了 await,因此實現(xiàn)了按順序輸出。

參考鏈接:
Promise 對象
async 函數(shù)

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • JavaScript涉及二進制的轉(zhuǎn)換方式

    JavaScript涉及二進制的轉(zhuǎn)換方式

    這篇文章主要介紹了JavaScript涉及二進制的轉(zhuǎn)換方式,具有很好的 參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • 前端大文件上傳處理與性能優(yōu)化詳解

    前端大文件上傳處理與性能優(yōu)化詳解

    隨著Web應用不斷發(fā)展,文件上傳功能已成為許多項目不可或缺的一部分,下面我們就來看看如何在前端處理文件上傳并且避免大文件造成的性能問題吧
    2025-03-03
  • javascript replace()方法的簡單分析

    javascript replace()方法的簡單分析

    javascript中replace()在javascript中,String的函數(shù)replace()簡直太讓人喜愛了。它靈活而強大的字符替換處理能力,讓我不禁想向大家介紹它。
    2008-11-11
  • JS 通過系統(tǒng)時間限定動態(tài)添加 select option的實例代碼

    JS 通過系統(tǒng)時間限定動態(tài)添加 select option的實例代碼

    這篇文章主要介紹了JS 通過系統(tǒng)時間限定 動態(tài)添加 select option的實例代碼,非常不錯具有參考借鑒價值,需要的朋友可以參考下
    2016-06-06
  • 基于Bootstrap使用jQuery實現(xiàn)簡單可編輯表格

    基于Bootstrap使用jQuery實現(xiàn)簡單可編輯表格

    這篇文章主要介紹了基于Bootstrap使用jQuery實現(xiàn)簡單可編輯表格的相關資料,需要的朋友可以參考下
    2016-05-05
  • 原生js封裝無縫輪播功能

    原生js封裝無縫輪播功能

    這篇文章主要為大家詳細介紹了原生js封裝無縫輪播功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-05-05
  • TypeScript?接口繼承的具體使用

    TypeScript?接口繼承的具體使用

    本文主要介紹了TypeScript?接口繼承的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-07-07
  • JavaScript如何判斷對象有某屬性

    JavaScript如何判斷對象有某屬性

    這篇文章主要介紹了JavaScript如何判斷對象有某屬性,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-07-07
  • 簡單聊聊JavaScript的事件循環(huán)機制

    簡單聊聊JavaScript的事件循環(huán)機制

    前端開發(fā)的童鞋應該都知道,JavaScript是一門單線程的腳本語言,這就意味著JavaScript 代碼在執(zhí)行的時候,只有一個主線程來執(zhí)行所有的任務,同一個時間只能做同一件事情,這篇文章主要給大家介紹了關于JavaScript事件循環(huán)機制的相關資料,需要的朋友可以參考下
    2022-03-03
  • JavaScript實時更新當前的時間的示例代碼

    JavaScript實時更新當前的時間的示例代碼

    這篇文章主要介紹了JavaScript實時更新當前的時間的示例代碼,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-07-07

最新評論

大悟县| 杂多县| 朝阳县| 九龙县| 土默特右旗| 广宁县| 儋州市| 吉隆县| 沧源| 久治县| 桐庐县| 苍溪县| 金秀| 达尔| 报价| 易门县| 西吉县| 丹棱县| 广州市| 阜阳市| 墨江| 云南省| 三亚市| 万载县| 汪清县| 阿鲁科尔沁旗| 自贡市| 杭州市| 华阴市| 广水市| 定兴县| 永顺县| 土默特右旗| 酉阳| 岳西县| 西城区| 曲周县| 成武县| 闵行区| 五华县| 余庆县|