Promise與異步編程
因為執行引擎是單線程的,所以需要跟蹤即將運行的代碼,那些代碼被放在一個任務隊列中,每當一段代碼準備執行時,都會被添加到任務隊列中,每當引擎中的一段代碼結束執行,事件循環會執行隊列中的一下個任務。
Promise相當於異步操作結果佔位符,它不會去訂閱一個事件,也不會傳遞一個回調函數給目標函數,而是讓函數返回一個Promise,就像這樣
// readFile承諾在未來的某個刻完成
let promise = readFile('txx.txt')
Promise的生命週期
- pending
- fulfilled 成功
- rejected 程序錯誤或一些其他原因
[[PromiseState]]內部屬性被用來表示Promise的3種狀態,這個屬性不暴露在Promise對象上,所以不能以編程的方式檢測Promise的狀態,只有當Promise狀態改變時,通過then()方法來採取特定的行為。所以Promise都有then方法,它接受兩個參數,fulfilled和rejected時的兩個回調函數
如果一個對象實現了上述的then方法,那這個對象我們就稱之為thenable對象,所有的Promise對象都是thenable對象,但並非所有thenable對象都是Promise。
let promise = readFile("example.txt");
promise.then(function(contents){
// 完成
},function(err){
// 拒絕
})
promise.then(function(contents){
// 完成
})
promise.then(null,function(err){
// 拒絕
})
// catch等同於上面這種
promise.catch(function(err){
// 拒絕
})
如果向Promise.resolve()方法或Promise.reject()方法傳入一個Promise,那麼這個Promise會被直接返回
Nodejs環境的拒絕處理
- unhandledRejection
- rejectionHandled
let rejected;
process.on("unhandledRejection",function(reason,promise){
console.log(reason.message); // "Explosin"
console.log(rejected === promise); // "Explosin"
})
rejected = Promise.reject(new Error('Explosin'))
串聯Promise及鏈式返回值
let p1 = new Promise(function(resolve,reject){
resolve(42)
})
p1.then(function(value){
console.log(value)
return value+1;
})
.then(function(value){
console.log(value); // "43"
})
let p1 = new Promise(function(resolve,reject){
reject(42)
})
p1.catch(function(value){
console.log(value) // 42
return value+1;
})
.then(function(value){
console.log(value); // "43"
})
在Promsie鏈返回Promise
Promise.all()
只接受一個參數並返回一個Promise,該參數是一個含有多個受監視Promise的可迭代對象,只有當可迭代對象中所有Promise都被解決後返回的Promise才會被解決,只有當可迭代對象中所有Promise都完成後返回的promise才會被完成。只要有一個reject,就不用等所有的都完成就會被reject。
let p1 = new Promise(function(resolve,reject){
resolve(42)
})
let p2 = new Promise(function(resolve,reject){
reject(43)
})
let p3 = new Promise(function(resolve,reject){
resolve(44)
})
let p4 = Promise.all([p1,p2,p3])
p4.catch(function(value){
console.log(Array.isArray(value)); //false
console.log(value); // 43
})
Promise.race()
只要有一個resolve,不用等所有的都被完成。一旦數組中的某個Promise被完成,Promise.race()方法也會像Promise.all()方法一樣返回一個特定的Promise
Promise繼承
class MyPromise extends Promise {
// 使用默認的構造函數
success(resolove,reject){
return this.then(resolove,reject)
}
failure(reject){
return this.catch(reject)
}
}
let promise = new MyPromise(function(resolve,reject){
resolve(42)
})
promise.success(function(value){
console.log(value) // 42
})
.failure(function(value){
console.log(value)
})
基於Promise的異步任務執行
改造之前的文件讀取功能。只要每個異步操作都返回Promise,就可以極大地簡化並能用化這個過程。以Promise作為通用接口用於所有異步代碼可以簡化任務執行器。
let fs = require("fs");
function run(taskDef){
// 創建迭代器
let task = taskDef()
// 開始執行任務
let result = task.next();
// 遞歸函數遍歷
(function step(){
// 如果有更多任務要做
if(!result.done){
// 用一個Promise來解決會簡化問題
let promise = Promise.resolove(result.value);
promise.then(function(value){
result = task.next(value);
step()
})
.catch(function(error){
result = task.throw(error);
step();
})
}
}())
}
// 定義一個可用於任務執行器的函數
function readFile(filename){
return new Promise(function(resolove,reject){
fs.readFile(filename,function(err,contents){
if(err){
reject(err);
} else {
resolove(contents)
}
})
})
}
// 執行一個任務
run(function *(){
let contents = yield readFile("config.json");
doSomethingWith(contents);
console.log("Done")
})
主題測試文章,只做測試使用。發佈者:Walker,轉轉請注明出處:https://walker-learn.xyz/archives/4337