91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Promise的原理和基礎用法介紹

發布時間:2021-09-13 09:37:22 來源:億速云 閱讀:191 作者:chen 欄目:web開發

這篇文章主要介紹“Promise的原理和基礎用法介紹”,在日常操作中,相信很多人在Promise的原理和基礎用法介紹問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Promise的原理和基礎用法介紹”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

一、Promise基礎用法

1.1 基本用法

new Promise(function(resolve, reject) {
    //待處理的異步邏輯
    //處理結束后,調用resolve或reject方法
})
  • 新建一個promise很簡單,只需要new一個promise對象即可。所以promise本質上就是一個函數,它接受一個函數作為參數,并且會返回promise對象,這就給鏈式調用提供了基礎

  • 其實Promise函數的使命,就是構建出它的實例,并且負責幫我們管理這些實例。而這些實例有以下三種狀態:

  • pending: 初始狀態,位履行或拒絕

  • fulfilled: 意味著操作成功完成

  • rejected: 意味著操作失敗

pending 狀態的 Promise對象可能以 fulfilled狀態返回了一個值,也可能被某種理由(異常信息)拒絕(reject)了。當其中任一種情況出現時,Promise 對象的 then 方法綁定的處理方法(handlers)就會被調用,then方法分別指定了resolve方法和reject方法的回調函數

Promise的原理和基礎用法介紹

var promise = 
new Promise(function(resolve, reject) {
  if (/* 異步操作成功 */){
    resolve(value);
  } 
else {
    reject(error);
  }
});
promise.then(function(value) {
  // 如果調用了resolve方法,執行此函數
}, 
function(value) {
  // 如果調用了reject方法,執行此函數
});

上述代碼很清晰的展示了promise對象運行的機制。下面再看一個示例:

var getJSON = 
function(url) {
  var promise = 
new Promise(function(resolve, reject){
    var client = 
new XMLHttpRequest();
    client.open("GET", url);
    client.>
    client.responseType = 
"json";
    client.setRequestHeader("Accept", 
"application/json");
    client.send();
    function handler(
) {
      if (this.status === 
200) { 
              resolve(this.response); 
          } 
else { 
              reject(new Error(this.statusText)); 
          }
    };
  });
  return promise;
};
getJSON("/posts.json").then(function(json) {
  console.log('Contents: ' + json);
}, 
function(error) {
  console.error('出錯了', error);
});

上面代碼中,resolve方法和reject方法調用時,都帶有參數。它們的參數會被傳遞給回調函數。reject方法的參數通常是Error對象的實例,而resolve方法的參數除了正常的值以外,還可能是另一個Promise實例,比如像下面這樣。

var p1 = 
new Promise(function(resolve, reject){
  // ... some code
});
var p2 = 
new Promise(function(resolve, reject){
  // ... some code
  resolve(p1);
})

上面代碼中,p1p2都是Promise的實例,但是p2resolve方法將p1作為參數,這時p1的狀態就會傳遞給p2。如果調用的時候,p1的狀態是pending,那么p2的回調函數就會等待p1的狀態改變;如果p1的狀態已經是fulfilled或者rejected,那么p2的回調函數將會立刻執行

1.2 promise捕獲錯誤

Promise.prototype.catch方法是Promise.prototype.then(null, rejection)的別名,用于指定發生錯誤時的回調函數

getJSON("/visa.json").then(function(result) {
  // some code
}).catch(function(error) {
  // 處理前一個回調函數運行時發生的錯誤
  console.log('出錯啦!', error);
});

Promise對象的錯誤具有“冒泡”性質,會一直向后傳遞,直到被捕獲為止。也就是說,錯誤總是會被下一個catch語句捕獲

getJSON("/visa.json").then(function(json) {
  return json.name;
}).then(function(name) {
  // proceed
}).catch(function(error) {
    //處理前面任一個then函數拋出的錯誤
});

1.3 常用的promise方法

Promise.all方法

Promise.all方法用于將多個Promise實例,包裝成一個新的Promise實例

var p = 
Promise.all([p1,p2,p3]);
  • 上面代碼中,Promise.all方法接受一個數組作為參數,p1p2p3都是Promise對象的實例。(Promise.all方法的參數不一定是數組,但是必須具有iterator接口,且返回的每個成員都是Promise實例。)

