// 循環執行期間,JS 執行和DOM渲染暫時卡頓 var i, sum = 0; for(var i = 0; i < 1000000000; i++) { sum += 1; } console.log(sum); // alert 不處理,JS 執行和DOM渲染暫時卡頓 alert('hello'); console.log(2);
console.log(100) setTimeout(function() { console.log(200) //反正1000ms 以後執行 },1000) //先無論它,先讓其餘JS代碼執行 console.log(300);
var ajax = $.ajax({ url: './data.json', success: function(result) { //ajax加載完才執行 console.log(result); //先無論它,先讓其餘JS代碼執行 } }) console.log(ajax) //{readyState: 1, getResponseHeader: ƒ, getAllResponseHeaders: ƒ, setRequestHeader: ƒ, overrideMimeType: ƒ, …} console.log(200); //200
// jQuery1.5以前 var ajax = $.ajax({ url: './data.json', success: function(result) { console.log('success1'); console.log('success2'); console.log('success3'); }, error:function(){ console.log('error'); } }) console.log(ajax) //返回一個XHR對象
// jquery1.5以後 var ajax = $.ajax('./data.json'); ajax.done(function() { console.log('success1'); }) .fail(function() { console.log('error1'); }) .done(function() { console.log('success2') }) console.log(ajax); //返回一個deferred對象,能夠進行鏈式操做 // 還可使用很像promise寫法 var ajax = $.ajax('./data.json'); ajax.then(function(){ console.log('success1'); },function(){ console.log('error1'); }).then(function(){ console.log('success2'); },function(){ console.log('error2'); })
2,jQuery Deferred應用css
看一個簡單的例子:html
// 給出一段很是簡單的異步操做代碼,使用setTimeout函數 var wait = function() { var task = function() { console.log('執行完成'); // 1 // 2 // 3 } setTimeout(task, 1000) } wait() // 新增需求:要在執行完成以後進行某些特別複雜的操做,代碼可能會不少,並且分好幾個步驟
使用Deferred:(開放封閉原則)前端
function waitHandler() { // 定義 var dtd = $.Deferred(); //建立一個deferred對象 var wait = function(dtd) { //要求傳入一個deferred對象 var task = function() { console.log('執行完成'); // 成功 dtd.resolve(); //表示異步任務已經完成 // 失敗 // dtd.reject(); //表示異步任務失敗或出錯 } setTimeout(task, 1000) // wait返回 return dtd; //要求返回deferred對象 } // 最終返回 注意這裏必定要有返回值 return wait(dtd); } var w = waitHandler(); w.then(function() { console.log('ok1'); }, function() { console.log('err1'); }).then(function() { console.log('ok2'); }, function() { console.log('err2'); }) // 還有 w.done w.fail
執行rejectjquery
function waitHandler() { // 定義 var dtd = $.Deferred(); //建立一個deferred對象 var wait = function(dtd) { //要求傳入一個deferred對象 var task = function() { console.log('執行完成'); // 成功 // dtd.resolve(); //表示異步任務已經完成 // 失敗 dtd.reject(); //表示異步任務失敗或出錯 } setTimeout(task, 1000) // wait返回 return dtd; //要求返回deferred對象 } // 最終返回 注意這裏必定要有返回值 return wait(dtd); } var w = waitHandler(); w.then(function() { console.log('ok1'); }, function() { console.log('err1'); }) w.then(function() { //reject須要分開,否則執行順序就錯啦 console.log('ok2'); }, function() { console.log('err2'); })
這裏注意一個原則:開放封閉原則ajax
總結,dtd的API可分紅兩類,用意不一樣npm
第一類(主動執行):dtd.resolve dtd.reject
第二類(監聽):dtd.then dtd.done dtd.fail
這兩類應該分開,不然後果很嚴重
可在上面代碼最後執行dtd.reject()試下結果json
使用dtd.promise()數組
function waitHandler(){ var dtd = $.Deferred();//Deferred var wait = function(dtd) { var task = function(){ console.log('執行完成'); dtd.resolve(); } setTimeout(task,2000); return dtd.promise();//注意,這裏返回的是promise,而不是直接返回deferred對象 } return wait(dtd); } var w = waitHandler();//通過上面的改動,w接收的就是一個promise對象 $.when(w) .then(function(){ console.log('ok1'); }) .then(function(){ console.log('ok1'); }) w.reject()//執行這句會報錯 w.reject is not a function promise不能使用,只有監聽的方法了,使用者只能監聽,開發人員封裝的時候才能用
說明promise和deferred區別: promise只能被動監聽,不能主動執行promise
1,基本語法回顧(備註:如今高級瀏覽器基本都支持promise,若是有些不支持,能夠在cdn上找,引入 bluebird )瀏覽器
<script src="https://cdn.bootcss.com/bluebird/3.5.1/bluebird.min.js"></script>
function loadImg(src) { const promise = new Promise(function(resolve, reject) { //new Promise實例 var img = document.createElement('img'); img.src = src; img.onload = function() { resolve(img); } img.onerror = function() { reject('圖片加載失敗'); } }); return promise; //返回 Promise實例 } var src = "https://shared-https.ydstatic.com/dict/v2016/result/logo.png"; var result = loadImg(src); //Promise實例 result.then(function(img) { //then監聽結果,成功時執行resolve(), 失敗時執行reject() console.log(1, img.width); //1 164 return img; }, function(img) { console.log('failed'); return img; }).then(function(img) { console.log(2, img.height) //2 36 })
2,異常捕獲
// 規定:then只接受一個參數(成功的處理函數),最後統一用catch捕獲異常 // var src = "https://shared-https.ydstatic.com/dict/v2016/result/logo.png"; var src = "https://shared-https.ydstatic.com/dict/v2016/result/logo_1.png";//寫一個不存在的地址 var result = loadImg(src); result.then(function(img) { console.log(img.width); return img; }).then(function(img) { console.log(img.height); }).catch(function(ex) { // 最後統一用catch捕獲異常 console.log(ex); //圖片加載失敗 (logo_1.png:1 GET https://shared-https.ydstatic.com/dict/v2016/result/logo_1.png 404 (Not Found)) })
自定義錯誤:
function loadImg(src) { const promise = new Promise(function(resolve, reject) { //new Promise實例 var img = document.createElement('img'); // 模擬拋出錯誤 模擬語法錯誤,邏輯以外的bug throw new Error('自定義錯誤'); img.src = src; img.onload = function() { resolve(img); } img.onerror = function() { reject('圖片加載失敗'); } }); return promise; //返回 Promise實例 } // 規定:then只接受一個參數(成功的處理函數),最後統一用catch捕獲異常 var src = "https://shared-https.ydstatic.com/dict/v2016/result/logo.png"; // var src = "https://shared-https.ydstatic.com/dict/v2016/result/logo_1.png"; //寫一個不存在的地址 var result = loadImg(src); result.then(function(img) { console.log(img.width); return img; }).then(function(img) { console.log(img.height); }).catch(function(ex) { // 最後統一用catch捕獲異常 console.log(ex); })
3,多個串聯
// 多個串聯 圖片只是用來模擬,實際可能更多的不是用圖片,好比處理用戶信息啥的,加載用戶信息的時候,先拿到用戶信息,再去處理其餘信息等 var src1 = 'https://shared-https.ydstatic.com/dict/v2016/result/logo.png'; var result1 = loadImg(src1); var src2 = 'https://img.mukewang.com/user/57b98e990001351004400440-100-100.jpg'; var result2 = loadImg(src2); // 鏈式操做 result1.then(function(img1) { console.log('第一個圖片加載完成', img1.width); return result2; //重要!!! }).then(function(img2) { console.log('第二個圖片加載完成', img2.width); }).catch(function(ex) { // 最後統一用catch捕獲異常 console.log(ex); })
4,Promise.all (所有promise實例完成後) 和 Promise.race (只要有一個promise實例完成)
// Promise.all 接收一個包含多個promise實例的數組,待所有完成以後,統一執行success var src1 = 'https://shared-https.ydstatic.com/dict/v2016/result/logo.png'; var result1 = loadImg(src1); //pending var src2 = 'https://img.mukewang.com/user/57b98e990001351004400440-100-100.jpg'; var result2 = loadImg(src2); Promise.all([result1, result2]).then(datas => { // 接收到的datas是一個數組,依次包含了多個promise返回的內容 console.log('all', datas[0]); //all <img src="https://shared-https.ydstatic.com/dict/v2016/result/logo.png"> console.log('all', datas[1]); //all <img src="https://img.mukewang.com/user/57b98e990001351004400440-100-100.jpg"> })
Promise.race (只要有一個promise實例完成)
// Promise.race 接收一個包含多個promise實例的數組 // 只要有一個完成,就執行success Promise.race([result1, result2]).then(data => { // data即最早執行完成的promise的返回值 console.log('race', data); //race <img src="https://shared-https.ydstatic.com/dict/v2016/result/logo.png"> })
promise標準
1,關於「標準」的閒談
任何技術推廣使用都須要一套標準來支撐
如html css js等,無規矩不成方圓
任何不符合標準的東西,終將會被用戶拋棄
不要挑戰標準,不要自造標準
2,狀態變化
三種狀態:pending fulfilled rejected
pending: 初始狀態
fulfilled: 成功
rejected:失敗
pending到fulfilled,或者pending到rejected,狀態不可逆
3,then
Promise實例必須實現then方法
then()必須能夠接收兩個函數做爲參數
then()返回的必須是一個Promise實例
若是then中沒有返回promise實例,則默認返回的是上一個promise實例,若是返回了一個promise實例,那就默認爲返回的promise實例
1,then只是將callback拆分了
// then只是將callback拆分了 var w = waitHandler(); w.then(function() { console.log('ok1'); }, function() { console.log('err1'); }).then(function() { console.log('ok2'); }, function() { console.log('err2'); })
2,async/await是最直接的同步寫法
// async/await是最直接的同步寫法 const load = async function() { const result1 = await loadImg(src1); console.log(result1); const result2 = await loadImg(src2); console.log(result2); } load()
完整的:
import 'babel-polyfill'; //引入babel-polyfill // async/await是最直接的同步寫法 function loadImg(src) { const promise = new Promise(function(resolve, reject) { var img = document.createElement('img'); img.src = src; img.onload = function() { resolve(img); } img.onerror = function() { reject('圖片加載失敗'); } }); return promise; } var src1 = 'https://shared-https.ydstatic.com/dict/v2016/result/logo.png'; var src2 = 'https://img.mukewang.com/user/57b98e990001351004400440-100-100.jpg'; // async/await是最直接的同步寫法 const load = async function() { //函數必須用async標識 const result1 = await loadImg(src1); //await後面跟的是一個Promise實例 console.log(result1); const result2 = await loadImg(src2); //await後面跟的是一個Promise實例 console.log(result2); } load()
用法:
要在函數體內使用await,函數必須用async標識
await後面跟的是一個Promise實例
須要安裝babel-polyfill
npm i --save-dev babel-polyfill
3,總結
使用了Promise,並無和Promise衝突
徹底是同步的寫法,再也沒有回調函數
可是:改變不了js單線程,異步的本質
1,jquery Deferred2,Promise3,Async/await