1. 問(wèn)題場(chǎng)景
完成一個(gè)簡(jiǎn)單的登錄注冊(cè)功能着憨。前端react+后臺(tái)koa2+MySQL數(shù)據(jù)庫(kù)。因?yàn)榈卿浐妥?cè)的業(yè)務(wù)流程差不多臼勉,我就拿登錄舉一個(gè)例子快毛。用戶輸入username和password,將這兩個(gè)參數(shù)通過(guò)get的方式傳遞給后臺(tái)捏雌,后臺(tái)使用router.get方式接受這兩個(gè)參數(shù)跃赚,再查詢數(shù)據(jù)庫(kù)中是否有該用戶相關(guān)信息,有的話返回前臺(tái)登錄成功性湿,沒(méi)有返回前臺(tái)登陸失敗纬傲。
2. 出現(xiàn)問(wèn)題
數(shù)據(jù)庫(kù)查詢connection.query()是異步的。我想要根據(jù)不同的查詢結(jié)果向前臺(tái)返回不同的響應(yīng)肤频,但是因?yàn)楫惒饺蝿?wù)調(diào)皮的特點(diǎn)叹括,還沒(méi)有等到查詢結(jié)果就會(huì)給前臺(tái)返回響應(yīng)(不寫(xiě)響應(yīng)還會(huì)404,就很離譜O摹)
問(wèn)題代碼類似于這樣(原來(lái)的忘了)
module.exports = ctx=>{
var mysql = require('mysql');
var connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'wxb7e2f16d9e113148',
database: 'yhytest'
});
connection.connect();
var a='ini';
var sql = 'SELECT * FROM yhytesttable';
//查詢數(shù)據(jù)庫(kù)
connection.query(sql, function (err, result) {
if (err) {
a = err.message;
return;
}
a = result["0"].name;
});
ctx.state.data = {
msg: a
}
}
為了解決這個(gè)問(wèn)題引出promise和await
3. promise
promise類似于一個(gè)容器汁雷,里面裝著一個(gè)異步任務(wù)净嘀,利用promise可以獲取異步任務(wù)的信息。
new Promise((resolve,reject)=>{
// 里面是一個(gè)異步任務(wù)
resolve()摔竿;// 異步任務(wù)成功了進(jìn)行它
reject()面粮;// 異步任務(wù)失敗了進(jìn)行它
});
Promise的構(gòu)造函數(shù)里直接傳入了一個(gè)function,我們可以稱呼它為executor继低,它有兩個(gè)函數(shù)參數(shù)resolve熬苍,reject。當(dāng)上面這行語(yǔ)句執(zhí)行的時(shí)候袁翁,executor會(huì)立即異步執(zhí)行柴底。在executor方法的方法體內(nèi),你可以寫(xiě)你自己的代碼邏輯粱胜,你可以在代碼的正常執(zhí)行邏輯里調(diào)用resolve(retValue)來(lái)把Promise的status改為resolved柄驻,表示任務(wù)執(zhí)行成功;在出錯(cuò)異常處理的代碼里調(diào)用reject(err)來(lái)把Promise的status改為rejected焙压,表示任務(wù)執(zhí)行失敗鸿脓。也就是說(shuō),executor函數(shù)的執(zhí)行成功還是失敗涯曲,是可以從Promise的狀態(tài)里判斷出來(lái)的野哭。這里要注意兩點(diǎn):
- Promise從pending狀態(tài)改為resolved或rejected狀態(tài)只會(huì)有一次,一旦變成resolve或rejected之后幻件,這個(gè)Promise的狀態(tài)就再也不會(huì)改變了拨黔。
- 通過(guò)resolve(retValue)傳入的retValue可以是任何值,null也可以绰沥,它會(huì)傳遞給后面的then方法里的function去使用篱蝇。通過(guò)rejected(err)傳入的err理論上也是沒(méi)有限制類型的,但我們一般都會(huì)傳入一個(gè)Error徽曲,比如reject(new Error(“Error”))零截。promise的狀態(tài)可以影響后面then的執(zhí)行。
new Promise((resolve,reject)=>{
resolve(value);
reject(error);
}).then((value)=>{
return 一個(gè)promise實(shí)例秃臣;
})
內(nèi)容參考:淺析JS中的 promise+await/async
4. async/await
async/await使得異步代碼看起來(lái)像同步代碼瞻润,但是改變不了JS單線程、異步的本質(zhì)甜刻。await就是等一等嗎绍撞,等等await后面的異步任務(wù)執(zhí)行完成之后,再進(jìn)行它之后的代碼的運(yùn)行得院。
用法:
- 使用await傻铣,函數(shù)必須用async標(biāo)識(shí)
- await后面跟的是一個(gè)Promise實(shí)例
// user.js
function userLogin(name, password) {
// 處理異步任務(wù)返回的results
return new Promise((resolve, reject) => {});
}
// index.js
router.get("/login", async (req, res) => {
var name = req.query.userName;
var pwd = req.query.userPwd;
// await處理異步任務(wù)results,根據(jù)不同results情況向前臺(tái)返回不同響應(yīng)
let results = await userLogin(name, pwd);
if (results.length == 1) {
req.body = "登陸成功祥绞!";
} else {
req.body = "登陸失敺侵蕖鸭限!請(qǐng)重新登陸!";
}
});
index.js中的await就會(huì)讓userLogin執(zhí)行两踏,而不是不等執(zhí)行直接進(jìn)行req.body
內(nèi)容參考:異步解決方案----Promise與Await
先寫(xiě)到這败京,想起來(lái)別的了繼續(xù)寫(xiě)...