1. 前言
引用來自:微信小程序開發中的多線程處理與異步編程_微信小程序 多線程-CSDN博客
微信小程序是基于JavaScript開發的,與瀏覽器JavaScript不同,小程序運行在WebView內部,沒有多線程的概念。小程序的 JavaScript 是單線程的,也就是說它只有一個主線程來處理所有的任務,包括用戶交互、網絡請求、動畫等。但是,為了提高性能,小程序提供了一些異步編程的方法,比如使用 Promise、async/await 來處理網絡請求和其他異步操作。
2. 異步編程的實現
2.1 Promise
參考:JavaScript Promise | 菜鳥教程
Promise 是一個 ECMAScript 6 提供的類,目的是更加優雅地書寫復雜的異步任務。?
Promise 構造函數接受一個函數作為參數,該函數是同步的并且會被立即執行,所以我們稱之為起始函數。起始函數包含兩個參數 resolve 和 reject,分別表示 Promise 成功和失敗的狀態。
起始函數執行成功時,它應該調用 resolve 函數并傳遞成功的結果。當起始函數執行失敗時,它應該調用 reject 函數并傳遞失敗的原因。
Promise 構造函數返回一個 Promise 對象,該對象具有以下幾個方法:
- then:用于處理 Promise 成功狀態的回調函數。
- catch:用于處理 Promise 失敗狀態的回調函數。
- finally:無論 Promise 是成功還是失敗,都會執行的回調函數
2.1.1?示例1?Promise返回成功狀態
?先以Promise返回成功狀態為例,先執行“起始函數”,由于返回成功狀態(即使用resolve),會再執行then,再執行finally。
onButton1Clicked(){const promise = new Promise((resolve,reject)=>{setTimeout(()=>{console.log("1秒-第一次打印");resolve();},1000)});promise.then(()=>{console.log("成功")setTimeout(()=>{console.log("2秒-第二次打印");},2000)}).finally(()=>{console.log("最后")});},
打印結果:
我好奇:then是成功才會調用的函數,finally無論成功失敗都會調用,那誰先誰后呢?測試發現誰寫前面先調用誰,比如我這樣寫:
promise.finally(...).then();
?打印結果是這樣的:
?
不過菜鳥教程中說不建議這樣寫,建議:最好按 then-catch-finally 的順序
Q: then、catch 和 finally 序列能否順序顛倒?
A: 可以,效果完全一樣。但不建議這樣做,最好按 then-catch-finally 的順序編寫程序。
2.1.2 示例2? Promise 與網絡請求wx.request 結合使用
onReqAuth() {const request = new Promise((resolve, reject) => {wx.request({url: 'https://www.yourhost.cn/api/',data: {sbxh: 'S20230831-001',ident: 'T01',parm: ''},method: 'POST',success: (res) => {resolve(res.data);},fail: (err) => {reject(err)}})});request.then((data) => {console.log('請求成功', data);// decodeURIComponent:解析URL編碼let msg = decodeURIComponent(data.msg);console.log(msg);this.data.reqResult = msg;this.setData({reqResult: this.data.reqResult})}).catch((err) => {console.error('請求失敗:', err);})},
2.1.3? 示例3 then傳遞值給下一個then
這個示例完全照搬菜鳥教程,
resolve() 中可以放置一個參數用于向下一個 then 傳遞一個值,then 中的函數也可以返回一個值傳遞給 then。但是,如果 then 中返回的是一個 Promise 對象,那么下一個 then 將相當于對這個返回的 Promise 進行操作,這一點從剛才的計時器的例子中可以看出來。
new Promise(function (resolve, reject) {console.log(1111);resolve(2222);
}).then(function (value) {console.log(value);return 3333;
}).then(function (value) {console.log(value);throw "An error";
}).catch(function (err) {console.log(err);
});
注意:
- resolve 和 reject 的作用域只有起始函數,不包括 then 以及其他序列;
- resolve 和 reject 并不能夠使起始函數停止運行,別忘了 return。
?resolve 和 reject 并不能夠使起始函數停止運行,這個我是這樣理解的:在起始函數內調用resolve 或 reject 不代表起始函數結束了,它會繼續執行后面的語句,直到函數結束;然后在起始函數執行完畢后,再去執行對應的成功或失敗后需要操作。比如在示例1的resolve后增加打印,將會打印如下:
2.2 async/await
5.3 ES6 async 函數 | 菜鳥教程
2.2.1?async?異步關鍵詞
async 是 ES7 才有的與異步操作有關的關鍵字。
async 函數返回一個 Promise 對象,可以使用 then 方法添加回調函數。
async function testAsync(){return "testAsync";
}onButton1Clicked(){console.log(testAsync());testAsync().then(v =>{console.log(v);})
}
?
2.2.2 await 操作符
?async 函數中可能會有 await 表達式,async 函數執行時,如果遇到 await 就會先暫停執行 ,等到觸發的異步操作完成后,恢復 async 函數的執行并返回解析值。
await 關鍵字僅在 async function 中有效。
function testAwait(){return new Promise((resolve,reject)=>{console.log("testAwait");setTimeout(()=>{console.log("setTimeout");resolve();},1000);});
}async function helloASync(){await testAwait();console.log("helloASync")
}helloASync();
正常情況下,await 命令后面是一個 Promise 對象,它也可以跟其他值,如字符串,布爾值,數值以及普通函數。
function testAwait(){console.log("testAwait");
}
async function helloAsync(){await testAwait();console.log("helloAsync");
}
helloAsync();
// testAwait
// helloAsync
await針對所跟不同表達式的處理方式:
- Promise 對象:await 會暫停執行,等待?Promise 對象 resolve,然后恢復 async 函數的執行并返回解析值。
- 非 Promise 對象:直接返回對應的值。
?