回調與promise
方法 用於請求數據(模擬)
resolve表明成功時要作的事情html
function f() { return new Promise(resolve => { setTimeout(function() { resolve(); }, 1000); }) } f() .then(function() { console.log(1); //return promise實例,才能繼續.then() return f(); }) .then(function() { console.log(2); return f(); }) .then(function() { console.log(4); return f(); }) .then(function() { console.log(3); return f(); }) .then(function() { console.log(5); return f(); }) .then(function() { console.log(6); });
案例:
Promise 新建後當即執行,因此首先輸出的是Promise,而後,then方法指定的回調函數,將在當前腳本全部同步任務執行完纔會執行,因此resolved最後輸出數組
let promise=new Promise(resolve=>{ console.log('Promise'); resolve(); }); promise.then(function(){ console.log('resolved'); }); console.log('Hello!'); //結果:Promise Hello! resolved
Promise小動畫案例:
index.htmlpromise
<!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> #el { width: 100px; background: green; transition: all 1s; color: white; line-height: 100px; text-align: center; font-size: 40px; } </style> </head> <body> <div id="el">哦</div> <button id="btn">開始</button> <script src="./main.js"></script> </body> </html>
main.jsapp
function moveTo(el, x, y) { return new Promise(resolve => { el.style.transform = `translate(${x}px, ${y}px)`; setTimeout(function() { resolve(); }, 1000); }); } let el = document.querySelector('div'); document.querySelector('button').addEventListener('click', e => { moveTo(el, 100, 100) .then(function() { console.log('第一次移動'); return moveTo(el, 200, 200); }) .then(function() { console.log('第二次移動'); }) .then(function() { console.log('第二次移動'); }); });
錯誤處理
resolve成功時操做
reject失敗時操做異步
function f(val) { return new Promise((resolve, reject) => { if (val) { resolve({ name: '小明' }); } else { reject('404'); } }); } f(true) .then((data) => { console.log(data) }, e => { console.log(e); })
catch
使用實例的catch方法 能夠捕獲錯誤函數
f(true) .then(data => { console.log(data); return f(false); }) .then(() => { console.log('我永遠不會被輸出'); }) .then(() => { }) .catch(e => { console.log(e); return f(false) ; });
finally
不論成功仍是失敗 finally中的內容必定會執行動畫
f(true) .then(data => { console.log(data); return f(false); }) .catch(e => { console.log(e); return f(false); }) .finally(() => { console.log(100); });
promise三種狀態
pending 進行中
fulfilled 成功
rejected 失敗
狀態的改變不可逆:
pending能夠到fulfilled或者rejectedui
Promise.all方法能夠把多個promise實例 包裝成一個新的promise實例
Promise.all([ promise1, promise2 ]) : Promise
模擬須要多個請求的數據 才能進行下一步操做的狀況spa
function getData1() { return new Promise((resolve, reject) => { setTimeout(() => { console.log('第一條數據加載成功'); resolve('data1'); }, 1000); }); } function getData2() { return new Promise((resolve, reject) => { setTimeout(() => { console.log('第二條數據加載成功'); resolve('data2'); }, 1000); }); } function getData3() { return new Promise((resolve, reject) => { setTimeout(() => { console.log('第三條數據加載成功'); resolve('data3'); }, 1000); }); } function getData4() { return new Promise((resolve, reject) => { setTimeout(() => { console.log('第四條數據加載成功'); resolve('data4'); }, 2000); }); } // 全部數據都成功,則總決議成功,並返回全部成功提示 let p = Promise.all([getData1(),getData2(),getData3(),getData4()]); p.then(arr => { console.log(arr); });
一條數據失敗,則總決議失敗,並返回錯誤信息code
function getData1() { return new Promise((resolve, reject) => { setTimeout(() => { console.log('第一條數據加載成功'); resolve('data1'); }, 1000); }); } function getData2() { return new Promise((resolve, reject) => { setTimeout(() => { console.log('第二條數據加載成功'); resolve('data2'); }, 1000); }); } function getData3() { return new Promise((resolve, reject) => { setTimeout(() => { console.log('第三條數據加載成功'); resolve('data3'); }, 1000); }); } function getData4() { return new Promise((resolve, reject) => { setTimeout(() => { reject('data4 err'); }, 500); }); } // 一條數據失敗,則總決議失敗,並返回錯誤信息 let p = Promise.all([getData1(),getData2(),getData3(),getData4()]); p.then(arr => { console.log(arr); },e=>{ console.log(e); });
空數組直接決議爲成功
function getData1() { return new Promise((resolve, reject) => { setTimeout(() => { console.log('第一條數據加載成功'); resolve('data1'); }, 1000); }); } function getData2() { return new Promise((resolve, reject) => { setTimeout(() => { console.log('第二條數據加載成功'); resolve('data2'); }, 1000); }); } function getData3() { return new Promise((resolve, reject) => { setTimeout(() => { console.log('第三條數據加載成功'); resolve('data3'); }, 1000); }); } function getData4() { return new Promise((resolve, reject) => { setTimeout(() => { reject('data4 err'); }, 500); }); } // 空數組直接決議爲成功 let p = Promise.all([]); p.then(() => { console.log('null'); },e=>{ console.log(e); });
promise.race
只要有一個決議爲成功或者失敗,就會返回
function getData1() { return new Promise((resolve, reject) => { setTimeout(() => { console.log('第一條數據加載成功'); reject('err'); }, 500); }); } function getData2() { return new Promise((resolve, reject) => { setTimeout(() => { console.log('第二條數據加載成功'); resolve('data2'); }, 1000); }); } function getData3() { return new Promise((resolve, reject) => { setTimeout(() => { console.log('第三條數據加載成功'); resolve('data3'); }, 1000); }); } let p = Promise.race([getData1(),getData2(),getData3()]); p.then(data => { console.log(data); }, e => { console.log(e); })
空數組會被掛起
let p = Promise.race([]);
Promise.resolve() 和 Promise.reject()
經常使用來生成已經被決議爲失敗或者成功的promise實例
Promise.resolve傳遞一個普通的值
決議成功並把值傳遞過去
let p1 = new Promise(resolve => { resolve('成功!'); }); let p2 = Promise.resolve('成功!');
Promise.resolve傳遞一個promise實例
let poruomiesi = new Promise(resolve => { resolve('耶!') }); // 直接返回傳遞進去的promise let p = Promise.resolve(poruomiesi); p.then(data => void console.log(data)); console.log(p === poruomiesi);
Promise.resolve傳遞一個thenable
若是傳遞的是個thenable
let obj = { then(cb) { console.log('我被執行了'); cb('哼!'); }, oth() { console.log('我被拋棄了'); } } // 當即執行then方法 Promise.resolve(obj).then(data => { console.log(data); });
Promise.reject
直接決議爲失敗,不作處理
Promise.reject({ then() { console.log(1) } }) .then(() => { console.log('我不會被執行'); }, e => { console.log(e); });
異步任務老是在同步任務以後執行
把同步的任務轉成異步任務
function createAsyncTask(syncTask) { return Promise.resolve(syncTask).then(syncTask => syncTask()); } createAsyncTask(() => { console.log('我變成了異步任務!!!'); return 1 + 1; }).then(res => { console.log(res); }); console.log('我是同步任務!');
要求:多張圖片加載完以後才能進行統一展現
const loadImg = src => { return new Promise((resolve, reject) => { const img = new Image(); img.src = src; img.onload=()=>{ resolve(img); }; img.onerror=(e)=>{ reject(e); }; // img.onload = void resolve(img); // img.onerror = void reject('加載失敗'); }); }; const imgs = [ 'http://img1.sycdn.imooc.com\/climg/5b16558d00011ed506000338.jpg', 'http://img1.sycdn.imooc.com\/climg/5b165603000146ca06000338.jpg', 'http://img1.sycdn.imooc.com//climg/5b1656140001c89906000338.jpg' ]; // map遍歷數組中的每一項 Promise.all(imgs.map(src => loadImg(src))).then(arr => { console.log(arr); arr.forEach((img)=>{ document.body.appendChild(img); }); }); // map遍歷數組中的每一項(與上面相同做用,上面是簡寫) // map進行循環,每循環一次就將src做爲參數傳遞進來 // const promises=imgs.map(src =>{ // return loadImg(src); // }); // Promise.all(promises).then(arr => { // console.log(arr); // arr.forEach((img)=>{ // document.body.appendChild(img); // }); // }).catch((e)=>{ // console.log(e); // });