Promise 解析
Promise
由于js的語(yǔ)言特性(用戶(hù)交互)和工作環(huán)境(瀏覽器腳本),決定了它是單線(xiàn)程工作,所以?xún)啥文_本不能同時(shí)運(yùn)行,但為了實(shí)現(xiàn)功能,所以人們使用了事件和回調(diào)來(lái)初步解決這個(gè)問(wèn)題,例如(addEventListener),但這也帶來(lái)了嚴(yán)重的回調(diào)問(wèn)題,非常容易陷入回調(diào)地獄的困惱,
由于這個(gè)問(wèn)題。js發(fā)展至今,社區(qū)提出了promise(承若)標(biāo)準(zhǔn),被es6寫(xiě)入了語(yǔ)言標(biāo)準(zhǔn)中,統(tǒng)一了它的用法,并在原生中提供了標(biāo)準(zhǔn)的Promise對(duì)象
讓我們先來(lái)實(shí)例化一個(gè)標(biāo)準(zhǔn)的promise對(duì)象:
//實(shí)例化一個(gè)promise對(duì)象,這個(gè)對(duì)象有兩個(gè)參數(shù)(resolve-決定,reject-拒絕)let promise = new Promise((resolve,reject)=>{//延時(shí)3s,把promise的狀態(tài)改為resolve-決定setTimeout(function(){resolve('666')},3000)})//每個(gè)實(shí)例都有then()方法,用來(lái)獲取其值或原因。//then(onFulfilled, onRejected)//成功的回調(diào),失敗的回調(diào)promise.then(data=>{console.log(data)},err=>{console.error(err)}).then()同時(shí)promise還可以多次調(diào)用then()方法,也可以在resolve中繼續(xù)拋出一個(gè)新的promise 例:
promise.then(function(data){console.log('data2=',data);},function(err){console.log('err2=',err);});或者:
let promise2 = promise.then(function(data){return new Promise(function(resolve,reject){setTimeout(function(){resolve(data + '777' );},1000);});});當(dāng)然還有常見(jiàn)的all(),catch(),resolve(),reject()等等一些方法,而這些方法都是按照Promise/A+規(guī)范規(guī)定的 (詳情)
我們現(xiàn)在就按照這個(gè)規(guī)范來(lái)實(shí)現(xiàn)一個(gè)屬于我們自己的promise
首先我們先定義出這個(gè)類(lèi):
// executor是一個(gè)執(zhí)行函數(shù),在實(shí)例化的時(shí)候被傳入。這個(gè)函數(shù)會(huì)執(zhí)行兩個(gè)被傳入的狀態(tài)函數(shù) var Promise = function (executor) { let self = this;//沒(méi)個(gè)promise都會(huì)有個(gè)初始化值,這個(gè)值在規(guī)范中叫做pendingself.status = 'pending';self.value = undefined; // 默認(rèn)成功的值self.reason = undefined; // 默認(rèn)失敗的原因self.onResolvedCallbacks = []; // 存放then成功的回調(diào)self.onRejectedCallbacks = []; // 存放then失敗的回調(diào)// 成功狀態(tài)要執(zhí)行的函數(shù)function resolve(value) {//更改他的狀態(tài)值,為成功,且不能更改if (self.status === 'pending') {self.status = 'resolved';self.value = value;//實(shí)例多次調(diào)用then(),循環(huán)釋放數(shù)組self.onResolvedCallbacks.forEach(function (fn) {fn();});}}// 失敗狀態(tài)要執(zhí)行的函數(shù)function reject(reason) {//更改他的狀態(tài)值,為失敗,且不能更改if (self.status === 'pending') {self.status = 'rejected';self.reason = reason;//實(shí)例多次調(diào)用then(),循環(huán)釋放數(shù)組self.onRejectedCallbacks.forEach(function (fn) {fn();})}}如果直接傳入錯(cuò)誤的代碼,那么直接進(jìn)入rejecttry {executor(resolve, reject)} catch (e) {// 捕獲的時(shí)候發(fā)生異常,就直接失敗了reject(e);} }下面我們來(lái)實(shí)現(xiàn)then()方法,個(gè)方法每個(gè)實(shí)例都有,他是一個(gè)方法,所以我們把它掛載到Promise原型上:
Promise.prototype.then = function (onFulfilled, onRjected) {//成功和失敗默認(rèn)一個(gè)函數(shù),防止報(bào)錯(cuò),onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (value) {return value;}onRjected = typeof onRjected === 'function' ? onRjected : function (err) {throw err;}let self = this;//定義一個(gè)返回的promiselet promise2;//當(dāng)狀態(tài)是成功的時(shí)候,可能會(huì)在函數(shù)中再次返回一個(gè)promiseif (self.status === 'resolved') {promise2 = new Promise(function (resolve, reject) {// 當(dāng)成功或者失敗執(zhí)行時(shí)有異常那么返回的promise應(yīng)該處于失敗狀態(tài)//這個(gè)x 是第一個(gè)promise執(zhí)行后的結(jié)果// x可能是一個(gè)promise 也有可能是一個(gè)普通的值setTimeout(function () {try {let x = onFulfilled(self.value);// x可能是別人promise,寫(xiě)一個(gè)方法統(tǒng)一處理resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}})})}//當(dāng)狀態(tài)是失敗的時(shí)候if (self.status === 'rejected') {promise2 = new Promise(function (resolve, reject) {setTimeout(function () {try {let x = onRjected(self.reason);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}})})}// 當(dāng)調(diào)用then時(shí)可能沒(méi)成功 也沒(méi)失敗if (self.status === 'pending') {promise2 = new Promise(function (resolve, reject) {// 此時(shí)沒(méi)有resolve 也沒(méi)有rejectself.onResolvedCallbacks.push(function () {setTimeout(function () {try {let x = onFulfilled(self.value);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e)}})});self.onRejectedCallbacks.push(function () {setTimeout(function () {try {let x = onRjected(self.reason);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}})});})}return promise2; }集中處理x
function resolvePromise(promise2, x, resolve, reject) {// 有可能這里返回的x是別人的promise// 先跑錯(cuò)if (promise2 === x) { //這里應(yīng)該報(bào)一個(gè)類(lèi)型錯(cuò)誤,有問(wèn)題return reject(new TypeError('循環(huán)引用了'))}// 看x是不是一個(gè)promise,promise應(yīng)該是一個(gè)對(duì)象let called; // 表示是否調(diào)用過(guò)成功或者失敗if (x !== null && (typeof x === 'object' || typeof x === 'function')) {//根據(jù)語(yǔ)法規(guī)定的幾種情況來(lái)判斷// 可能是promise {},看這個(gè)對(duì)象中是否有then方法,如果有then我就認(rèn)為他是promise了try {let then = x.then;if (typeof then === 'function') {// 成功then.call(x, function (y) {if (called) returncalled = true// y可能還是一個(gè)promise,在去解析直到返回的是一個(gè)普通值//遞歸調(diào)用這個(gè)函數(shù),resolvePromise(promise2, y, resolve, reject)}, function (err) { //失敗if (called) returncalled = truereject(err);})} else {resolve(x)}} catch (e) {if (called) returncalled = true;reject(e);}} else { // 說(shuō)明是一個(gè)普通值1resolve(x); // 表示成功了} }在實(shí)現(xiàn)了這些之后,其他的方法,更多的就是一個(gè)語(yǔ)法糖,我們來(lái)實(shí)現(xiàn)他們
catch:
all
//會(huì)傳入一個(gè)數(shù)組,這個(gè)數(shù)組是promise集合 Promise.all = function (promises) {return new Promise(function (resolve, reject) {//arr是最終返回值的結(jié)果let arr = []; // 表示成功了多少次let i = 0; function processData(index, y) {arr[index] = y;if (++i === promises.length) {resolve(arr);}}for (let i = 0; i < promises.length; i++) {promises[i].then(function (y) {processData(i, y)}, reject)}}) }race
//race就是賽跑的意思,誰(shuí)獲取結(jié)果比較快,就返回誰(shuí) // 只要有一個(gè)promise成功了 就算成功。如果第一個(gè)失敗了就失敗了 Promise.race = function (promises) {return new Promise(function (resolve, reject) {for (var i = 0; i < promises.length; i++) {promises[i].then(resolve,reject)}}) } // 生成一個(gè)成功的promise Promise.resolve = function(value){return new Promise(function(resolve,reject){resolve(value);}) } // 生成一個(gè)失敗的promise Promise.reject = function(reason){return new Promise(function(resolve,reject){reject(reason);}) }defer 延期處理
會(huì)包容promise 可用于封裝在傳遞方法之外調(diào)用原有的promise回調(diào)
轉(zhuǎn)載于:https://www.cnblogs.com/oicb/p/10568151.html
總結(jié)
以上是生活随笔為你收集整理的Promise 解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 爬虫(3)
- 下一篇: Hive常用函数大全一览