p的狀態由p1p2p3決定,分成兩種情況

  • 只有p1p2p3的狀態都變成fulfilledp的狀態才會變成fulfilled,此時p1p2p3的返回值組成一個數組,傳遞給p的回調函數

  • 只要p1p2p3之中有一個被rejectedp的狀態就變成rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調函數

// 生成一個Promise對象的數組
var promises = [2, 
3, 
5, 
7, 
11, 
13].map(function(id){
  return getJSON("/get/addr" + id + 
".json");
});
Promise.all(promises).then(function(posts) {
  // ...  
}).catch(function(reason){
  // ...
});

Promise.race方法

Promise.race方法同樣是將多個Promise實例,包裝成一個新的Promise實例。

var p = 
Promise.race([p1,p2,p3]);

上面代碼中,只要p1p2p3之中有一個實例率先改變狀態,p的狀態就跟著改變。那個率先改變的Promise實例的返回值,就傳遞給p的返回值

  • 如果Promise.all方法和Promise.race方法的參數,不是Promise實例,就會先調用下面講到的Promise.resolve方法,將參數轉為Promise實例,再進一步處理

Promise.resolve

有時需要將現有對象轉為Promise對象,Promise.resolve方法就起到這個作用

var jsPromise = 
Promise.resolve($.ajax('/whatever.json'));

上面代碼將jQuery生成deferred對象,轉為一個新的ES6Promise對象

  • 如果Promise.resolve方法的參數,不是具有then方法的對象(又稱thenable對象),則返回一個新的Promise對象,且它的狀態為fulfilled

var p = 
Promise.resolve('Hello');
p.then(function (s){
  console.log(s)
});
// Hello
  • 上面代碼生成一個新的Promise對象的實例p,它的狀態為fulfilled,所以回調函數會立即執行,Promise.resolve方法的參數就是回調函數的參數

  • 如果Promise.resolve方法的參數是一個Promise對象的實例,則會被原封不動地返回

  • Promise.reject(reason)方法也會返回一個新的Promise實例,該實例的狀態為rejectedPromise.reject方法的參數reason,會被傳遞給實例的回調函數

var p = 
Promise.reject('出錯啦');
p.then(null, 
function (error){
  console.log(error)
});
// 出錯了

1.4 Async/await簡化寫法

function getDataAsync (url) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            var res = {
                url: url,
                data: 
Math.random()
            }
            resolve(res)
        }, 
1000)
    })
}
async function getData (
) {
    var res1 = 
await getDataAsync('/page/1?param=123')
    console.log(res1)
    var res2 = 
await getDataAsync(`/page/2?param=${res1.data}`)
    console.log(res2)
    var res3 = 
await getDataAsync(`/page/2?param=${res2.data}`)
    console.log(res3)
}

async/await 是基于 Promise 的,因為使用 async 修飾的方法最終返回一個 Promise, 實際上,async/await 可以看做是使用 Generator 函數處理異步的語法糖,我們來看看如何使用 Generator 函數處理異步

1.5 Generator

首先異步函數依然是:

function getDataAsync (url) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            var res = {
                url: url,
                data: 
Math.random()
            }
            resolve(res)
        }, 
1000)
    })
}

使用 Generator 函數可以這樣寫

function * 
getData (
) {
    var res1 = 
yield getDataAsync('/page/1?param=123')
    console.log(res1)
    var res2 = 
yield getDataAsync(`/page/2?param=${res1.data}`)
    console.log(res2)
    var res3 = 
yield getDataAsync(`/page/2?param=${res2.data}`)
    console.log(res3))
}

然后我們這樣逐步執行

var g = getData()
g.next().value.then(res1 => {
    g.next(res1).value.then(res2 => {
        g.next(res2).value.then(() => {
            g.next()
        })
    })
})

上面的代碼,我們逐步調用遍歷器的 next() 方法,由于每一個 next() 方法返回值的 value 屬性為一個 Promise 對象,所以我們為其添加 then 方法, 在 then方法里面接著運行 next 方法挪移遍歷器指針,直到 Generator 函數運行完成,實際上,這個過程我們不必手動完成,可以封裝成一個簡單的執行器

