摘要:上網(wǎng)查了一下好像是標準第二步開寫構造函數(shù)什么都不想,先寫一個構造函數(shù),就叫把。對構造函數(shù)再次做修改。并且可以一個值。給下一個繼續(xù)調用。應該是一個新的。最后的版本總結后來去看了看別人實現(xiàn)的方法。
我能不能在不看別人怎么實現(xiàn)promise的情況下,自己實現(xiàn)一個promise?
都8102年為什么還要寫promise實現(xiàn)?第一步: 先稍微分析一下原生的Promise Promise 使用方式? 年前和年后面試了幾家公司, 雖然都掛了… 但是都談到了一個面試題,就是promise. 雖然使用promise很簡單,而且我回答的都沒問題.
? 但是面試官都問到了一個題目. "如果讓你實現(xiàn)一個promise.all方法, 怎么實現(xiàn) ? " 臨時想了一個每個promise.then里用計數(shù)器+1, 在判斷計數(shù)器是否等于參數(shù)Array[promise]的 length 來判斷promise是否都完成的實現(xiàn)思路, 也不知道算不算是對的.
? 然后就回來想自己能不能在不看任何人的代碼的情況下, 實現(xiàn)一個promise。
var a = new Promise(function( resolve, reject ){})
new一個Promise實例,傳入一個函數(shù),里面有兩個參數(shù)。
resolve:成功時調用,并將成功后的數(shù)據(jù)傳進then方法里。
reject:失敗的時候調用,并將失敗的數(shù)據(jù)傳進catch方法里。
Promise的原型方法很簡單,只有我們常見的then catch還有finally方法。不過finally方法應該不屬于ES6標準的,所以先忽略。(上網(wǎng)查了一下好像是ES2018標準)
第二步:開寫 2.1:構造函數(shù)什么都不想,先寫一個構造函數(shù),就叫 Future 把。
因為Promise有兩種狀態(tài),所以我給他加一個 status。
function Future(func){ this.status = null; }2.2:增加resolve和reject
? 接著需要執(zhí)行傳入的函數(shù),并傳給他一個resolve和reject方法。經(jīng)常用Promise的同學應該知道 Promise.resolve 和 Promise.reject。
? 但是沒在原型里找到這兩個方法,所以我就直接在Future上加這兩個方法。
// 只要執(zhí)行了resolve或者reject肯定要改變status, 所以對實例的status做更新 Future.resolve = function (data) { this.status = "resolve" this.data = data } Future.reject = function (data) { this.status = "reject" this.data = data }
這兩個這里的data要在then里用,所以還是得緩存起來,然后將這兩個方法傳進func里,這里對構造函數(shù)再做改動
function Future(func){ this.status = null; this.data = null; func(Future.resolve, Future.resolve) }
? 但是這里有一個問題,resolve執(zhí)行的時候,this并不是指向當前的promise實例的,這時我就想到了bind方法。所以必須在初始化的時候把resolve和reject的作用域給綁定好。對構造函數(shù)再次做修改。( 還要加上setTimeout , 加入even loop,這個是后加的)
function Future(func){ if(typeOf func !== "function") throw new Errow("Future 的參數(shù)必須為函數(shù)"); var _this = this; this.status = null; this.data = null; setTimeout(function () { func(Future.resolve.bind(_this), Future.resolve.bind(_this)) }) }2.3:實現(xiàn)then和catch
回顧一下then的使用方式:傳入一個函數(shù),在promise執(zhí)行resolve后,才會調用,并且函數(shù)的參數(shù)就是調用resolve的時候傳入的值。并且可以return一個值。給下一個then繼續(xù)調用。
? 所以then函數(shù)應該很簡單,直接緩存這個函數(shù),resolve的時候再拿出來調用即可。而關于鏈式調用,一開始想到的就是return this
? 所以一開始我先是這么寫的
function Future(func){ //再加一個函數(shù)隊列數(shù)組和一個錯誤狀態(tài)的執(zhí)行函數(shù) this.queue = []; this.failCb = null; ...其余代碼省略 }
Future.prototype.then = function (callback) { if(typeof callback !== "function") throw new Errow("then必須傳入函數(shù)"); if(this.status === "resolve"){ this.data = callback(this.data); }else if(this.status === null){ this.queue.push(callback); } return this; } Future.prototype.catch = function (callback) { if(typeof callback !== "function") throw new Errow("catch必須傳入函數(shù)"); if (this.status === "reject") { this.data = callback(this.data); }else if(this.status === null){ this.failCb = callback; } return this; }2.4:實現(xiàn)resolve和reject
? 其他的都好了,接著就是在resolve里去執(zhí)行隊列里的函數(shù)。reject里執(zhí)行錯誤函數(shù)。
Future.resolve = function (data) { var context = this; context.status = "resolve"; context.data = data; //先把第一個函數(shù)拿出來 var func = context.queue.shift(); if(func){ try{ var d = func(data); //函數(shù)可以返回一個值,也可以返回一個promise if(d instanceof Future){ d = d.data; } //遞歸的方式再執(zhí)行下一個,這里再用call去改變this的指向 Future.resolve.call(context, d); }catch(err){ //捕捉報錯,執(zhí)行catch Future.reject.call(context, err); } } } Future.reject = function (data) { this.status = "reject"; this.data = data; if(this.failCb){ this.failCb(data) }else{ throw new Error("promise catch") } }
以上。
? 到這里呢,就是那時臨時想臨時做的第一版。
后記? 當然,后面又大改了一些東西。最主要的是then函數(shù)不應該返回this。應該是一個新的promise。如果按照現(xiàn)在這么做,經(jīng)過多個then之后,初始的data就變成了最后一個值了。我們希望的是要保留最初初始化的時候的那個值。
//比如 var a = new Future(function(resolve, reject){ setTimeout(function(){ console.log("success") resolve(true) }, 1000) }) a.then(function(res){ console.log(res); return "啦拉拉" }) setTimeout(function(){ a.then(function(res){ //這里就會輸出 "啦拉拉"。其實期望的是輸出 true console.log("settimeout: ", res) }) },2000)
? 后來為了解決這個,突然陷入了牛角尖。。。花了一天才做完。水平有限,只能做到這樣了,最后附上完整代碼吧。
最后的版本
總結? 后來去看了看別人實現(xiàn)的方法。大體思路應該也是差不多的。其實就做個記錄總結,方便以后面試用。嘻嘻(^__^)。
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/94033.html
摘要:它的作用是為實例添加狀態(tài)改變時的回調函數(shù)。里面有兩個回調函數(shù),前者返回的回調函數(shù),后者是可選值。可以看成是的別名專門用來指定錯誤發(fā)生時的回調函數(shù)。 最近一直私下在看Android項目,前端這一塊沒怎么仔細研究。昨天在寫重構公司前端項目的時候,我發(fā)現(xiàn)一旦有異步的任務,腦海里面條件反射一般的出現(xiàn)promise的字樣。重構的多了 心就就在納悶:既然promise這么好用,我能不能自己手寫一個pro...
摘要:在年正式發(fā)布了,簡稱,又稱為。再次簡寫循環(huán)迭代數(shù)組每個元素都執(zhí)行一次回調函數(shù)。方法用于調用數(shù)組的每個元素,并將元素傳遞給回調函數(shù)。注意對于空數(shù)組是不會執(zhí)行回調函數(shù)的。 轉載請注明出處 原文連接 http://blog.huanghanlian.com/article/5c7aa6c7bf3acc0864870f9d es6 是什么 首先弄明白ECMA和js的關系。ECMA是標準,Jav...
摘要:在年正式發(fā)布了,簡稱,又稱為。再次簡寫循環(huán)迭代數(shù)組每個元素都執(zhí)行一次回調函數(shù)。方法用于調用數(shù)組的每個元素,并將元素傳遞給回調函數(shù)。注意對于空數(shù)組是不會執(zhí)行回調函數(shù)的。 轉載請注明出處 原文連接 http://blog.huanghanlian.com/article/5c7aa6c7bf3acc0864870f9d es6 是什么 首先弄明白ECMA和js的關系。ECMA是標準,Jav...
閱讀 1382·2021-10-08 10:04
閱讀 2696·2021-09-22 15:23
閱讀 2727·2021-09-04 16:40
閱讀 1179·2019-08-29 17:29
閱讀 1496·2019-08-29 17:28
閱讀 2994·2019-08-29 14:02
閱讀 2223·2019-08-29 13:18
閱讀 848·2019-08-23 18:35