我雙手敲著鍵盤,就無法抱著你,雙手放開鍵盤,就無法養你~~~~~,誒,還是繼續寫文章吧!
本文主要是簡單介紹下Promise及使用,如有錯誤,歡迎指正,這廂有禮了!
什麼是Promise
Promise是ES6新增的一個特徵,它已被列入ES6的正式規範中。
萬物生必有因,Promise的產生有以下三個原因。
1. 解決回撥地獄問題(回撥函式多層巢狀,此處不貼程式碼了)。
2. 可以進行鏈式呼叫(通過then,後續詳解then)。
p.then((data)=> {
console.log(1);
},(err)=> {
console.log(2);
}).then((data)=>{
console.log('成功態');
},(err)=>{
console.log('失敗態');
});
複製程式碼
3. 解決併發非同步,在同一時刻內獲取的併發結果。
let fs = require("fs");
function after(times, callback) { // 可以快取函式,當條件達到時---本函式快取了times的值
let arr = [];
return function (data) {
arr.push(data);
if (--times === 0) {
// 當執行兩次後進入本方法
callback(arr);
}
}
}
// 本方法在同一時刻列印出 兩個非同步併發的結果。
let out = after(2,function(arr){
console.log(arr);
});
fs.readFile('./2.txt','utf8',function(err,data){out(data)});
fs.readFile('./2.txt','utf8',function(err,data){out(data)});
複製程式碼
Promise 的三個狀態
- resolved(成功態)
- rejected(失敗態)
- pending (初始狀態,未完成)
備註: Promise這個名字的英語意思是承諾,表示其他手段無法改變。狀態一旦從pending 狀態 執行為resolved或rejected ,結果就固定了,resolved 和rejected兩種狀態結果不會互相轉換;
配合以下(模擬Promise實現原始碼)程式碼,更容易理解,resolved和rejected兩種狀態不可改變的特性。
function Promise(executor) {//executor 執行器--函式
let self = this;
self.status = "pending"; // 等待狀態
function resolve(value) { // 成功
if (self.status == "pending") {// 由pending 狀態轉為resolved
self.status = "resolved";
}
}
function reject(reason) {// 失敗
if (self.status == "pending") {// 由pending 狀態轉為rejected
self.status = "rejected";
}
executorz(resolve, reject);
}
例項:
var p = new Promise(function (resolve, reject) {
if(/* 非同步操作成功 */){
resolve(); // 此函式執行,代表由 pending 狀態轉為 resolved狀態
} else {
reject(); // 此函式執行,代表由pending 狀態轉為 rejected 狀態
}
});
複製程式碼
Promise 的 then方法
使用案例:
var p = new Promise(function (resolve, reject) {
if(/* 非同步操作成功 */){
resolve(value);
} else {
reject(err);
}
});
// p.then(onFulfilled,onRejected) onFulfilled引數代表成功態,onRejected代表失敗態。
p.then((value)=>{
// 成功態,value是上面resolve傳入的值,可能是普通值(如:1,"34"),可能是Promise物件;如果vaule是普通值,則會作為下一次then的onRejected;如果是Promise物件,需要等待返回的promise執行後的結果傳遞給下一次then的onFulfilled或onRejected。
}, (err)=> {
// 失敗態,err是上面reject傳入的值
}).then((value)=>{
// 如果第一個then 返回的是普通值(不管是成功態返回的,還是失敗態返回的)都會進人當前then的成態裡,
},(err)=>{
});
複製程式碼
備註:
- then方法返回的是一個新的Promise例項(注意,不是原來那個Promise例項)。因此可以採用鏈式寫法,即then方法後面再呼叫另一個then方法。
- 上面的程式碼使用then方法,依次指定了兩個回撥函式。第一個回撥函式完成以後,會將返回結果作為引數,傳入第二個回撥函式。
- 上面程式碼中,第一個then方法指定的回撥函式,返回的是另一個Promise物件。這時,第二個then方法指定的回撥函式,就會等待這個新的Promise物件狀態發生變化。如果變為resolved,就呼叫funcA,如果狀態變為rejected,就呼叫funcB。
promise中的值穿透(then方法中可以什麼引數都不傳):
p.then().then().then((data)=>{
console.log("then的穿透效果");
// 成功態
},(err)=>{
// 失敗態
console.log('err:' + err);
});
複製程式碼
模擬then值穿透原始碼: Promise 的then方法是例項中的方法,所以寫在Promise的prototye上。
Promise.prototype.then = (onFulfilled, onRejected)=> {
// then方法中的 成功和失敗引數不傳,就給預設值,實現then值穿透的關鍵步驟;
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (value)=> {
return value;
}
onRejected = typeof onRejected === "function" ? onRejected :(err)=> {
throw err;// 只有丟擲錯誤才會走下一個then的失敗函式
// return err; 不能這麼寫的原因是錯誤函式只要有返回值,就會走下一個then的成功函式。
}
}
複製程式碼
promise 的catch 方法
Promise.prototype.catch 方法是由then(null,rejected)實現,專門用來指定發生錯誤時的回撥函式。
程式碼一:
p.then((data)=>{
},(err)=>{
}).then(null,(err)=>{
})
複製程式碼
程式碼二:
p.then((data)=>{
}).catch((err)=>{
});
複製程式碼
*** 程式碼一和程式碼二的效果一樣,實質也一樣。
原始碼實現catch方法:
Promise.prototype.catch=(onRejected)=>{
// catch 接收的引數只用於報錯。
return this.then(null, onRejected);
};
複製程式碼
Promise 的 all方法
例項:
Promise.all([read("1.txt"), read('2.txt')]).then(([one, two]) => {
// 此處返回的是一個陣列,因為all的引數的是一個陣列,所以返回值也是一個陣列====此處[one,two]用到了物件解構
console.log(one, two)
});
複製程式碼
備註:
- Promise.all 方法的引數是由Promise物件組成的陣列,執行後返回的依舊是promise陣列。
- all方法,多個任務全部成功才算是成功,如果有一個失敗了就算是失敗。
- all屬於promise的靜態方法,所以直接放到Promise類中。
配合以下(模擬all實現原始碼)程式碼,更容易理解。
Promise.all = function (promises) {
return new Promise((resolve,reject)=>{
let arr = [];
let i = 0; // i的目的是為了保證獲取全部成功,來設定的索引
function processData(index,data) {
arr[index] = data;
i++;
if (i === promises.length){
resolve(arr);
}
}
for(let i = 0;i<promises.length;i++){
promises[i].then(data=>{
processData(i,data); // 此處使用了遞迴
}, reject);
}
})
}
複製程式碼
Promise 的 race 方法
例項:
Promise.race([read("1.txt"), read('2.txt')]).then(data => {
console.log(data);
}).catch(err => {
console.log(err);
});
複製程式碼
備註:
- Promise.race方法的引數是由Promise物件組成的陣列,race翻譯為中文是‘賽跑’,誰最先有結果就返回誰的結果。 如果有一項任務先成功了,那就成功,如果有一項任務失敗了,那就是失敗。
- 返回的是布林值。
- race屬於promise的靜態方法,所以直接放到Promise類中。
配合以下(模擬race實現原始碼)程式碼,更容易理解。
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(resolve, reject);// promise 陣列中的promise物件執行,誰先resolve或者reject(有結果,不管成功或失敗)Promise.all 就會返回一個以此結果為準的promise物件。
}
});
}
複製程式碼
如果有錯誤,歡迎指正,時間不早了,回家做飯給媳婦賠罪去了。