參考:javascript
EC前端 - Promise - http://www.ecmaer.com/javascript/nativeObj/promise.htmlhtml
關於Promise:前端
Promise 的常規寫法:java
new Promise(請求1) .then(請求2(請求結果1)) .then(請求3(請求結果2)) .then(請求4(請求結果3)) .then(請求5(請求結果4)) .catch(處理異常(異常信息))
Promise 的寫法更爲直觀,而且可以在外層捕獲異步函數的異常信息jquery
請求1(function(請求結果1){ 請求2(function(請求結果2){ 請求3(function(請求結果3){ 請求4(function(請求結果4){ 請求5(function(請求結果5){ 請求6(function(請求結果3){ ... }) }) }) }) }) })
回調地獄帶來的負面做用有如下幾點:
一、代碼臃腫;
二、可讀性差;
三、耦合度太高,可維護性差;
四、代碼複用性差;
五、容易滋生 bug;
六、只能在回調裏處理異常;
爲了能使用一種更加友好的代碼組織方式,解決異步嵌套的問題:es6
let 請求結果1 = 請求1(); let 請求結果2 = 請求2(請求結果1); let 請求結果3 = 請求3(請求結果2); let 請求結果4 = 請求2(請求結果3); let 請求結果5 = 請求3(請求結果4);
Promise 的業界實現都有哪些?
業界著名的 Q 和 bluebird,bluebird 甚至號稱運行最快的類庫面試
const gen = function* () { yield 1; yield 2; return 3; } let g = gen(); g.next(); // { value: 1, done: false } g.next(); // { value: 2, done: false } g.next(); // { value: 3, done: true } g.next(); // { value: undefined, done: true }
generator函數有一個最大的特色,能夠在內部執行的過程當中交出程序的控制權,yield至關於起到了一個暫停的做用;而當必定狀況下,外部又將控制權再移交回來
五、async / await
es7中的async/await
在async函數中可使用await語句。await後通常是一個Promise對象ajax
async function foo () { console.log('開始'); let res = await post(data); console.log(`post已完成,結果爲:${res}`); };
四、Promise 如何使用?編程
// 聲明函數 function run(callback) { let parmas = 0; if (callback) callback(parmas); }; function fnStep1(callback) { let parmas = 123; if (callback) callback(parmas); }; function fnStep2(callback) { let parmas = 456; if (callback) callback(parmas); }; function fnStep3(callback) { let parmas = 789; if (callback) callback(parmas); }; // fnStep4 ... // 傳統使用回調的寫法 run(function (parmas) { // parmas = 0 console.log(parmas); fnStep1(function (parmas1) { // parmas = 123 console.log(parmas1); fnStep2(function (parmas2) { // parmas = 456 console.log(parmas2); fnStep3(function (parmas3) { // ... // 一直嵌套 }); }); }); }); let p = new Promise((resolve, reject) => { const parmas = 0; resolve(parmas); // fulfilled // reject("failure reason"); // rejected }) p.then( (parmas) => { // parmas,resolve返回的值 console.log(parmas); //0 return 123; //返回值給下一個then } ) .then( (parmas) => { // parmas,上一個then返回的值 console.log(parmas); //123 return 456; //返回值給下一個then } ) .then( (parmas) => { // parmas,上一個then返回的值 console.log(parmas); //456 return 789; //返回值給下一個then })
六、Promise 在事件循環中的執行過程是怎樣的?promise
構造函數傳入的參數是什麼類型?
它接收的參數是一個匿名函數,任何狀況下,它裏面的js最早執行。
這個匿名函數也有二個參數:
一、resolve,完成,操做成功時調用。
二、reject,失敗,操做失敗時調用。
若調用了兩次resolve方法會怎麼樣?
只執行第一次resolve
發生異常會怎麼樣?
promise的原理?jquery的ajax返回的是promise對象嗎?(百度面試)
promise 只有2個狀態,成功和失敗,怎麼讓一個函數不管成功和失敗都能被調用?
Promise.all() 是幹什麼用的,怎麼用?
初始化Promise對象的方法
new Promise(fn)
Promise.resolve(fn)
/* *end *nextTick *then *setImmediate * *process.nextTick 和 promise.then 都屬於 microtask * 而 setImmediate 屬於 macrotask * 在事件循環的 check 階段執行 * 事件循環的每一個階段(macrotask)之間都會執行 microtask,事件循環的開始會先執行一次 microtask * */ process.nextTick(()=>{ console.log('nextTick'); }); Promise.resolve().then(()=>{ console.log('then'); }); setImmediate(()=>{ console.log('setImmediate'); }); console.log('end');
Promise擴展之事件循環機制:
macrotasks:
microtasks:
任務能夠分紅兩種,一種是同步任務(synchronous),另外一種是異步任務(asynchronous)。
同步任務指的是,在主線程上排隊執行的任務,只有前一個任務執行完畢,才能執行後一個任務;
異步任務指的是,不進入主線程、而進入"任務隊列"(task queue)的任務,只有"任務隊列"通知主線程,某個異步任務能夠執行了,該任務纔會進入主線程執行。
執行優先級的問題 microtasks > macrotasks
在每一次事件循環中,macrotask 只會提取一個執行,而 microtask 會一直提取,直到 microtasks 隊列清空。
而事件循環每次只會入棧一個 macrotask ,主線程執行完該任務後又會先檢查 microtasks 隊列並完成裏面的全部任務後再執行 macrotask
setImmediate(function(){ console.log(1); },0); setTimeout(function(){ console.log(2); },0); new Promise(function(resolve){ console.log(3); resolve(); console.log(4); }).then(function(){ console.log(5); }); console.log(6); process.nextTick(function(){ console.log(7); }); console.log(8); //3 4 6 8 7 5 2 1