function run (gen) {
    var g = gen()

    function next (data) {
        var res = g.next(data)
        if (res.done) 
return res.value
        res.value.then((data) => {
            next(data)
        })
    }

    next()

}

run方法用來自動運行異步的 Generator 函數,其實就是一個遞歸的過程調用的過程。這樣我們就不必手動執行 Generator 函數了。 有了 run 方法,我們只需要這樣運行 getData 方法

run(getData)

這樣,我們就可以把異步操作封裝到 Generator 函數內部,使用 run 方法作為 Generator 函數的自執行器,來處理異步。其實我們不難發現, async/await 方法相比于 Generator 處理異步的方式,有很多相似的地方,只不過 async/await 在語義化方面更加明顯,同時 async/await 不需要我們手寫執行器,其內部已經幫我們封裝好了,這就是為什么說 async/await 是 Generator 函數處理異步的語法糖了

二、Promise實現原理剖析

2.1 Promise標準

  • Promise 規范有很多,如Promise/APromise/BPromise/D以及 Promise/A 的升級版 Promise/A+ES6中采用了 Promise/A+ 規范

中文版規范:  Promises/A+規范(中文)

Promise標準解讀

  • 一個promise的當前狀態只能是pendingfulfilledrejected三種之一。狀態改變只能是pendingfulfilled或者pendingrejected。狀態改變不可逆

  • promisethen方法接收兩個可選參數,表示該promise狀態改變時的回調(promise.then(onFulfilled, onRejected))。then方法返回一個promisethen 方法可以被同一個 promise 調用多次

2.2 實現Promise

構造函數

function Promise(resolver) {}

原型方法

Promise.prototype.then = 
function(
) {}
Promise.prototype.catch = 
function(
) {}

靜態方法

Promise.resolve = 
function(
) {}
Promise.reject = 
function(
) {}
Promise.all = 
function(
) {}
Promise.race = 
function(
) {}

2.3 極簡promise雛形

function Promise(fn) {
    var value = 
null,
        callbacks = [];  //callbacks為數組,因為可能同時有很多個回調
    this.then = 
function (onFulfilled) {
        callbacks.push(onFulfilled);
    };
    function resolve(value) {
        callbacks.forEach(function (callback) {
            callback(value);
        });
    }
    fn(resolve);
}

大致的邏輯是這樣的

  • 調用then方法,將想要在Promise異步操作成功時執行的回調放入callbacks隊列,其實也就是注冊回調函數,可以向觀察者模式方向思考

  • 創建Promise實例時傳入的函數會被賦予一個函數類型的參數,即resolve,它接收一個參數value,代表異步操作返回的結果,當一步操作執行成功后,用戶會調用resolve方法,這時候其實真正執行的操作是將callbacks隊列中的回調一一執行

//例1
function getUserId(
) {
    return new Promise(function(resolve) {
        //異步請求
        http.get(url, 
function(results) {
            resolve(results.id)
        })
    })
}
getUserId().then(function(id) {
    //一些處理
})
// 結合例子1分析

// fn 就是getUserId函數
function Promise(fn) {
    var value = 
null,
        callbacks = [];  //callbacks為數組,因為可能同時有很多個回調
    
    // 當用戶調用getUserId().then的時候開始注冊傳進來的回調函數
    // onFulfilled就是例子中的function(id){}
    // 把then的回調函數收集起來 在resolve的時候調用
    this.then = 
function (onFulfilled) {
        callbacks.push(onFulfilled);
    };
    
    // value是fn函數執行后返回的值
    function resolve(value) {
        // callbacks是傳給then的回調函數就是例子中的function(id){}
        // 遍歷用戶通過then傳遞進來的回調函數把resolve成功的結果返回給then調用即then(function(data){ console.log(data) }) 這里的data就是通過這里調用返回
        callbacks.forEach(function (callback) {
            callback(value);
        });
    }
    
    //執行fn函數即getUserId()并且傳入函數參數resolve 當fn執行完成返回的值傳遞給resolve函數
    fn(resolve);
}

