摘要:前言在前端異步請(qǐng)求中,要獲取數(shù)據(jù),傳統(tǒng)的寫(xiě)法是回調(diào),但這種方法不利于代碼的維護(hù)和可讀性,所以時(shí)代通過(guò)和解決了這種問(wèn)題,更是通過(guò)和使其更加簡(jiǎn)潔通過(guò)替代回調(diào)嵌套的特點(diǎn)是初始化后,調(diào)用一次方法會(huì)暫停在關(guān)鍵字前,同時(shí)也可以在方法里傳值,使對(duì)應(yīng)的語(yǔ)句
前言
在前端異步請(qǐng)求中,要獲取數(shù)據(jù),傳統(tǒng)的寫(xiě)法是ajax回調(diào),但這種方法
不利于代碼的維護(hù)和可讀性,所以es6時(shí)代通過(guò)Generator和Promise解決了這種問(wèn)題,es7更是通過(guò)async和await使其更加簡(jiǎn)潔
Generator的特點(diǎn)是初始化后,調(diào)用一次next方法會(huì)暫停在yield關(guān)鍵字前,同時(shí)也可以在next方法里傳值,使對(duì)應(yīng)的yield語(yǔ)句獲取到
首先編寫(xiě)準(zhǔn)備代碼
const axios = require("axios") const http = axios.create({ baseURL: "http://127.0.0.1:89", timeout: 3000, headers: {"Accept": "application/json"} }); let it;
定義的it是迭代器的意思,現(xiàn)在還沒(méi)有值
異步請(qǐng)求調(diào)用方法
function call(url,options={}) { setTimeout(()=>{ if ( !it ) { throw new Error("請(qǐng)初始化生成器") } http(url,options) .then(v=>{ it.next(v.data) // 生成器傳遞參數(shù),并且啟動(dòng)下一次執(zhí)行 }) },0) }
用setTimeout包裹,是確保這段代碼是異步執(zhí)行,如果不加,同步執(zhí)行的it判斷可能會(huì)拋出異常
編寫(xiě)生成器,這里是主要的異步請(qǐng)求邏輯處理
/** 多個(gè)請(qǐng)求互相依賴 1. 根據(jù)用戶名,密碼獲取用戶憑證 2. 根據(jù)用戶憑證獲取用戶數(shù)據(jù)id列表 3. 獲取數(shù)據(jù)列表中第一條數(shù)據(jù)詳情 */ function * getData() { const data1 = yield call("/login", { method: "POST", data: JSON.stringify({user:"root",pass:"123456"}) }) console.log("我是結(jié)果1:",data1) const data2 = yield call("/list", { method: "POST", headers: { token: data1.data.token } }) console.log("我是結(jié)果2:",data2) const data3 = yield call("/item", { method: "POST", headers: { token: data1.data.token }, data: JSON.stringify({ id:data2.data.ids[0] }) }) console.log("我是結(jié)果3:",data3) }
調(diào)用,運(yùn)行
it = getData() it.next()
這里給it附上值,然后會(huì)觸發(fā)第2步的代碼
首先我們定義了生成器,運(yùn)行它的時(shí)候,只需執(zhí)行it.netx,然后會(huì)運(yùn)行第一個(gè)yield后面的語(yǔ)句,并停在第一個(gè)yield語(yǔ)句處,當(dāng)call函數(shù)里的異步請(qǐng)求執(zhí)行完畢,會(huì)將異步請(qǐng)求的結(jié)果it.next(data)傳遞給第一個(gè)yield前面的取值語(yǔ)句,然后會(huì)執(zhí)行到第二個(gè)yield語(yǔ)句后面的call,以此類推,直到整個(gè)生成器執(zhí)行完畢
Generator + Promise單個(gè)通過(guò)Generator已經(jīng)可以解決大部分異步嵌套的問(wèn)題,但是不夠完善,要確保it初始化,必須讓整個(gè)call異步執(zhí)行,代碼不夠優(yōu)雅,而且依賴外部it,結(jié)構(gòu)分散,所以我們用Generator + Promise可以進(jìn)一步完善
簡(jiǎn)化call方法
function call(url,options={}) { return http(url,options) }
去掉在call里執(zhí)行it.next
增加外部調(diào)用生成器next函數(shù)run
function run (g) { const it = g(); // 初始化生成器, 注意這里的冒號(hào) (function each(res) { // 根據(jù)生成器的返回結(jié)果進(jìn)行判斷 if (!res.done && res.value instanceof Promise ) { // 如果是Promise返回 res.value.then(v=>{ each( it.next(v.data) ) // 這里是方案一的call里的next并傳值到下一次next }) } else if (res.done) { // 生成器執(zhí)行結(jié)束, 運(yùn)行結(jié)束 return } else { throw new Error("yield 后面請(qǐng)用返回Promise的函數(shù)") } })(it.next()) //自運(yùn)行 }
運(yùn)行
run(getData)
運(yùn)行方法一中的getData生成器,得到的結(jié)果一樣
getData里yield后的函數(shù)擴(kuò)展
根據(jù)run函數(shù)可知,只要it.next返回的結(jié)果是Promise即可正常運(yùn)行,那么在getData里如下寫(xiě)法也是可以的
function * getData() { const data1 = yield http("/login", { method: "POST", data: JSON.stringify({user:"root",pass:"123456"}) }) console.log("我是結(jié)果1:",data1) const data2 = yield http("/list", { method: "POST", headers: { token: data1.data.token } }) console.log("我是結(jié)果2:",data2) const data3 = yield http("/item", { method: "POST", headers: { token: data1.data.token }, data: JSON.stringify({ id:data2.data.ids[0] }) }) console.log("我是結(jié)果3:",data3) }
**這里的http函數(shù)是axios的一個(gè)實(shí)例,返回值為Promise,
外層加call是可以在call里寫(xiě)一些異常,或者測(cè)試處理,類似React的dva處理方式**
如果你覺(jué)得方案二還是有些繁瑣,那么可以試試ES7的await語(yǔ)法
改造getData函數(shù)如下
/** 多個(gè)請(qǐng)求互相依賴 1. 根據(jù)用戶名,密碼獲取用戶憑證 2. 根據(jù)用戶憑證獲取用戶數(shù)據(jù)id列表 3. 獲取數(shù)據(jù)列表中第一條數(shù)據(jù)詳情 */ async function getData() { const { data:data1 } = await call("/login", { method: "POST", data: JSON.stringify({user:"root",pass:"123456"}) }) console.log("我是結(jié)果1:",data1) const { data:data2 } = await call("/list", { method: "POST", headers: { token: data1.data.token } }) console.log("我是結(jié)果2:",data2) const { data:data3 } = await call("/item", { method: "POST", headers: { token: data1.data.token }, data: JSON.stringify({ id:data2.data.ids[0] }) }) console.log("我是結(jié)果3:",data3) }
和方案二比較這個(gè)方法頭部多了async關(guān)鍵字,去掉了*號(hào),yield換成了await,這是ES7異步函數(shù)的聲明方式。
注意返回值不是通過(guò)方案二中next res.data注入,所以獲取到的是整個(gè)res,取值的時(shí)候注意拿結(jié)果里的.data數(shù)據(jù)
運(yùn)行
getData()
結(jié)果和方案一二一樣,這種方式更加簡(jiǎn)潔易懂
方案三簡(jiǎn)單完整代碼個(gè)人比較喜歡簡(jiǎn)潔有效的代碼,所以推薦方案三
const axios = require("axios") const http = axios.create({ baseURL: "http://127.0.0.1:89", timeout: 3000, headers: {"Accept": "application/json"} }); /** 多個(gè)請(qǐng)求互相依賴 1. 根據(jù)用戶名,密碼獲取用戶憑證 2. 根據(jù)用戶憑證獲取用戶數(shù)據(jù)id列表 3. 獲取數(shù)據(jù)列表中第一條數(shù)據(jù)詳情 */ async function getData() { const { data:data1 } = await http("/login", { method: "POST", data: JSON.stringify({user:"root",pass:"123456"}) }) console.log("我是結(jié)果1:",data1) const { data:data2 } = await http("/list", { method: "POST", headers: { token: data1.data.token } }) console.log("我是結(jié)果2:",data2) const { data:data3 } = await http("/item", { method: "POST", headers: { token: data1.data.token }, data: JSON.stringify({ id:data2.data.ids[0] }) }) console.log("我是結(jié)果3:",data3) } getData() //運(yùn)行
以上代碼僅完成了核心功能,一些防御性和異常處理不完善,僅供理解和學(xué)習(xí)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/106585.html
摘要:如果你把函數(shù)的指針地址作為參數(shù)傳遞給另一個(gè)函數(shù),當(dāng)這個(gè)指針被用來(lái)調(diào)用其所指向的函數(shù)時(shí),我們就說(shuō)這是回調(diào)函數(shù)?;卣{(diào)函數(shù)不是由該函數(shù)的實(shí)現(xiàn)方直接調(diào)用,而是在特定的事件或條件發(fā)生時(shí)由另外的一方調(diào)用的,用于對(duì)該事件或條件進(jìn)行響應(yīng)。 同期異步系列文章推薦談一談javascript異步j(luò)avascript異步與promisejavascript異步之Promise.all()、Promise.ra...
摘要:我的博客大家都知道解決了回調(diào)地獄的問(wèn)題。這就是異步的嵌套帶來(lái)的可讀性的問(wèn)題,它是由異步的運(yùn)行機(jī)制引起的。在與第三方團(tuán)隊(duì)溝通之后問(wèn)題得到了解決。這不但使代碼變得臃腫不堪,還進(jìn)一步加劇了可讀性的問(wèn)題。的特征保證了可以解決信任問(wèn)題。 我的github博客 https://github.com/zhuanyongxigua/blog 大家都知道Promise解決了回調(diào)地獄的問(wèn)題。說(shuō)到回調(diào)地獄,...
摘要:從源碼看概念與實(shí)現(xiàn)是異步編程中的重要概念,它較好地解決了異步任務(wù)中回調(diào)嵌套的問(wèn)題。這些概念中有趣的地方在于,標(biāo)識(shí)狀態(tài)的變量如都是形容詞,用于傳入數(shù)據(jù)的接口如與都是動(dòng)詞,而用于傳入回調(diào)函數(shù)的接口如及則在語(yǔ)義上用于修飾動(dòng)詞的副詞。 從源碼看 Promise 概念與實(shí)現(xiàn) Promise 是 JS 異步編程中的重要概念,它較好地解決了異步任務(wù)中回調(diào)嵌套的問(wèn)題。在沒(méi)有引入新的語(yǔ)言機(jī)制的前提下,這...
摘要:異步請(qǐng)求線程在在連接后是通過(guò)瀏覽器新開(kāi)一個(gè)線程請(qǐng)求將檢測(cè)到狀態(tài)變更時(shí),如果設(shè)置有回調(diào)函數(shù),異步線程就產(chǎn)生狀態(tài)變更事件,將這個(gè)回調(diào)再放入事件循環(huán)隊(duì)列中。 基礎(chǔ):瀏覽器 -- 多進(jìn)程,每個(gè)tab頁(yè)獨(dú)立一個(gè)瀏覽器渲染進(jìn)程(瀏覽器內(nèi)核) 每個(gè)瀏覽器渲染進(jìn)程是多線程的,主要包括:GUI渲染線程 JS引擎線程 也稱為JS內(nèi)核,負(fù)責(zé)處理Javascript腳本程序。(例如V8引擎) JS引擎線程負(fù)...
摘要:引擎線程也稱為內(nèi)核,負(fù)責(zé)處理腳本程序例如引擎引擎線程負(fù)責(zé)解析腳本,運(yùn)行代碼。對(duì)象代表一個(gè)未完成但預(yù)計(jì)將來(lái)會(huì)完成的操作。注意一旦新建就會(huì)立即執(zhí)行它屬于,無(wú)法取消。 寫(xiě)在前面: 第一遍學(xué)Promise時(shí), 只是大概過(guò)了一遍, 感覺(jué)學(xué)的不夠深入, 這一篇算是對(duì)之前的一個(gè)總結(jié)吧. Promise在ES6中也屬于一個(gè)較難理解的一部分; 所以在學(xué)習(xí)一個(gè)比較難理解的知識(shí)點(diǎn)時(shí), 我們可以圍繞這個(gè)知識(shí)點(diǎn)...
閱讀 1426·2023-04-25 23:47
閱讀 985·2021-11-23 09:51
閱讀 4727·2021-09-26 10:17
閱讀 3796·2021-09-10 11:19
閱讀 3316·2021-09-06 15:10
閱讀 3602·2019-08-30 12:49
閱讀 2499·2019-08-29 13:20
閱讀 1787·2019-08-28 18:14