异步加载
異步加載
1、promise基礎實例
<script> $(function(){function myAsync(url,data,type){return new Promise((resolve,reject) => {let requestObj;if(window.XMLHttpRequest){requestObj = new XMLHttpRequest();}else{requestObj = new ActiveXObject();}let sendData = "";if(type == "POST"){//將json對象轉換為字符串sendData = JSON.stringify(data);}//參數true表示異步處理requestObj.open(type,url,true);requestObj.send(sendData);requestObj.onreadystatechange = () => {//readyState == 4,相應內容解析完成if(requestObj.readyState == 4){// 服務器成功處理請求if(requestObj.status == 200){let obj = requestObj.response;if( typeof obj !== 'object'){obj = JSON.parse(obj)}resolve(obj)}else{reject(obj)}}}})}$("#btn").on("click",()=>{myAsync("http://jsonplaceholder.typicode.com/posts","GET").then((rsp) => { console.log("成功!",rsp)}).catch((error)=>{console.log(error)})}); }); </script>2、Promise.all方法可以接收多個 promise 作為參數,以數組的形式,當這些 promise 都成功執行完成后才調用回調函數。
var request1 = fetch('/users.json'); var request2 = fetch('/articles.json');Promise.all([request1, request2]).then(function(results) { });3、Promise.race是在所有的 promise 中只要有一個執行結束,它就會觸發。
var req1 = new Promise(function(resolve, reject) {setTimeout(function() { resolve('First!'); }, 8000); }); var req2 = new Promise(function(resolve, reject) { setTimeout(function() { resolve('Second!'); }, 3000); }); Promise.race([req1, req2]).then(function(one) {console.log('Then: ', one); }).catch(function(one, two) {console.log('Catch: ', one); });3、async 和 await
以下內容摘自:邊城的《理解 JavaScript 的 async/await》原文地址:https://segmentfault.com/a/11...
(1)、介紹
async 是“異步”的簡寫,而 await 可以認為是 async wait 的簡寫。async 用于申明一個 function 是異步的,而 await 用于等待一個異步方法執行完成。await 只能出現在 async 函數中。
(2)、async 起什么作用
這個問題的關鍵在于,async 函數是怎么處理它的返回值的!我們當然希望它能直接通過 return 語句返回我們想要的值,但是如果真是這樣,似乎就沒 await 什么事了。所以,寫段代碼來試試,看它到底會返回什么:
async function testAsync() {return "hello async"; }const result = testAsync(); console.log(result);輸出的是一個 Promise 對象:
Promise { 'hello async' }所以,async 函數返回的是一個 Promise 對象。async 函數(包含函數語句、函數表達式、Lambda表達式)會返回一個 Promise 對象,如果在函數中 return 一個直接量,async 會把這個直接量通過 Promise.resolve() 封裝成 Promise 對象。使用.then() 鏈來處理這個 Promise 對象,
testAsync().then(v => {console.log(v); // 輸出 hello async });現在回過頭來想下,如果 async 函數沒有返回值,它會返回 Promise.resolve(undefined)。
聯想一下 Promise 的特點——無等待,所以在沒有 await 的情況下執行 async 函數,它會立即執行,返回一個 Promise 對象,并且,絕不會阻塞后面的語句。這和普通返回 Promise 對象的函數并無二致。
(3)、await 到底在等啥
一般來說,都認為 await 是在等待一個 async 函數完成。不過按語法說明,await 等待的是一個表達式,這個表達式的計算結果是 Promise 對象或者其它值(換句話說,就是沒有特殊限定)。
因為 async 函數返回一個 Promise 對象,所以 await 可以用于等待一個 async 函數的返回值——這也可以說是 await 在等 async 函數,但要清楚,它等的實際是一個返回值。注意到 await 不僅僅用于等 Promise 對象,它可以等任意表達式的結果,所以,await 后面實際是可以接普通函數調用或者直接量的。所以下面這個示例完全可以正確運行
function getSomething() {return "something"; }async function testAsync() {return Promise.resolve("hello async"); }async function test() {const v1 = await getSomething();const v2 = await testAsync();console.log(v1, v2); }test();如果它等到的不是一個 Promise 對象,那 await 表達式的運算結果就是它等到的東西。
如果它等到的是一個 Promise 對象,await 就忙起來了,它會阻塞后面的代碼,等著 Promise 對象 resolve,然后得到 resolve 的值,作為 await 表達式的運算結果。
看到上面的阻塞一詞,心慌了吧……放心,這就是 await 必須用在 async 函數中的原因。async 函數調用不會造成阻塞,它內部所有的阻塞都被封裝在一個 Promise 對象中異步執行。(5)、async/await 幫我們干了啥
作個簡單的比較:上面已經說明了 async 會將其后的函數(函數表達式或 Lambda)的返回值封裝成一個 Promise 對象,而 await 會等待這個 Promise 完成,并將其 resolve 的結果返回出來。
現在舉例,用 setTimeout 模擬耗時的異步操作,先來不用 async/await:
function takeLongTime() {return new Promise(resolve => {setTimeout(() => resolve("long_time_value"), 1000);}); }takeLongTime().then(v => {console.log("got", v); });如果改用 async/await :
function takeLongTime() {return new Promise(resolve => {setTimeout(() => resolve("long_time_value"), 1000);}); }async function test() {const v = await takeLongTime();console.log(v); }test();眼尖的同學已經發現 takeLongTime() 沒有申明為 async。實際上,takeLongTime() 本身就是返回的 Promise 對象,加不加 async 結果都一樣,如果沒明白,請回過頭再去看看上面的“async 起什么作用”。
(6)、對比之后,async/await的優勢到底在哪?
async/await 的優勢在于處理 then 鏈
單一的 Promise 鏈并不能發現 async/await 的優勢,但是,如果需要處理由多個 Promise 組成的 then 鏈的時候,優勢就能體現出來了(很有意思,Promise 通過 then 鏈來解決多層回調的問題,現在又用 async/await 來進一步優化它)。
假設一個業務,分多個步驟完成,每個步驟都是異步的,而且依賴于上一個步驟的結果。我們仍然用 setTimeout 來模擬異步操作:
/*** 傳入參數 n,表示這個函數執行的時間(毫秒)* 執行的結果是 n + 200,這個值將用于下一步驟*/ function takeLongTime(n) {return new Promise(resolve => {setTimeout(() => resolve(n + 200), n);}); }function step1(n) {console.log(`step1 with ${n}`);return takeLongTime(n); }function step2(n) {console.log(`step2 with ${n}`);return takeLongTime(n); }function step3(n) {console.log(`step3 with ${n}`);return takeLongTime(n); } 現在用 Promise 方式來實現這三個步驟的處理function doIt() {console.time("doIt");const time1 = 300;step1(time1).then(time2 => step2(time2)).then(time3 => step3(time3)).then(result => {console.log(`result is ${result}`);console.timeEnd("doIt");}); }doIt();// c:\var\test>node --harmony_async_await . // step1 with 300 // step2 with 500 // step3 with 700 // result is 900 // doIt: 1507.251ms輸出結果 result 是 step3() 的參數 700 + 200 = 900。doIt() 順序執行了三個步驟,一共用了 300 + 500 + 700 = 1500 毫秒,和 console.time()/console.timeEnd() 計算的結果一致。
如果用 async/await 來實現呢,會是這樣
async function doIt() {console.time("doIt");const time1 = 300;const time2 = await step1(time1);const time3 = await step2(time2);const result = await step3(time3);console.log(`result is ${result}`);console.timeEnd("doIt"); }doIt();結果和之前的 Promise 實現是一樣的,但是這個代碼看起來是不是清晰得多,幾乎跟同步代碼一樣
(7)、現在把業務要求改一下,仍然是三個步驟,但每一個步驟都需要之前每個步驟的結果。
function step1(n) {console.log(`step1 with ${n}`);return takeLongTime(n); }function step2(m, n) {console.log(`step2 with ${m} and ${n}`);return takeLongTime(m + n); }function step3(k, m, n) {console.log(`step3 with ${k}, ${m} and ${n}`);return takeLongTime(k + m + n); }這回先用 async/await 來寫:
async function doIt() {console.time("doIt");const time1 = 300;const time2 = await step1(time1);const time3 = await step2(time1, time2);const result = await step3(time1, time2, time3);console.log(`result is ${result}`);console.timeEnd("doIt"); }doIt();// c:\var\test>node --harmony_async_await . // step1 with 300 // step2 with 800 = 300 + 500 // step3 with 1800 = 300 + 500 + 1000 // result is 2000 // doIt: 2907.387ms除了覺得執行時間變長了之外,似乎和之前的示例沒啥區別啊!別急,認真想想如果把它寫成 Promise 方式實現會是什么樣子?
function doIt() {console.time("doIt");const time1 = 300;step1(time1).then(time2 => {return step2(time1, time2).then(time3 => [time1, time2, time3]);}).then(times => {const [time1, time2, time3] = times;return step3(time1, time2, time3);}).then(result => {console.log(`result is ${result}`);console.timeEnd("doIt");}); }doIt();有沒有感覺有點復雜的樣子?那一堆參數處理,就是 Promise 方案的死穴—— 參數傳遞太麻煩了,看著就暈!
總結
- 上一篇: HttpClient库设置超时
- 下一篇: 计算机基本概念及简单的二进制运算