Promise對象原理解析
ES6 原生提供了 Promise 對象。
所謂 Promise,就是一個對象,用來傳遞異步操作的消息。它代表了某個未來才會知道結果的事件(通常是一個異步操作)晒屎,并且這個事件提供統(tǒng)一的 API,可供進一步處理缓升。
異步方法的各種調用形式
以ajax請求為例
- ES5正常寫法
這種寫法缺點如果在回調中還有需要執(zhí)行的異步方法鼓鲁,容易進入套娃模式。
$.get(url,(res)=>{
//此處執(zhí)行請求成功的回調
$.get(url2,(res2)=>{
//此處執(zhí)行請求成功的回調2
...
...
})
})
- Promise寫法
getAjax(url).then((res)=>{
//此處執(zhí)行請求成功的回調
})
- async_await 寫法
(async ()=>{
//await等待異步方法的執(zhí)行仔沿,執(zhí)行成功將響應結果返回
let res = await getAjax(url)
})()
總結:
- ES5寫法和promise寫法坐桩,主要區(qū)別在寫法的不同,可以讓回調函數(shù)封锉,劃分出去在.then的函數(shù)里去執(zhí)行绵跷,使得代碼更加的易讀,也可以將兩個不同的參數(shù)成福,劃分開來寫碾局。
- async_await和promise的區(qū)別,async_await只是promise實現(xiàn)的語法糖而已奴艾,這種形式的寫法在底層編譯之后會自動轉化成promise的寫法
Promise實現(xiàn)原理(自已實現(xiàn)MyPromise對象)
創(chuàng)建類構造對象
class MyPromise{
constructor(fn) {
//將成功的事件函數(shù)集成在successList數(shù)組里
this.successList = [];
//這里將所有的失敗函數(shù)集成到failList里
this.failList = []
//pending,fullfilled,rejected
this.state = "pending"
//傳入的函數(shù)對象,(異步操作的函數(shù)內容)
fn(this.resolveFn.bind(this),this.rejectFn.bind(this))
}
}
構造函數(shù)的作用:
- 聲明成功函數(shù)放置的數(shù)組對象
- 聲明失敗函數(shù)放置的數(shù)組對象
- 定義初始化狀態(tài)
- 調用傳入進行執(zhí)行異步內容的函數(shù)(在未來有成功的結果時調用傳入進去的成功函數(shù)净当,在未來失敗時調用傳入進行的失敗函數(shù))
在MyPromise對象中定義 接收“成功或者失敗”時需要調用的函數(shù)
將“成功或者失敗函數(shù)”存放到成功函數(shù)隊列和失敗函數(shù)隊列中,以便在事件完成時調用蕴潦。
class MyPromise{
constructor(fn) {
//將成功的事件函數(shù)集成在successList數(shù)組里
this.successList = [];
//這里將所有的失敗函數(shù)集成到failList里
this.failList = []
//pending,fullfilled,rejected
this.state = "pending"
//傳入的函數(shù)對象,(異步操作的函數(shù)內容)
fn(this.resolveFn.bind(this),this.rejectFn.bind(this))
}
//then方法接收成功或者失敗時需要調用的函數(shù)像啼,將函數(shù)存放到成功或失敗函數(shù)隊列中
then(successFn,failFn){
if(typeof successFn=='function'){
this.successList.push(successFn)
}
if(typeof failFn=='function'){
this.failList.push(failFn)
}
}
//catch方法接收失敗時需要調用的函數(shù),將函數(shù)存放到失敗函數(shù)隊列中
catch(failFn){
if(typeof failFn=='function'){
this.failList.push(failFn)
}
}
}
作用:
- 接收成功和失敗的函數(shù)放到成功和失敗的函數(shù)隊列里
定義 在事件完成時 調用成功函數(shù)和失敗函數(shù)的 函數(shù)(有點繞)
class MyPromise{
constructor(fn) {
//將成功的事件函數(shù)集成在successList數(shù)組里
this.successList = [];
//這里將所有的失敗函數(shù)集成到failList里
this.failList = []
//pending,fullfilled,rejected
this.state = "pending"
//傳入的函數(shù)對象,(異步操作的函數(shù)內容)
fn(this.resolveFn.bind(this),this.rejectFn.bind(this))
}
//then方法接收成功或者失敗時需要調用的函數(shù)潭苞,將函數(shù)存放到成功或失敗函數(shù)隊列中
then(successFn,failFn){
if(typeof successFn=='function'){
this.successList.push(successFn)
}
if(typeof failFn=='function'){
this.failList.push(failFn)
}
}
//catch方法接收失敗時需要調用的函數(shù)忽冻,將函數(shù)存放到失敗函數(shù)隊列中
catch(failFn){
if(typeof failFn=='function'){
this.failList.push(failFn)
}
}
//當事件成功時,執(zhí)行此函數(shù)此疹,此函數(shù)會執(zhí)行成功函數(shù)隊列中的所有函數(shù)
resolveFn(res){
this.state = "fullfilled"
//循環(huán)調用成功函數(shù)隊列中的函數(shù)
this.successList.forEach(function(item,index){
//將成功的事件循環(huán)調用
item(res)
})
}
//當事件失敗時僧诚,執(zhí)行此函數(shù)遮婶,此函數(shù)會執(zhí)行失敗函數(shù)隊列中的所有函數(shù)
rejectFn(res){
this.state = 'rejected'
//循環(huán)調用失敗函數(shù)隊列中的函數(shù)
this.failList.forEach(function(item,index){
item(res)
})
throw Error(res);
}
}
作用:
- 成功時調用成功數(shù)組里所有的函數(shù),失敗時調用失敗數(shù)組里所有的函數(shù)湖笨。
應用MyPromise對象
以node中fs模塊為例旗扑,我們使用MyPromise對象封裝一個fs讀取文件的方法
引入fs
let fs = require('fs');
封裝fsRead方法,讀取文件
//例:使用MyPromise對象封裝一個fs模塊方法
function fsRead(path){
return new MyPromise(function(resolve,reject){
fs.readFile(path,{flag:'r',encoding:"utf-8"},function(err,data){
if(err){
reject(err)
}else{
resolve(data)
}
})
})
}
準備需要讀取的文件test.txt
小池
作者:楊萬里
泉眼無聲惜細流慈省,樹陰照水愛晴柔臀防。
小荷才露尖尖角,早有蜻蜓立上頭边败。
調用fsRead方法讀取test.txt文件
(async ()=>{
//需要讀取的文件路徑
let path = './test.txt';
//調用我們使用MyPromise對象封裝的fsRead方法異步方法
//Promise寫法
fsRead(path).then((data)=>{
console.log("===========Promise寫法=============")
console.log(data)
})
//async_await寫法
let data = await fsRead(path)
console.log("===========async_await寫法=============")
console.log(data)
})()
執(zhí)行 node node .\mypromise.js控制臺輸入
PS E:\Workspace_VSCode\node-in-action> node .\promise.js
===========Promise寫法=============
小池
作者:楊萬里
泉眼無聲惜細流清钥,樹陰照水愛晴柔。
小荷才露尖尖角放闺,早有蜻蜓立上頭。
===========async_await寫法=============
小池
作者:楊萬里
泉眼無聲惜細流缕坎,樹陰照水愛晴柔怖侦。
小荷才露尖尖角,早有蜻蜓立上頭谜叹。
完整代碼
let fs = require('fs');
class MyPromise{
constructor(fn) {
//將成功的事件函數(shù)集成在successList數(shù)組里
this.successList = [];
//這里將所有的失敗函數(shù)集成到failList里
this.failList = []
//pending,fullfilled,rejected
this.state = "pending"
//傳入的函數(shù)對象,(異步操作的函數(shù)內容)
fn(this.resolveFn.bind(this),this.rejectFn.bind(this))
}
then(successFn,failFn){
if(typeof successFn=='function'){
this.successList.push(successFn)
}
if(typeof failFn=='function'){
this.failList.push(failFn)
}
}
catch(failFn){
if(typeof failFn=='function'){
this.failList.push(failFn)
}
}
resolveFn(res){
this.state = "fullfilled"
this.successList.forEach(function(item,index){
//將成功的事件循環(huán)調用
item(res)
})
}
rejectFn(res){
this.state = 'rejected'
//注冊到的失敗所有事件進行調用
this.failList.forEach(function(item,index){
item(res)
})
throw Error(res);
}
}
//例:使用MyPromise對象封裝一個fs模塊方法
function fsRead(path){
return new MyPromise(function(resolve,reject){
fs.readFile(path,{flag:'r',encoding:"utf-8"},function(err,data){
if(err){
reject(err)
}else{
resolve(data)
}
})
})
}
(async ()=>{
//需要讀取的文件路徑
let path = './test.txt';
//調用我們使用MyPromise對象封裝的fsRead方法異步方法
//Promise寫法
fsRead(path).then((data)=>{
console.log("===========Promise寫法=============")
console.log(data)
})
let data = await fsRead(path)
console.log("===========async_await寫法=============")
console.log(data)
})()