結合例1中的代碼來看,首先new Promise時,傳給promise的函數發送異步請求,接著調用promise對象的then屬性,注冊請求成功的回調函數,然后當異步請求發送成功時,調用resolve(results.id)方法, 該方法執行then方法注冊的回調數組

  • then方法應該能夠鏈式調用,但是上面的最基礎簡單的版本顯然無法支持鏈式調用。想讓then方法支持鏈式調用,其實也是很簡單的

this.then = 
function (onFulfilled) {
    callbacks.push(onFulfilled);
    return this;
};

只要簡單一句話就可以實現類似下面的鏈式調用

// 例2
getUserId().then(function (id) {
    // 一些處理
}).then(function (id) {
    // 一些處理
});

2.4 加入延時機制

上述代碼可能還存在一個問題:如果在then方法注冊回調之前,resolve函數就執行了,怎么辦?比如promise內部的函數是同步函數

// 例3
function getUserId(
) {
    return new Promise(function (resolve) {
        resolve(9876);
    });
}
getUserId().then(function (id) {
    // 一些處理
});

這顯然是不允許的,Promises/A+規范明確要求回調需要通過異步方式執行,用以保證一致可靠的執行順序。因此我們要加入一些處理,保證在resolve執行之前,then方法已經注冊完所有的回調。我們可以這樣改造下resolve函數:

function resolve(value) {
    setTimeout(function(
) {
        callbacks.forEach(function (callback) {
            callback(value);
        });
    }, 
0)
}

上述代碼的思路也很簡單,就是通過setTimeout機制,將resolve中執行回調的邏輯放置到JS任務隊列末尾,以保證在resolve執行時,then方法的回調函數已經注冊完成

  • 但是,這樣好像還存在一個問題,可以細想一下:如果Promise異步操作已經成功,這時,在異步操作成功之前注冊的回調都會執行,但是在Promise異步操作成功這之后調用的then注冊的回調就再也不會執行了,這顯然不是我們想要的

2.5 加入狀態

我們必須加入狀態機制,也就是大家熟知的pendingfulfilledrejected

Promises/A+規范中的2.1 Promise States中明確規定了,pending可以轉化為fulfilledrejected并且只能轉化一次,也就是說如果pending轉化到fulfilled狀態,那么就不能再轉化到rejected。并且fulfilledrejected狀態只能由pending轉化而來,兩者之間不能互相轉換

Promise的原理和基礎用法介紹

//改進后的代碼是這樣的:

function Promise(fn) {
    var state = 
'pending',
        value = 
null,
        callbacks = [];
    this.then = 
function (onFulfilled) {
        if (state === 
'pending') {
            callbacks.push(onFulfilled);
            return this;
        }
        onFulfilled(value);
        return this;
    };
    function resolve(newValue) {
        value = newValue;
        state = 
'fulfilled';
        setTimeout(function (
) {
            callbacks.forEach(function (callback) {
                callback(value);
            });
        }, 
0);
    }
    fn(resolve);
}

上述代碼的思路是這樣的:resolve執行時,會將狀態設置為fulfilled,在此之后調用then添加的新回調,都會立即執行

2.6 鏈式Promise

如果用戶在then函數里面注冊的仍然是一個Promise,該如何解決?比如下面的例4

// 例4
getUserId()
    .then(getUserJobById)
    .then(function (job) {
        // 對job的處理
    });
