Promise
對象是 JavaScript
的異步操做解決方案,爲異步操做提供統一接口。它起到代理做用(proxy),充當異步操做與回調函數之間的中介,使得異步操做具有同步操做的接口。javascript
Promise
可讓異步操做寫起來,就像在寫同步操做的流程,而沒必要一層層地嵌套回調函數。java
若是幾個異步操做之間並無先後順序之分,但須要等多個異步操做都完成後才能執行後續的任務,沒法實現並行節約時間。數組
在 ES6 Promises
標準中定義的API還不是不少,目前大體有下面三種類型。promise
首先,Promise
是一個對象,也是一個構造函數。bash
function f1(resolve, reject) {
// 異步代碼...
}
var promise = new Promise(f1);
複製代碼
Promise
對象經過自身的狀態,來控制異步操做。Promise實例具備三種狀態。異步
這三種的狀態的變化途徑只有兩種。函數
因此Promise
的最終結果只有兩個,ui
fulfilled
。rejected
。promise.then(onFulfilled, onRejected)
// resolve(成功)時,onFulfilled 會被調用
// reject(失敗)時,onRejected 會被調用
複製代碼
像 Promise
這樣的全局對象還擁有一些靜態方法。包括 Promise.all()
還有Promise.resolve()
等在內,主要都是一些對Promise
進行操做的輔助方法。this
Promise
的實現resolve
和reject
都是函數spa
//構造函數中
function Promise(executor) {
let self = this;
/*初始化status*/
self.status = 'pending';
/*初始化value*/
self.value = undefined;
/*訂閱事件的數組*/
self.onResolvedCallBacks = [];
self.onRejectedCallBacks = [];
/*此函數將Promise實例的狀態由pending 轉化爲 fulfilled*/
function resolve(value) {
if (value instanceof Promise) {
return value.then(resolve, reject);
}
setTimeout(function () {
if (self.status === 'pending') {
self.status = 'fulfilled';
self.value = value;
/*發佈已經訂閱過的事件*/
self.onResolvedCallBacks.forEach(item => item(self.value))
}
}, 0)
}
/*此函數將Promise實例的狀態由pending 轉化爲 rejected*/
function reject(reason) {
setTimeout(function () {
if (self.status === 'pending') {
self.status = 'rejected';
self.value = reason;
/*發佈已經訂閱過的事件*/
self.onRejectedCallBacks.forEach(item => item(self.value))
}
}, 0)
}
// new Promise 的時候,執行器(executor)的代碼會當即執行
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
複製代碼
promise
成功後,onFullfilled
會被調用。而且把promise
的值當作它的第一個參數。promise
在成功以前,不會調用它,而且只能被調用一次。reject
也同樣。調用 then
方法後,返回一個全新的 promise
。
// 先封裝一個方法
function resolvePromise(promise2,x,resolve,reject){
//
if(promise2 === x){
return reject(new TypeError('循環引用'));
}
// 爲了防止 resolve 和 reject 同時調用
let called = false;//promise2是否已經resolve 或reject了,防止重複調用
if(x instanceof Promise){
if(x.status == PENDING){
x.then(function(y){
resolvePromise(promise2,y,resolve,reject);
},reject);
}else{
x.then(resolve,reject);
}
//x是一個thenable對象或函數,只要有then方法的對象,
}else if(x!= null &&((typeof x=='object')||(typeof x == 'function'))){
//當咱們的promise和別的promise進行交互,編寫這段代碼的時候儘可能的考慮兼容性,
//容許別人瞎寫,x能夠是對象,也能夠是函數
try{
let then = x.then;
if(typeof then == 'function'){
//有些promise會同時執行成功和失敗的回調
then.call(x,function(y){
//若是promise2已經成功或失敗了,則不會再處理了
if(called)return;
called = true;
resolvePromise(promise2,y,resolve,reject)
},function(err){
if(called)return;
called = true;
reject(err);
});
}else{
//到此的話x不是一個thenable對象,那直接把它當成值resolve promise2就能夠了
// 當返回一個對象 {name:'a',then:{age:8}},對象裏的then不是thenable對象
resolve(x);
}
}catch(e){
if(called)return;
called = true;
reject(e);
}
}else{
//若是X是一個普通 的值,則用x的值去resolve promise2
resolve(x);
}
}
Promise.prototype.then = function(onFulfilled,onRejected){
//若是成功和失敗的回調沒有傳,則表示這個then沒有任何邏輯,只會把值日後拋,叫作值的穿透
// 例如:promise.then().then().then(function(data){},function(err){})
onFulfilled = typeof onFulfilled == 'function'?onFulfilled:function(value){return value};
onRejected = typeof onRejected == 'function'?onRejected:reason=>{throw reason};
//若是當前promise狀態已是成功態了,onFulfilled直接取值
let self = this;
let promise2;
if(self.status == FULFILLED){
return promise2 = new Promise(function(resolve,reject){
setTimeout(function(){
try{
let x =onFulfilled(self.value);
//若是獲取到了返回值x,會走解析promise的過程
resolvePromise(promise2,x,resolve,reject);
}catch(e){
//若是執行成功的回調過程當中出錯了,用錯誤緣由把promise2 reject
reject(e);
}
})
});
}
if(self.status == REJECTED){
return promise2 = new Promise(function(resolve,reject){
setTimeout(function(){
try{
let x =onRejected(self.value);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
})
});
}
if(self.status == PENDING){
return promise2 = new Promise(function(resolve,reject){
self.onResolvedCallbacks.push(function(){
try{
let x =onFulfilled(self.value);
//若是獲取到了返回值x,會走解析promise的過程
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
});
self.onRejectedCallbacks.push(function(){
try{
let x =onRejected(self.value);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
});
});
}
}
複製代碼
Promise.prototype.catch=function (callback) {
return this.then(null,callback);
}
---------使用-------
let promise = new Promise(function (resolve, reject) {
reject('錯誤');
})
promise.then(function(data){console.log(data)}).catch(e=>{console.log(e)});
複製代碼
Promise.all = function (promises) {
return new Promise(function (resolve,reject) {
let arr =[];//arr是最終返回值的結果的集合。
let j =0;
function processData(i,data){// 每調用一次此函數,j就會+1;
arr[i] = data;// 每次成功的結果都放入數組中
if(++j===promises.length){
resolve(arr); //只有promises中的最後一個成功,才能調用resolve方法。
}
}
for(let i=0;i<promises.length;i++){
promises[i].then(function (data) {
processData(i,data);
},reject)// 若是有一個失敗,總體就會失敗
}
})
}
複製代碼
使用方法:
function read(file) {
return new Promise1(function (resolve, reject) {
require('fs').readFile(file,'utf8',function (err, data) {
resolve(data);
})
})
}
Promise1.all([read('./1.txt'),read('./2.txt')]).then(function (data) {
console.log(data)
})
// ['file1','file2']
複製代碼
只要有一個promise成功,就會執行成功的回調,參數是由 promise 組成的數組
Promise.race=function (promises) {
return new Promise(function (resolve, reject) {
for(let i=0;i<promises.length;i++){
promises[i].then(resolve,reject);
}
})
}
複製代碼
Promise.resolve = function (value) {
return new Promise(function (resolve, reject) {
resolve(value)
})
}
複製代碼
Promise.reject = function (reason) {
return new Promise(function (resolve, reject) {
reject(reason);
})
}
複製代碼
Promise
對象的缺點:一、沒法取消Promise
,一旦新建它就會當即執行,沒法中途取消。
二、若是不設置回調函數,Promise
內部拋出的錯誤,不會反應到外部。
三、當處於Pending
狀態時,沒法得知目前進展到哪個階段(剛剛開始仍是即將完成)。