閱讀時間:
12 minutes
文章類型:理論知識 & 案例演示
案例需求:用JavaScript實現,3個小球前後運動,完成接力賽跑
案例源碼:見文章最後html引言:
前端開發中,異步處理必不可少;
過去,咱們常常用回調函數來完成異步處理,所以也常常產生回調地獄(callback hell
);
今天,咱們用實例來對比異步處理的方法;
是時候用async
來處理咱們的異步流程了。前端
Callback
回調函數: 是將一個函數做爲參數,傳遞給另外一個函數,而後在外部函數中調用該函數來完成某種例程或動做。用法:在函數內部調用函數promise
callback
實現小球移動的方法;function move(ele, target, callback) { let left = parseInt(getComputedStyle(ele)["left"]); let timer = setInterval(function () { if (left >= target) { clearInterval(timer); callback(); } else { left += 2; ele.style.left = left + "px"; } }, 4) }
move(ball1, 200, function () { move(ball2, 400, function () { move(ball3, 600, function () { alert("callback"); }); }) })
Promise
Promise
: 是一個返回值的代理,它容許您將處理程序與異步操做的最終成功值或失敗緣由相關聯。 這使異步方法能夠像同步方法那樣返回值:不是當即返回最終值,而是異步方法返回一個Promise
,以便在將來的某個時間點提供該值。用法:
Promise
對象是由關鍵字new
及其構造函數來建立的。該函數接收一個函數(executor function
)做爲它的參數。這個函數接受兩個函數——resolve
和reject
——做爲其參數。當異步任務順利完成且返回結果值時,會調用resolve
函數;而當異步任務失敗且返回失敗緣由(一般是一個錯誤對象)時,會調用reject
函數。異步
Promise
實現小球移動的方法;// 讓move方法擁有Promise功能 function move(ele, target) { return new Promise(function (resolve, reject) { let left = parseInt(getComputedStyle(ele)["left"]); let timer = setInterval(function () { if (left >= target) { clearInterval(timer); resolve(); } else { left += 2; ele.style.left = left + "px"; } }, 4) }) }
Promise.then()
方法;move(ball1, 200).then(function () { return move(ball2, 400); }).then(function () { return move(ball3, 600); }).then(function () { alert("promise"); })
Generator
Generator
:生成器函數在函數執行時能暫停,還能從暫停處繼續執行,至關於將函數分段執行。用法:必須用
.next()
配合yield
關鍵字使用;例如:async
function *gen(){ yield 10; y=yield 'foo'; yield y; } var gen_obj=gen(); console.log(gen_obj.next()); // 執行 yield 10,返回 10 console.log(gen_obj.next()); // 執行 yield 'foo',返回 'foo' console.log(gen_obj.next(10)); // 將 10 賦給上一條 yield 'foo' 的左值,即執行 y=10,返回 10 console.log(gen_obj.next()); // 執行完畢,value 爲 undefined,done 爲 true
Genertor
實現小球移動的方法;// 函數move方法調用上面Promise中的move方法; function move(ele, target) { return new Promise(function (resolve, reject) { let left = parseInt(getComputedStyle(ele)["left"]); let timer = setInterval(function () { if (left >= target) { clearInterval(timer); resolve(); } else { left += 2; ele.style.left = left + "px"; } }, 4) }) }
let g = m(); g.next(); //讓第一個小球運動; g.next(); //讓第二個小球運動; g.next(); //讓第三個小球運動;
co
庫迭代generator
執行器;function co(it) { return new Promise(function (resolve, reject) { function next(d) { let { value, done } = it.next(d); if (!done) { value.then(function (data) { next(data) }, reject) } else { resolve(value); } }; next(); }); } // 一行代碼實現函數執行,可是須要引入co庫; co(m()).then(function () { alert("generator"); })
async/await
async
: 異步函數聲明定義了一個異步函數,它返回一個AsyncFunction
對象。當async
函數執行,返回一個Promise
對象;用法:用
async
聲明函數,函數內配合await
使用。函數
async/await
實現小球移動的方法;// 調用上面的move()方法; function move(ele, target) { return new Promise(function (resolve, reject) { let left = parseInt(getComputedStyle(ele)["left"]); let timer = setInterval(function () { if (left >= target) { clearInterval(timer); resolve(); } else { left += 2; ele.style.left = left + "px"; } }, 4) }) }
await
方法;async function a() { await move(ball1, 200); await move(ball2, 400); await move(ball3, 600); } a().then(function () { alert("async") })
經過上述4種方法的對比,咱們能夠看出JavaScript
這門語言的發展和進步;
ES6+
增長了不少實用功能和方法,將有助於前期代碼的編寫以及後期代碼的維護,是時候用async/await
來處理咱們的異步操做了。
案例源碼:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .container .ball { width: 100px; height: 100px; border-radius: 50%; position: absolute; } .container .ball:nth-child(1) { background-color: blue; left: 0; top: 20px; } .container .ball:nth-child(2) { background-color: yellow; left: 200px; top: 150px; } .container .ball:nth-child(3) { background-color: green; left: 400px; top: 280px; } </style> </head> <body> <div class="container"> <div class="ball"></div> <div class="ball"></div> <div class="ball"></div> </div> <!-- <script src="Promise.js"></script> --> <script> let ball = document.querySelectorAll(".ball"); let [ball1, ball2, ball3] = [...ball]; // 1.回調函數處理; function move(ele, target, callback) { let left = parseInt(getComputedStyle(ele)["left"]); let timer = setInterval(function () { if (left >= target) { clearInterval(timer); callback(); } else { left += 2; ele.style.left = left + "px"; } }, 4) } move(ball1, 200, function () { move(ball2, 400, function () { move(ball3, 600, function () { alert("callback"); }); }) }) // 2.promise // generator、async都是基於promise的發展; // function move(ele, target) { // return new Promise(function (resolve, reject) { // let left = parseInt(getComputedStyle(ele)["left"]); // let timer = setInterval(function () { // if (left >= target) { // clearInterval(timer); // resolve(); // } else { // left += 2; // ele.style.left = left + "px"; // } // }, 4) // }) // } // move(ball1, 200).then(function () { // return move(ball2, 400); // }).then(function () { // return move(ball3, 600); // }).then(function () { // alert("promise"); // }) // 3.Generator // function* m() { // yield move(ball1, 200); // yield move(ball2, 400); // yield move(ball3, 600); // } // // 利用co方法自動迭代generator // function co(it) { // return new Promise(function (resolve, reject) { // function next(d) { // let { value, done } = it.next(d); // if (!done) { // value.then(function (data) { // 2,txt // next(data) // }, reject) // } else { // resolve(value); // } // } // next(); // }); // } // co(m()).then(function () { // alert("generator"); // }) // 4.async/await // async function a() { // await move(ball1, 200); // await move(ball2, 400); // await move(ball3, 600); // } // a().then(function () { // alert("async") // }) </script> </body> </html>