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