function getUserJobById(id) {
    return new Promise(function (resolve) {
        http.get(baseUrl + id, 
function(job) {
            resolve(job);
        });
    });
}
  • 這種場景相信用過promise的人都知道會有很多,那么類似這種就是所謂的鏈式Promise

  • 鏈式Promise是指在當前promise達到fulfilled狀態后,即開始進行下一個promise(后鄰promise)。那么我們如何銜接當前promise和后鄰promise呢?(這是這里的難點

  • 只要在then方法里面return一個promise就好啦。Promises/A+規范中的2.2.7就是這樣

下面來看看這段暗藏玄機的then方法和resolve方法改造代碼

function Promise(fn) {
    var state = 
'pending',
        value = 
null,
        callbacks = [];
    this.then = 
function (onFulfilled) {
        return new Promise(function (resolve) {
            handle({
                onFulfilled: onFulfilled || 
null,
                resolve: resolve
            });
        });
    };
    function handle(callback) {
        if (state === 
'pending') {
            callbacks.push(callback);
            return;
        }
        //如果then中沒有傳遞任何東西
        if(!callback.onFulfilled) {
            callback.resolve(value);
            return;
        }
        var ret = callback.onFulfilled(value);
        callback.resolve(ret);
    }
    
    function resolve(newValue) {
        if (newValue && (typeof newValue === 
'object' || 
typeof newValue === 
'function')) {
            var then = newValue.then;
            if (typeof then === 
'function') {
                then.call(newValue, resolve);
                return;
            }
        }
        state = 
'fulfilled';
        value = newValue;
        setTimeout(function (
) {
            callbacks.forEach(function (callback) {
                handle(callback);
            });
        }, 
0);
    }
    fn(resolve);
}

我們結合例4的代碼,分析下上面的代碼邏輯,為了方便閱讀,我把例4的代碼貼在這里

// 例4
getUserId()
    .then(getUserJobById)
    .then(function (job) {
        // 對job的處理
    });
function getUserJobById(id) {
    return new Promise(function (resolve) {
        http.get(baseUrl + id, 
function(job) {
            resolve(job);
        });
    });
}
  • then方法中,創建并返回了新的Promise實例,這是串行Promise的基礎,并且支持鏈式調用

  • handle方法是promise內部的方法。then方法傳入的形參onFulfilled以及創建新Promise實例時傳入的resolve均被push到當前promisecallbacks隊列中,這是銜接當前promise和后鄰promise的關鍵所在

  • getUserId生成的promise(簡稱getUserId promise)異步操作成功,執行其內部方法resolve,傳入的參數正是異步操作的結果id

  • 調用handle方法處理callbacks隊列中的回調:getUserJobById方法,生成新的promise(getUserJobById promise

  • 執行之前由getUserId promisethen方法生成的新promise(稱為bridge promise)的resolve方法,傳入參數為getUserJobById promise。這種情況下,會將該resolve方法傳入getUserJobById promisethen方法中,并直接返回

  • getUserJobById promise異步操作成功時,執行其callbacks中的回調:getUserId bridge promise中的resolve方法

  • 最后執行getUserId bridge promise的后鄰promisecallbacks中的回調

2.7 失敗處理

在異步操作失敗時,標記其狀態為rejected,并執行注冊的失敗回調

//例5
function getUserId(
) {
    return new Promise(function(resolve) {
        //異步請求
        http.get(url, 
function(error, results) {
            if (error) {
                reject(error);
            }
            resolve(results.id)
        })
    })
}
getUserId().then(function(id) {
    //一些處理
}, 
function(error) {
    console.log(error)
})

有了之前處理fulfilled狀態的經驗,支持錯誤處理變得很容易,只需要在注冊回調、處理狀態變更上都要加入新的邏輯

function Promise(fn) {
    var state = 
'pending',
        value = 
null,
        callbacks = [];
    this.then = 
function (onFulfilled, onRejected) {
        return new Promise(function (resolve, reject) {
            handle({
                onFulfilled: onFulfilled || 
null,
                onRejected: onRejected || 
null,
                resolve: resolve,
                reject: reject
            });
        });
    };
    function handle(callback) {
        if (state === 
'pending') {
            callbacks.push(callback);
            return;
        }
        var cb = state === 
'fulfilled' ? callback.onFulfilled : callback.onRejected,
            ret;
        if (cb === 
null) {
            cb = state === 
'fulfilled' ? callback.resolve : callback.reject;
            cb(value);
            return;
        }
        ret = cb(value);
        callback.resolve(ret);
    }
    function resolve(newValue) {
        if (newValue && (typeof newValue === 
'object' || 
typeof newValue === 
'function')) {
            var then = newValue.then;
            if (typeof then === 
'function') {
                then.call(newValue, resolve, reject);
                return;
            }
        }
        state = 
'fulfilled';
        value = newValue;
        execute();
    }
    function reject(reason) {
        state = 
'rejected';
        value = reason;
        execute();
    }
    function execute(
) {
        setTimeout(function (
) {
            callbacks.forEach(function (callback) {
                handle(callback);
            });
        }, 
0);
    }
    fn(resolve, reject);
}

上述代碼增加了新的reject方法,供異步操作失敗時調用,同時抽出了resolvereject共用的部分,形成execute方法

錯誤冒泡是上述代碼已經支持,且非常實用的一個特性。在handle中發現沒有指定異步操作失敗的回調時,會直接將bridge promise(then函數返回的promise,后同)設為rejected狀態,如此達成執行后續失敗回調的效果。這有利于簡化串行Promise的失敗處理成本,因為一組異步操作往往會對應一個實際功能,失敗處理方法通常是一致的

//例6
getUserId()
    .then(getUserJobById)
    .then(function (job) {
        // 處理job
    }, 
function (error) {
        // getUserId或者getUerJobById時出現的錯誤
        console.log(error);
    });

2.8 異常處理

如果在執行成功回調、失敗回調時代碼出錯怎么辦?對于這類異常,可以使用try-catch捕獲錯誤,并將bridge promise設為rejected狀態。handle方法改造如下

function handle(callback) {
    if (state === 
'pending') {
        callbacks.push(callback);
        return;
    }
    var cb = state === 
'fulfilled' ? callback.onFulfilled : callback.onRejected,
        ret;
    if (cb === 
null) {
        cb = state === 
'fulfilled' ? callback.resolve : callback.reject;
        cb(value);
        return;
    }
    try {
        ret = cb(value);
        callback.resolve(ret);
    } 
catch (e) {
        callback.reject(e);
    } 
}

如果在異步操作中,多次執行resolve或者reject會重復處理后續回調,可以通過內置一個標志位解決

2.9 完整實現

// 三種狀態
const PENDING = 
"pending";
const RESOLVED = 
"resolved";
const REJECTED = 
"rejected";
// promise 接收一個函數參數,該函數會立即執行
function MyPromise(fn) {
  let _this = 
this;
  _this.currentState = PENDING;
  _this.value = 
undefined;
  // 用于保存 then 中的回調,只有當 promise
  // 狀態為 pending 時才會緩存,并且每個實例至多緩存一個
  _this.resolvedCallbacks = [];
  _this.rejectedCallbacks = [];

  _this.resolve = 
function (value) {
    if (value 
instanceof MyPromise) {
      // 如果 value 是個 Promise,遞歸執行
      return value.then(_this.resolve, _this.reject)
    }
    setTimeout(() => { 
// 異步執行,保證執行順序
      if (_this.currentState === PENDING) {
        _this.currentState = RESOLVED;
        _this.value = value;
        _this.resolvedCallbacks.forEach(cb => cb());
      }
    })
  };

  _this.reject = 
function (reason) {
    setTimeout(() => { 
// 異步執行,保證執行順序
      if (_this.currentState === PENDING) {
        _this.currentState = REJECTED;
        _this.value = reason;
        _this.rejectedCallbacks.forEach(cb => cb());
      }
    })
  }
  // 用于解決以下問題
  // new Promise(() => throw Error('error))
  try {
    fn(_this.resolve, _this.reject);
  } 
catch (e) {
    _this.reject(e);
  }
}

MyPromise.prototype.then = 
function (onResolved, onRejected) {
  var self = 
this;
  // 規范 2.2.7,then 必須返回一個新的 promise
  var promise2;
  // 規范 2.2.onResolved 和 onRejected 都為可選參數
  // 如果類型不是函數需要忽略,同時也實現了透傳
  // Promise.resolve(4).then().then((value) => console.log(value))
  typeof 'function' ? onResolved : 
v => v;
  typeof 'function' ? onRejected : 
r => throw r;

  if (self.currentState === RESOLVED) {
    return (promise2 = 
new MyPromise(function (resolve, reject) {
      // 規范 2.2.4,保證 onFulfilled,onRjected 異步執行
      // 所以用了 setTimeout 包裹下
      setTimeout(function (
) {
        try {
          var x = onResolved(self.value);
          resolutionProcedure(promise2, x, resolve, reject);
        } 
catch (reason) {
          reject(reason);
        }
      });
    }));
  }

  if (self.currentState === REJECTED) {
    return (promise2 = 
new MyPromise(function (resolve, reject) {
      setTimeout(function (
) {
        // 異步執行onRejected
        try {
          var x = onRejected(self.value);
          resolutionProcedure(promise2, x, resolve, reject);
        } 
catch (reason) {
          reject(reason);
        }
      });
    }));
  }

  if (self.currentState === PENDING) {
    return (promise2 = 
new MyPromise(function (resolve, reject) {
      self.resolvedCallbacks.push(function (
) {
        // 考慮到可能會有報錯,所以使用 try/catch 包裹
        try {
          var x = onResolved(self.value);
          resolutionProcedure(promise2, x, resolve, reject);
        } 
catch (r) {
          reject(r);
        }
      });

      self.rejectedCallbacks.push(function (
) {
        try {
          var x = onRejected(self.value);
          resolutionProcedure(promise2, x, resolve, reject);
        } 
catch (r) {
          reject(r);
        }
      });
    }));
  }
};
// 規范 2.3
function resolutionProcedure(promise2, x, resolve, reject) {
  // 規范 2.3.1,x 不能和 promise2 相同,避免循環引用
  if (promise2 === x) {
    return reject(new TypeError("Error"));
  }
  // 規范 2.3.2
  // 如果 x 為 Promise,狀態為 pending 需要繼續等待否則執行
  if (x 
instanceof MyPromise) {
    if (x.currentState === PENDING) {
      x.then(function (value) {
        // 再次調用該函數是為了確認 x resolve 的
        // 參數是什么類型,如果是基本類型就再次 resolve
        // 把值傳給下個 then
        resolutionProcedure(promise2, value, resolve, reject);
      }, reject);
    } 
else {
      x.then(resolve, reject);
    }
    return;
  }
  // 規范 2.3.3.3.3
  // reject 或者 resolve 其中一個執行過得話,忽略其他的
  let called = 
false;
  // 規范 2.3.3,判斷 x 是否為對象或者函數
  if (x !== 
null && (typeof x === 
"object" || 
typeof x === 
"function")) {
    // 規范 2.3.3.2,如果不能取出 then,就 reject
    try {
      // 規范 2.3.3.1
      let then = x.then;
      // 如果 then 是函數,調用 x.then
      if (typeof then === 
"function") {
        // 規范 2.3.3.3
        then.call(
          x,
          y => {
            if (called) 
return;
            called = 
true;
            // 規范 2.3.3.3.1
            resolutionProcedure(promise2, y, resolve, reject);
          },
          e => {
            if (called) 
return;
            called = 
true;
            reject(e);
          }
        );
      } 
else {
        // 規范 2.3.3.4
        resolve(x);
      }
    } 
catch (e) {
      if (called) 
return;
      called = 
true;
      reject(e);
    }
  } 
else {
    // 規范 2.3.4,x 為基本類型
    resolve(x);
  }
}

2.10 小結

這里一定要注意的點是promise里面的then函數僅僅是注冊了后續需要執行的代碼,真正的執行是在resolve方法里面執行的,理清了這層,再來分析源碼會省力的多

現在回顧下Promise的實現過程,其主要使用了設計模式中的觀察者模式

  • 通過Promise.prototype.thenPromise.prototype.catch方法將觀察者方法注冊到被觀察者Promise對象中,同時返回一個新的Promise對象,以便可以鏈式調用

  • 被觀察者管理內部pendingfulfilledrejected的狀態轉變,同時通過構造函數中傳遞的resolvereject方法以主動觸發狀態轉變和通知觀察者

到此,關于“Promise的原理和基礎用法介紹”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

盐池县| 那曲县| 平乐县| 化德县| 河北区| 临湘市| 崇左市| 金溪县| 昭觉县| 宜州市| 宁津县| 罗田县| 西乌珠穆沁旗| 五指山市| 独山县| 广平县| 神农架林区| 任丘市| 沐川县| 阳东县| 安徽省| 东阳市| 陆良县| 淄博市| 大冶市| 纳雍县| 成都市| 巫溪县| 精河县| 辽中县| 柳州市| 芜湖市| 井研县| 株洲市| 怀安县| 花莲县| 双峰县| 鄄城县| 凉山| 雷州市| 桐庐县|