曾幾什麼時候,咱們爲了獲取異步調用的結果,不得不大量使用回調函數,咱們看下面這個例子:javascript
經過Jquery的ajax獲取服務器數據前端
let url1 = 'http://xxx.xxx.1';
$.ajax({
url:url1,
error:function (error) {},
success:function (data1) {
console.log(data1);
}
});
複製代碼
當須要發送多個異步請求,且每一個請求之間須要相互依賴時,咱們只能以嵌套的方式來解決java
let url1 = 'http://xxx.xxx.1';
let url2 = 'http://xxx.xxx.2';
let url3 = 'http://xxx.xxx.3';
$.ajax({
url:url1,
error:function (error) {},
success:function (data1) {
console.log(data1);
$.ajax({
url:url2,
data:data1,
error:function (error) {},
success:function (data2) {
console.log(data2);
$.ajax({
url:url3,
data,
error:function (error) {},
success:function (data3) {
console.log(data3);
}
});
}
});
}
});
複製代碼
在處理多個異步邏輯時,就須要多層的回調函數嵌套,也就是咱們常說的回調地獄。node
這種編碼模式的主要問題:git
而Promise的出現,就是爲了解決回調函數所引出的各類問題github
Promise 是異步編程的一種解決方案,比傳統的異步解決方案【回調函數】和【事件】更合理、更強大。ajax
首先封裝一個支持 Promise 的 ajax 方法,不理解這塊代碼的話,也沒有關係,後文會逐步講解 Promise 的執行機制編程
function request(url,data = {}){
return new Promise((resolve,reject)=>{
$.ajax({
url,
data,
success:function (data) {
resolve(data);
},
error:function (error) {
reject(error);
}
})
});
}
複製代碼
用 request 方法實現前面多個互相依賴的網絡請求數組
let url1 = 'http://xxx.xxx.1';
let url2 = 'http://xxx.xxx.2';
let url3 = 'http://xxx.xxx.3';
request(url1)
.then((data)=>{
console.log(data);
return request(url2,data)
})
.then((data)=>{
console.log(data);
return request(url3,data)
})
.then((data)=>{
console.log(data)
})
.catch((error)=>{
console.log(error);
});
複製代碼
Promise 是一個構造函數,使用 new 操做符返回一個 promise 對象promise
構造函數接收一個 excutor 函數做爲參數
excutor 函數有兩個函數類型的參數 resolve 和 reject
let p = new Promise((resolve,reject)=>{
// 在 excutor 函數中執行異步操做
// 當異步操做完成後,調用 resolve 函數或 reject 函數
});
複製代碼
let p1 = new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('p1');
},1000);
});
// p1 的狀態一直爲 pending
複製代碼
let p2 = new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('p2');
resolve('我是p2的終值')
},1000);
});
// 代碼執行,1000ms內,p2 的狀態爲 pending
// 代碼執行,1000ms後,p2 的狀態爲 fulfilled
// 代碼執行,1000ms後,p2 的終值爲 '我是p2的終值'
複製代碼
let p = new Promise((resolve,reject)=>{
reject('error')
})
let p1 = new Promise((resolve,reject)=>{
resolve(p)
})
// p1 的狀態爲 rejected ,拒由於 error
複製代碼
let thenable1 = {
then:function(resolve,reject){
resolve(1)
}
}
let thenable2 = {
then:function(resolve,reject){
reject(2)
}
}
let thenable3 = {
then:function(resolve,reject){
throw new Error(3)
}
}
let thenable4 = {
then:function(fn1,fn2){
//不調用 fn1 fn2
}
}
let p1 = new Promise((resolve,reject)=>{
resolve(thenable1);
})
let p2 = new Promise((resolve,reject)=>{
resolve(thenable2);
})
let p3 = new Promise((resolve,reject)=>{
resolve(thenable3);
})
let p4 = new Promise((resolve,reject)=>{
resolve(thenable4);
})
// p1 的狀態爲 fulfilled 終值爲 1
// p2 的狀態爲 rejected 終值爲 2
// p3 的狀態爲 rejected 拒由於 Error:3
// p4 的狀態爲 pending
複製代碼
let p3 = new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('p3');
reject('我是p3的拒因')
},1000);
});
// 代碼執行,1000ms內,p3 的狀態爲 pending
// 代碼執行,1000ms後,p3 的狀態爲 rejected
// 代碼執行,1000ms後,p3 的拒由於 '我是p3的拒因'
複製代碼
promise 提供一個 then 方法,用於訪問其終值和拒因。
promise 的 then 方法接受兩個參數:
promise.then(onFulfilled, onRejected);
複製代碼
new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('異步任務獲取的數據')
},50)
}).then((data)=>{
console.log(data)
})
// 異步任務獲取的數據
複製代碼
new Promise((resolve,reject)=>{
setTimeout(()=>{
reject(new Error('異步任務異常'))
},50)
}).then(null,(error)=>{
console.log(error)
})
// Error: 異步任務異常
複製代碼
new Promise((resolve,reject)=>{
throw new Error('拋出一個異常');
}).then(null,(error)=>{
console.log(error)
})
// Error: 拋出一個異常
複製代碼
若是 onFulfilled 是函數:
若是 onRejected 是函數:
console.log(1);
setTimeout(function(){
console.log(2)
},0)
new Promise((resolve,reject)=>{
resolve(3);
}).then((data)=>{
console.log(data);
})
console.log(4)
// print: 1 4 3 2
複製代碼
function fn1(){
new Promise((resolve)=>{
resolve();
}).then(function(){
console.log(this)
})
}
function fn2(){
"use strict";
new Promise((resolve)=>{
resolve();
}).then(function(){
console.log(this)
})
}
fn1(); // print: window
fn2(); // print: undefined
複製代碼
let p = new Promise((resolve)=>{
resolve()
});
let p1 = p.then(()=>{
console.log('異步執行,第一個onFulfilled');
});
let p2 = p.then(()=>{
console.log('異步執行,第二個onFulfilled');
});
console.log(p1.constructor === Promise);
console.log(p === p1);
console.log(p === p2);
console.log(p1 === p2);
// print: true
// print: false
// print: false
// print: false
// print: 異步執行,第一個onFulfilled
// print: 異步執行,第二個onFulfilled
複製代碼
then 方法返回一個 promise 對象
promise2 = promise1.then(onFulfilled, onRejected);
複製代碼
let p = new Promise((resolve,reject)=>{
throw new Error();
});
let p1 = p.then(null,(data)=>{
return '我是p2的終值'
});
p1.then((data)=>{
console.log(data)
});
// print: 我是p2的終值
複製代碼
let p1 = new Promise((resolve,reject)=>{
resolve(1)
})
let p2 = new Promise((resolve,reject)=>{
reject(2)
})
let p3 = new Promise((resolve)=>{
resolve()
})
let p4 = p3.then(()=>{
return p1;
})
let p5 = p3.then(()=>{
return p2;
})
// p4 的狀態爲 fulfilled 終值爲 1
// p5 的狀態爲 rejected 拒由於 2
複製代碼
let thenable1 = {
then:function(resolve,reject){
resolve(1)
}
}
let thenable2 = {
then:function(resolve,reject){
reject(2)
}
}
let p1 = new Promise((resolve,reject)=>{
resolve()
})
let p2 = p1.then(()=>{
return thenable1;
})
let p3 = p1.then(()=>{
return thenable2;
})
// p2 的狀態爲 fulfilled 終值爲 1
// p3 的狀態爲 rejected 拒由於 2
複製代碼
let p = new Promise((resolve,reject)=>{
resolve();
});
let p1 = p.then((data)=>{
throw new Error('error')
});
p1.then(null,(err)=>{
console.log(err);
});
// print: Error: error
複製代碼
let p = new Promise((resolve,reject)=>{
resolve('我是p1的終值');
});
let p1 = p.then(null,null);
p1.then((data)=>{
console.log(data);
});
// print: 我是p1的終值
複製代碼
let p = new Promise((resolve,reject)=>{
reject('我是p1的拒因');
});
let p1 = p.then(null,null);
p1.then(null,(err)=>{
console.log(err);
});
// print:我是p1的拒因
複製代碼
let p = new Promise((resolve,reject)=>{
resolve('我是p的終值');
});
let p1 = p.then((data)=>{
throw new Error('異常')
});
p1.then(null,(err)=>{
console.log(err);
});
// print:Error: 異常
複製代碼
let p1 = new Promise((resolve,reject)=>{
resolve(1)
})
let p2 = new Promise((resolve,reject)=>{
reject(2)
})
let p3 = p1.then(null,null);
let p4 = p2.then(null,null);
// p3 的狀態是 fulfilled 終值 1
// p4 的狀態是 rejected 拒因 2
p5 = p3.then(null,null);
p6 = p4.then(null,null);
// p3 的狀態是 fulfilled 終值 1
// p4 的狀態是 rejected 拒因 2
複製代碼
let fn1 = function(){}
let fn2 = function(){}
let fn3 = function(){}
let fn4 = function(){}
let fn5 = function(){}
let onError = function(){};
new Promise((resolve,reject)=>{
setTimeout(function(){
reject()
})
})
.then(fn1)
.then(fn2)
.then(fn3)
.then(fn4)
.then(fn5)
.then(null,onError)
複製代碼
fn一、fn二、fn三、fn四、fn5 均可能發生錯誤,經過在最後的then函數註冊的 onRejected 函數接收可能發生異常錯誤
catch(fn) 方法其實是 then(null,fn) 方法的別名,catch 方法的返回值以及 catch 方法中出現異常的狀況與調用 then 方法相同
new Promise((resolve,reject)=>{
reject()
}).then(null,function(error){
})
// 等同於
new Promise((resolve,reject)=>{
reject()
}).catch(function(error){
})
複製代碼
let p = Promise.resolve(x)
// 等價於
let p = new Promise((resolve)=>{
resolve(x)
})
複製代碼
let p = Promise.reject(x)
// 等價於
let p = new Promise((resolve,reject)=>{
reject(x)
})
複製代碼
const p = Promise.all([p1, p2, p3]);
複製代碼
let p1 = Promise.resolve(1);
let p2 = Promise.resolve(2);
let p3 = 3;
Promise.all([p1,p2,p3]).then((data)=>{
console.log(data); // print: [1,2,3]
})
複製代碼
let p1 = Promise.resolve(1);
let p2 = new Promise((resolve,reject)=>{
setTimeout(function(){
reject('p2 error')
},1000)
})
let p3 = new Promise((resolve,reject)=>{
setTimeout(function(){
reject('p3 error')
},500)
})
Promise.all([p1,p2,p3]).catch((error)=>{
console.log(error); // print: p3 error
})
複製代碼
const p = Promise.race([p1, p2, p3]);
複製代碼
let p1 = Promise.resolve(1);
let p2 = new Promise((resolve,reject)=>{
setTimeout(function(){
reject('p2 error')
},1000)
})
let p3 = new Promise((resolve,reject)=>{
setTimeout(function(){
reject('p3 error')
},500)
})
Promise.race([p1,p2,p3]).then(data=>{
console.log(data);
}).catch(error=>{
console.log(error);
})
// print: 1
複製代碼
let p1 = new Promise((resolve,reject)=>{
setTimeout(function(){
resolve(1)
},1000)
})
let p2 = new Promise((resolve,reject)=>{
setTimeout(function(){
reject('p2 error')
},800)
})
let p3 = new Promise((resolve,reject)=>{
setTimeout(function(){
reject('p3 error')
},500)
})
Promise.race([p1,p2,p3]).then(data=>{
console.log(data);
}).catch(error=>{
console.log(error);
})
// print: p3 error
複製代碼
當 promise 的狀態爲 rejected 且爲對 promise 對象使用 catch 方法,此時的異常信息會被 promise 對象吃掉 能夠經過監聽 unhandledRejection 事件,專門監聽未捕獲的reject錯誤
// node 環境下
process.on('unhandledRejection', error => {
console.log('unhandledRejection', error);
});
// 瀏覽器下
window.addEventListener('unhandledrejection',(e)=>{
e.preventDefault();
console.log(e);
});
複製代碼
const promise = new Promise((resolve, reject) => {
console.log(1)
resolve()
console.log(2)
})
promise.then(() => {
console.log(3)
})
console.log(4)
複製代碼
結果:1 2 4 3
const promise = new Promise((resolve, reject) => {
resolve('success1')
reject('error')
resolve('success2')
})
promise
.then((data) => {
console.log(data)
})
.catch((err) => {
console.log(err)
})
複製代碼
結果:success1
Promise.resolve(1)
.then((data) => {
console.log(data)
return 2
})
.catch((err) => {
return 3
})
.then((data) => {
console.log(data)
})
複製代碼
結果:1 2
Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)
複製代碼
結果:1
new Promise((resolve,reject)=>{
console.log(3);
let p = new Promise((resolve, reject)=>{
console.log(7);
setTimeout(()=>{
console.log(5);
resolve(6);
},0)
resolve(1);
});
resolve(2);
p.then((arg)=>{
console.log(arg);
});
}).then((arg)=>{
console.log(arg);
});
console.log(4);
複製代碼
結果:3 7 4 1 2 5
以上題目,若有疑問,可在留言區與我互動詢問
歡迎關注微信公衆號
【前端小黑屋】
,每週1-3篇精品優質文章推送,助你走上進階之旅