JavaScript中Promise的使用方法實例
前言
我還記得我剛開始學(xué)習(xí)JavaScript的Promise很多概念都不懂很"懵逼", 現(xiàn)在已經(jīng)工作有小半年時間了, 整理整理筆記和個人在工作中的使用情況, 寫個文章記錄一下(PS只記錄怎么使用, 原理太深奧功力不夠), 如果有不對的地方前輩勿噴??
Promise簡介
Promise也稱期約, 是ES6推出的一個異步解決方案, 可以有效的解決異步函數(shù)嵌套太深("回調(diào)地獄")的問題
什么是回調(diào)地獄?
假設(shè)有個需求需要獲取用戶的指定數(shù)據(jù)用戶數(shù)據(jù)3這個數(shù)據(jù)依賴用戶數(shù)據(jù)2而用戶數(shù)據(jù)2又依賴于用戶數(shù)據(jù)1, 所以正確的數(shù)據(jù)獲取數(shù)據(jù)順序為: 用戶數(shù)據(jù)1-->用戶數(shù)據(jù)2-->用戶數(shù)據(jù)3, 模擬一下使用回調(diào)函數(shù)的寫法如下:
Node接口:
const router = require('express').Router(); const data1 = { data: "用戶數(shù)據(jù)1" }; router.get('/testData1', (req, res) => { res.json(data1); }) const data2 = { data: "用戶數(shù)據(jù)1,用戶數(shù)據(jù)2" }; router.get('/testData2', (req, res) => { if (req.query.data === data1.data) { res.json(data2); } else { res.status(401).json("參數(shù)錯誤"); } }) router.get('/testData3', (req, res) => { if (req.query.data === data2.data) { res.json({ data: "用戶數(shù)據(jù)1,用戶數(shù)據(jù)2,用戶數(shù)據(jù)3" }); } else { res.status(401).json("參數(shù)錯誤"); } }) module.exports = router;
前端請求代碼:
// 簡單封裝的 XMLHttpRequest 請求函數(shù) const baseUrl = "http://localhost:8888/test"; const request = (url, cb) => { const xhr = new XMLHttpRequest(); xhr.open('GET', baseUrl + url); xhr.send(); xhr.onreadystatechange = () => { const { readyState, status, response } = xhr; if (readyState === 4) { if (status >= 200 && status <= 299) { cb(JSON.parse(response)); } else { throw new Error(response); } } } } // 因為下一個請求需要上一個請求的數(shù)據(jù)所以需要一個回調(diào)函數(shù)嵌套一個回調(diào)函數(shù) request("/testData1", res1 => { console.log(res1); // => {data: '用戶數(shù)據(jù)1'} request(`/testData2?data=${res1.data}`, res2 => { console.log(res2); // => {data: '用戶數(shù)據(jù)1,用戶數(shù)據(jù)2'} request(`/testData3?data=${res2.data}`, res3 => { console.log("需求需要的數(shù)據(jù)", res3); // => 需求需要的數(shù)據(jù) {data: '用戶數(shù)據(jù)1,用戶數(shù)據(jù)2,用戶數(shù)據(jù)3'} // .... }) }) })
這個代碼看著就頭大, 如果需求復(fù)雜的話, 我只能用一張圖表示(這張圖片我也不記得從哪里保存的忘了??)
這種一個回調(diào)嵌套一個回調(diào)的代碼可讀性和可維護(hù)性都很差, 被稱為"回調(diào)地獄", 而Promise的出現(xiàn)就可以很好的解決這個問題
Promise的特點(diǎn)
Promise對象有一個狀態(tài), 這個狀態(tài)不受外界影響, 狀態(tài)一共分為3種:
- Pending狀態(tài) (進(jìn)行中(又稱待定)) 初始狀態(tài)
- Fulfilled狀態(tài) (成功(又稱兌現(xiàn)))
- Rejected狀態(tài)(失敗(又稱拒絕))
關(guān)于Promise的狀態(tài)叫法下文統(tǒng)一使用成功,失敗
一旦Promise對象的狀態(tài)改變(成功或失敗)就不會再變, 是單向的:
Pending(進(jìn)行中) -> Fulfilled(成功)
Pending(進(jìn)行中) -> Rejected(失敗)
創(chuàng)建Promise實例
創(chuàng)建Promise實例需要newPromise構(gòu)造函數(shù), 該構(gòu)造函數(shù)接受一個函數(shù)(處理器函數(shù))作為參數(shù), 該函數(shù)會收到兩個參數(shù), 這兩個參數(shù)分別是resolve和reject(叫什么都行一般還是要語義化名稱)它們是兩個函數(shù), 不用自己實現(xiàn)就可以使用, 如下:
const p = new Promise((resolve, reject) => { }) console.log(p);
可以看到這個狀態(tài)默認(rèn)是Pending(進(jìn)行中)
resolve和reject這兩個參數(shù)(函數(shù))可以在處理器函數(shù)里面調(diào)用(可以傳遞參數(shù)), 這樣將會改變 Promise 對象的狀態(tài):
const p = new Promise((resolve, reject) => { resolve(); }) console.log(p);
當(dāng)調(diào)用resolve函數(shù)時會將Priomise對象的狀態(tài)修改為Fulfilled(成功), 調(diào)用reject函數(shù)則會將狀態(tài)修改為Rejected(失敗)
then方法
Promise實例的then方法, 可以接受兩個參數(shù)(都是函數(shù))分別指定Primise實例里面狀態(tài)(成功或失敗)改變時調(diào)用的回調(diào)函數(shù)(并且Promise的then方法是異步的微任務(wù)):
const p = new Promise((resolve, reject) => { // 將p的狀態(tài)修改為成功 resolve(); }) console.log("同步代碼"); p.then( () => { console.log("成功的回調(diào)"); }, () => { console.log("失敗的回調(diào)"); } )
結(jié)果如下:
反之調(diào)用reject函數(shù)就會觸發(fā)then方法的第二個回調(diào)函數(shù), 如果將resolve函數(shù)和reject函數(shù)都調(diào)用只會生效最先調(diào)用的(因為狀態(tài)時單向的嘛)
resolve 和 reject 的參數(shù)傳遞
經(jīng)過上面的測試我們知道resolve和reject這兩個函數(shù)是可以修改狀態(tài)并且觸發(fā)Promise的then方法的回調(diào)函數(shù)的, 那么是函數(shù)就可以傳遞參數(shù), 這個參數(shù)會被傳遞給對應(yīng)的then方法的回調(diào)函數(shù)接收到:
const p = new Promise((resolve, reject) => { // 將p的狀態(tài)修改為成功, 并且傳遞一個參數(shù) resolve("ok"); }) console.log("同步代碼"); p.then( // 這里接收 resolve 函數(shù)傳遞的參數(shù) res => { console.log("成功的回調(diào)", res); }, // 這里接收 reject 函數(shù)傳遞的參數(shù) err => { console.log("失敗的回調(diào)"); } )
結(jié)果如下:
then()鏈?zhǔn)秸{(diào)用
了解完then方法以后我們就可以稍微修改一下一開始最上面的需求:
// 請求函數(shù)使用 Promise 封裝 const baseUrl = "http://localhost:8888/test"; const request = (url) => { // 返回一個Promise實例 return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('GET', baseUrl + url); xhr.send(); xhr.onreadystatechange = () => { const { readyState, status, response } = xhr; if (readyState === 4) { if (status >= 200 && status <= 299) { const res = JSON.parse(response); // 修改狀態(tài)為成功并且把響應(yīng)傳遞過去 resolve(res); } else { // 修改狀態(tài)為失敗也把響應(yīng)傳遞過去 reject(response); } } } }) } // 使用then方法 request("/testData1").then( res1 => { console.log(res1); // {data: '用戶數(shù)據(jù)1'} request(`/testData2?data=${res1.data}`).then( res2 => { console.log(res2); // {data: '用戶數(shù)據(jù)1,用戶數(shù)據(jù)2'} request(`/testData3?data=${res2.data}`).then( res3 => { console.log("需求需要的數(shù)據(jù)", res3); // => 需求需要的數(shù)據(jù) {data: '用戶數(shù)據(jù)1,用戶數(shù)據(jù)2,用戶數(shù)據(jù)3'} } ) } ) } )
寫完以后發(fā)現(xiàn)好像還不如使用回調(diào)函數(shù)的方式寫, 看到這里好像Promise還是不能很好的解決回調(diào)嵌套的問題; 換個思路如果我們在then方法中再返回一個Promise實例, 那么不就又可以調(diào)用then方法了嗎? 代碼中測試一下:
const p1 = new Promise((resolve, reject) => { resolve("p1數(shù)據(jù)"); }) // 這里的p2就是p1.then方法成功回調(diào)里面返回的p2 const p2 = p1.then( // 這里的res1參數(shù)就是p1的處理器函數(shù)中調(diào)用 resolve("p1數(shù)據(jù)") 傳遞的參數(shù) res1 => { console.log(res1); // p1數(shù)據(jù) // 這里新建一個新的Promise實例, 記作p2 const p2 = new Promise((resolve, reject) => { // 0.5s后修改狀態(tài) setTimeout(() => { resolve(res1 + ",p2數(shù)據(jù)"); }, 500); }) // 將p2返回 return p2; } ) const p3 = p2.then( res2 => { console.log(res2); // p1數(shù)據(jù),p2數(shù)據(jù) // 這里和上面的同理 const p3 = new Promise((resolve, reject) => { setTimeout(() => { resolve(res2 + ",p3數(shù)據(jù)"); }, 500); }) return p3; } ) p3.then( res3 => { console.log(res3); // p1數(shù)據(jù),p2數(shù)據(jù),p3數(shù)據(jù) } )
發(fā)現(xiàn)可行后, 把需求代碼再修改一下:
// 這里的p1就是 request("/testData1") 返回的Promise實例 const p1 = request("/testData1"); // 這里的p2就是p1.then方法成功回調(diào)返回的p2 const p2 = p1.then( res1 => { console.log(res1); // {data: '用戶數(shù)據(jù)1'} // 再調(diào)用request方法將其返回的Promise實例記作p2 const p2 = request(`/testData2?data=${res1.data}`); // 將p2返回 return p2; } ) const p3 = p2.then( res2 => { console.log(res2); // {data: '用戶數(shù)據(jù)1,用戶數(shù)據(jù)2'} // 這里和上面的同理 const p3 = request(`/testData3?data=${res2.data}`); return p3; } ) p3.then( res3 => { console.log("需求需要的數(shù)據(jù)", res3); // 需求需要的數(shù)據(jù) {data: '用戶數(shù)據(jù)1,用戶數(shù)據(jù)2,用戶數(shù)據(jù)3'} } )
需求實現(xiàn)是實現(xiàn)了, 就是代碼有點(diǎn)冗余, 可以精簡一下, 如下:
request("/testData1").then( res1 => { console.log(res1); // {data: '用戶數(shù)據(jù)1'} // 這里直接返回 request方法的返回值Promise實例 return request(`/testData2?data=${res1.data}`); } ).then( // 這個成功回調(diào)時上一個then方法返回的Promise實例的成功回調(diào) res2 => { console.log(res2); // {data: '用戶數(shù)據(jù)1,用戶數(shù)據(jù)2'} // 同理 return request(`/testData3?data=${res2.data}`); } ).then( // 同理 res3 => { console.log("需求需要的數(shù)據(jù)", res3); // 需求需要的數(shù)據(jù) {data: '用戶數(shù)據(jù)1,用戶數(shù)據(jù)2,用戶數(shù)據(jù)3'} } )
上面的代碼格式就像鏈條一樣所以又被稱為"鏈?zhǔn)秸{(diào)用"
then()的返回值
經(jīng)過上面的代碼測試, then方法除了返回Promise對象外還可以返回其他任意的值, 返回會被轉(zhuǎn)換為Promise對象, 內(nèi)部的狀態(tài)視返回值而定:
const p1 = new Promise(resolve => resolve()); p1.then(() => { // 這里相當(dāng)于是 return undefined }).then( res1 => { console.log(res1); // undefined return "hello"; } ).then( res2 => { console.log(res2); // hello return { name: "張三" }; } ).then( res3 => { console.log(res3); // { name: "張三" } // 返回錯誤對象該P(yáng)romise對象的狀態(tài)也是成功 return new Error("error object"); } ).then( res4 => { console.log(res4 instanceof Error); // true console.log(res4.message); // error object // 拋出一個錯誤則該P(yáng)romise對象的狀態(tài)是失敗 throw "thorw error"; } ).then( () => { }, err => { console.log(err); // thorw error } )
catch方法
上面使用then方法的鏈?zhǔn)秸{(diào)用可以解決回調(diào)嵌套太深的問題, 但是還沒處理請求之間的失敗回調(diào)處理, then方法的第二個回調(diào)就是指定失敗的回調(diào), 但是一般都不使用這個回調(diào)來處理錯誤, 而是使用catch方法來失敗, 使用格式如下:
p1.then( // ... ).then( // ... ).catch(err => { // 這個catch可以捕獲這一條調(diào)用鏈上的錯誤 // 處理錯誤 })
finally方法
除了catch方法那自然就有finally方法, finally方法和try...catch...finally中的finally是一樣的作用, 使用格式如下:
p.then( // ... ).then( // ... ).catch(err => { // 這個catch方法可以捕獲這一條調(diào)用鏈上的錯誤 // 處理錯誤 }).finally(() => { // 無論成功還是失敗這個finally中指定的回調(diào)都會執(zhí)行 // 清除loading, 重置狀態(tài)... })
Promise的方法
Promise.resolve()
立即返回一個狀態(tài)是成功(Fulfilled) 的 Promise 對象, 可以傳遞參數(shù), 參數(shù)會被其返回的Promise實例的then方法的回調(diào)(異步微任務(wù))接受到:
const p = Promise.resolve("Promise.resolve"); p.then(res => console.log(res)); // Promise.resolve
也可以利用Promise.resolve()
來創(chuàng)建一個微任務(wù):
console.log("同步代碼"); setTimeout(() => console.log("setTimeout"), 0); const p = Promise.resolve("Promise.resolve"); p.then(res => console.log(res));
結(jié)果如下:
Promise.reject()
和Promise.resolve()
一樣不過返回的狀態(tài)是失敗(Rejected) 的Promise對象(同樣是微任務(wù))
console.log("同步代碼"); setTimeout(() => console.log("setTimeout"), 0); const p = Promise.reject("Promise.reject"); p.then().catch(err => console.log("Promise.reject"));
Promise.all()
Promise.all
接收一個Promise的iterable類型(就是可迭代對象里面存放著Promise實例, Array, Map, Set都屬于ES6的iterable類型), Promise.all
會等待所有的Promise對象都完成(或第一個失敗) , 根據(jù)給定的參數(shù)返回不同的參數(shù)
const p1 = new Promise((resolve, reject) => { setTimeout(() => resolve("p1 data"), 500); }) const p2 = new Promise((resolve, reject) => { setTimeout(() => resolve("p2 data"), 1000); }) const p3 = new Promise((resolve, reject) => { setTimeout(() => resolve("p3 data"), 1500); }) // 依次打印數(shù)據(jù) p1.then(res => console.log(res)); // 0.5s 后打印 p1 data p2.then(res => console.log(res)); // 1.0s 后打印 p2 data p3.then(res => console.log(res)); // 1.5s 后打印 p3 data const proArray = [p1, p2, p3]; Promise.all(proArray).then(resList => { console.log(resList); // 1.5s后打印數(shù)據(jù) ['p1 data', 'p2 data', 'p3 data'] }).catch(err => { // 如果在`Promise.all`方法中出現(xiàn)了失敗的狀態(tài), 那么這個參數(shù)會是這個失敗狀態(tài)返回的參數(shù)(如果有的話) console.error("error: ", err); })
利用Promise.all()
方法的特定可以用于同時發(fā)送多個請求, 如下例子:
Node接口:
const getRandom = () => Math.random() * 9 + 1; router.get('/testData4', (req, res) => { let n = req.query.n; const random = getRandom(); // 定時器模擬接口響應(yīng)時間差 setTimeout(() => { res.json(`第${++n}個請求${random}`); }, random * 50); });
前端發(fā)送多個請求:
const proArray = []; for (let i = 0; i < 10; i++) { // 將10個請求方法返回的Promsie對象添加到proArray數(shù)組中 proArray.push(request(`/testData4?n=${i}`)); } Promise.all(proArray).then(resList => { for (const res of resList) { // 每個請求的返回結(jié)果 console.log(res); } })
Promise.allSettled()
Promise.allSettled()
方法和Promise.all()
很類似只不過是接受的期約對象無論是成功還是失敗都會觸發(fā)then方法的成功回調(diào), 每個期約都會返回一個對象status屬性表示狀態(tài), value表示成功回調(diào)的值, 如果狀態(tài)是失敗的那么失敗回調(diào)的值存儲在reason屬性中:
const p1 = new Promise((resolve, reject) => { setTimeout(() => resolve("p1 data"), 500);; }) const p2 = new Promise((resolve, reject) => { // p2的Promise實例的狀態(tài)修改為失敗 setTimeout(() => reject("p2 err"), 1000); }) const proArray = [p1, p2]; Promise.allSettled(proArray).then(resList => { console.log(resList); // (2) [{…}, {…}] for (const res of resList) { const { status, value, reason } = res; if (reason) { console.log(`失敗: ${status}, 原因是: ${reason}`); // 失敗: rejected, 原因是: p2 err } else { console.log(`成功: ${status}, 數(shù)據(jù)是: ${value}`); // 成功: fulfilled, 數(shù)據(jù)是: p1 data } } }).catch(err => { // 這里不會捕獲p2的失敗的回調(diào) console.error("error: ", err); })
Promise.race()
Promise.race()
和Promise.all()
類似, 都接收一個可以迭代的參數(shù), 但是不同之處是
Promise.race()
的狀態(tài)變化不是受全部參數(shù)的狀態(tài)影響, 一旦迭代器中的某個Promise解決或拒絕,返回的 Promise就會解決或拒絕
const p1 = new Promise((resolve, reject) => { setTimeout(() => resolve("p1 data"), 500);; }) const p2 = new Promise((resolve, reject) => { setTimeout(() => reject("p2 err"), 1000); }) const proArray = [p1, p2]; Promise.race(proArray).then(res => { console.log(res); // p1 data }).catch(err => { console.error(err); })
async 和 await
async函數(shù)函數(shù)
async函數(shù)函數(shù)就是使用async關(guān)鍵字聲明的函數(shù)(也叫異步函數(shù)), async函數(shù)和普通的函數(shù)使用沒有什么區(qū)別:
// 函數(shù)聲明 async function asyncFn1() { console.log("asyncFn1"); } // 函數(shù)表達(dá)式 const asyncFn2 = async () => { console.log("asyncFn2"); } asyncFn1(); asyncFn2(); // 立即調(diào)用 (async () => { console.log("asyncFn3"); })();
await
await操作符用于等待一個Promise對象, 它只能在async function
中使用, 使用async+await可以將異步的代碼"變"的跟同步的一樣:
const p = new Promise((resolve, reject) => { setTimeout(() => { resolve("data"); }, 1000); }); // async 函數(shù) async function asyncFn() { console.log("asyncFn函數(shù)開始執(zhí)行"); // await 會等待右邊的Promise對象的狀態(tài)變成功后返回其值 const res = await p; console.log(res); // data console.log("asyncFn函數(shù)執(zhí)行完了"); } // 調(diào)用 asyncFn();
上面的代碼會先輸出"asyncFn函數(shù)開始執(zhí)行"后, 等待1s左右輸出"data", 然后再輸出"asyncFn函數(shù)執(zhí)行完了"
注意: 異步函數(shù)不會阻塞主線程的執(zhí)行, 它是異步的:
const p = new Promise((resolve, reject) => { setTimeout(() => { resolve("data"); }, 1000); }); // async 函數(shù) async function asyncFn() { console.log("asyncFn函數(shù)開始執(zhí)行"); const res = await p; console.log(res); console.log("asyncFn函數(shù)執(zhí)行完了"); } console.log("hello"); asyncFn(); console.log("javascript");
等待大約1s后上面的代碼執(zhí)行結(jié)果如下:
根據(jù)上面的代碼執(zhí)行結(jié)果, 我們發(fā)現(xiàn)異步函數(shù)內(nèi)await關(guān)鍵字會等待其右邊的Promise對象的返回值, 等待結(jié)束后, 后面的代碼才會被執(zhí)行, 利用這個特性我們可以在JavaScript中可以實現(xiàn)類似Java的Thread.sleep()
方法, 如下:
const sleep = async time => new Promise(resolve => setTimeout(resolve, time)); (async () => { console.log("1"); await sleep(1000); console.log("2"); await sleep(500); console.log("2.5"); })();
了解完async和await的使用后我們可以使用異步函數(shù)再來完成我們一開始的需求:
// 請求函數(shù)使用 Promise 封裝 const baseUrl = "http://localhost:8888/test"; const request = (url) => { // 返回一個Promise實例 return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('GET', baseUrl + url); xhr.send(); xhr.onreadystatechange = () => { const { readyState, status, response } = xhr; if (readyState === 4) { if (status >= 200 && status <= 299) { const res = JSON.parse(response); // 修改狀態(tài)為成功并且把響應(yīng)傳遞過去 resolve(res); } else { // 修改狀態(tài)為失敗也把響應(yīng)傳遞過去 reject(response); } } } }) } async function asyncFn() { const res1 = await request("/testData1"); console.log(res1); // {data: '用戶數(shù)據(jù)1'} const res2 = await request(`/testData2?data=${res1.data}`); console.log(res2); // {data: '用戶數(shù)據(jù)1,用戶數(shù)據(jù)2'} const res3 = await request(`/testData3?data=${res2.data}`); console.log(res3); // {data: '用戶數(shù)據(jù)1,用戶數(shù)據(jù)2,用戶數(shù)據(jù)3'} } asyncFn();
可以看到使用async和await來發(fā)送網(wǎng)絡(luò)請求寫的代碼很簡潔, 也很直觀
異步函數(shù)的錯誤處理
異步函數(shù)的異常處理可以使用try...catch
和catch處理:
try...catch
async function asyncFn() { let res1, res2, res3; try { res1 = await request("/testData1"); try { if (res1?.data) { res2 = await request(`/testData2?data=${res1.data}`); } try { if (res2?.data) { res3 = await request(`/testData3?data=${res2.data}`); } } catch (error) { // 處理res3 error } } catch (error) { // 處理res2 error } } catch (error) { // 處理res3 error } }
catch
async function asyncFn() { const res1 = await request("/testData1") .catch(err => { // 處理res1 error }); if (res1?.data) { const res2 = await request(`/testData2?data=${res1.data}`) .catch(err => { // 處理res2 error }); if (res2?.data) { const res3 = await request(`/testData3?data=${res2.data}`) .catch(err => { // 處理res3 error }); } } }
異步函數(shù)同樣適用于Promise的一些靜態(tài)方法
const p1 = new Promise((resolve, reject) => { setTimeout(() => resolve("p1 data"), 500); }) const p2 = new Promise((resolve, reject) => { setTimeout(() => resolve("p2 data"), 1000); }) const p3 = new Promise((resolve, reject) => { setTimeout(() => resolve("p3 data"), 1500); }) const proArray = [p1, p2, p3]; async function asyncFn() { const list = await Promise.all(proArray); console.log(list); // ['p1 data', 'p2 data', 'p3 data'] } asyncFn();
for await...of
一個數(shù)組中存儲多個Promise對象我們可以通過Promise.all
獲取或者通過循環(huán)來等待其返回值, 我們使用循環(huán):
const p1 = new Promise((resolve, reject) => { setTimeout(() => resolve("p1 data"), 500); }) const p2 = new Promise((resolve, reject) => { setTimeout(() => resolve("p2 data"), 1000); }) const p3 = new Promise((resolve, reject) => { setTimeout(() => resolve("p3 data"), 1500); }) const proArray = [p1, p2, p3]; async function asyncFn() { for (const pro of proArray) { // 這里不要忘記 await const res = await pro; console.log(res); } } asyncFn();
ES9開始有一個新語法就是for await..of
可以自動等待每次循環(huán)的項
async function asyncFn() { for await (const item of proArray) { console.log(item); } } asyncFn();
參考:
- MDN Promise
- MDN async
- MDN for await...of
- JavaScript權(quán)威指南
- 阮一峰ES6入門之promise
總結(jié)
到此這篇關(guān)于JavaScript中Promise使用的文章就介紹到這了,更多相關(guān)JS Promise的使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JS獲取url參數(shù),JS發(fā)送json格式的POST請求方法
下面小編就為大家分享一篇JS獲取url參數(shù),JS發(fā)送json格式的POST請求方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-03-03利用百度echarts實現(xiàn)圖表功能簡單入門示例【附源碼下載】
這篇文章主要介紹了利用百度echarts實現(xiàn)圖表功能簡單,結(jié)合簡單示例形式分析了echarts插件的圖標(biāo)繪制功能相關(guān)實現(xiàn)技巧,并附帶源碼供讀者下載參考,需要的朋友可以參考下2019-06-06JS實現(xiàn)將對象轉(zhuǎn)化為數(shù)組的方法分析
這篇文章主要介紹了JS實現(xiàn)將對象轉(zhuǎn)化為數(shù)組的方法,結(jié)合實例形式分析了javascript操作及轉(zhuǎn)換json數(shù)組相關(guān)實現(xiàn)技巧,需要的朋友可以參考下2019-01-01