摘要:一個(gè)后可以通過方法,指定和時(shí)的回調(diào)函數(shù)。構(gòu)造函數(shù)內(nèi)部要有一個(gè)值,用來保存上次執(zhí)行的結(jié)果值,如果報(bào)錯(cuò),則保存的是異常信息。因?yàn)槭且粋€(gè)構(gòu)造函數(shù),使用的寫法,首先想到的就是有顯式聲明的。
Javascript語言的執(zhí)行環(huán)境是"單線程"(single thread)。所謂"單線程",就是指一次只能完成一件任務(wù)。如果有多個(gè)任務(wù),就必須排隊(duì),前面一個(gè)任務(wù)完成,再執(zhí)行后面一個(gè)任務(wù),以此類推。
這種模式的好處是實(shí)現(xiàn)起來比較簡(jiǎn)單,執(zhí)行環(huán)境相對(duì)單純;壞處是只要有一個(gè)任務(wù)耗時(shí)很長(zhǎng),后面的任務(wù)都必須排隊(duì)等著,會(huì)拖延整個(gè)程序的執(zhí)行。常見的瀏覽器無響應(yīng)(假死),往往就是因?yàn)槟骋欢蜫avascript代碼長(zhǎng)時(shí)間運(yùn)行(比如死循環(huán)),導(dǎo)致整個(gè)頁面卡在這個(gè)地方,其他任務(wù)無法執(zhí)行。
為了解決這個(gè)問題,Javascript語言將任務(wù)的執(zhí)行模式分成兩種:同步(Synchronous)和異步(Asynchronous)。
異步模式"編程的4種方法:回調(diào)函數(shù)、事件監(jiān)聽、發(fā)布/訂閱、Promises對(duì)象。
還有g(shù)enerator、async/await.
本文嘗試說一下對(duì)Promise的理解及如何實(shí)現(xiàn)。
1.Promise原理
promise對(duì)象有三種狀態(tài),pending、fulfilled和rejected。promise對(duì)象內(nèi)部保存一個(gè)需要執(zhí)行一段時(shí)間的異步操作,當(dāng)異步操作執(zhí)行結(jié)束后可以調(diào)用resolve或reject方法,來改變promise對(duì)象的狀態(tài),狀態(tài)一旦改變就不能再變。new一個(gè)promise后可以通過then方法,指定resolved和rejected時(shí)的回調(diào)函數(shù)。下面是我們?nèi)粘J褂肞romise的代碼邏輯。
let p = new Promise((resolve,reject)=>{
$.ajax({ url: "../www/data.txt", dataType: "json", success(data){ resolve(data); }, error(err){ reject(err); } }); }); p.then(function(data){ alert("success"+data); },function(err){ alert("failed"); })
結(jié)合Promise A+規(guī)范,我們就可以分析一下我們要實(shí)現(xiàn)一個(gè)什么東西:
實(shí)現(xiàn)一個(gè)狀態(tài)機(jī),有三個(gè)狀態(tài),pending、fulfilled、rejected,狀態(tài)之間的轉(zhuǎn)化只能是pending->fulfilled、pending->rejected,狀態(tài)變化不可逆。
實(shí)現(xiàn)一個(gè)then方法,可以用來設(shè)置成功和失敗的回調(diào)
then方法要能被調(diào)用多次,所以then方法需要每次返回一個(gè)新的promise對(duì)象,這樣才能支持鏈?zhǔn)秸{(diào)用。
構(gòu)造函數(shù)內(nèi)部要有一個(gè)value值,用來保存上次執(zhí)行的結(jié)果值,如果報(bào)錯(cuò),則保存的是異常信息。
2.實(shí)現(xiàn)原理
2.1實(shí)現(xiàn)狀態(tài)機(jī)
那我們現(xiàn)在就按照上面提到的原理和規(guī)范來實(shí)現(xiàn)這個(gè)Promise構(gòu)造函數(shù)。
class myPromise {
constructor(executor) { this.status = PENDING; this.value = ""; this.Resolve = this.resolve.bind(this); this.Reject = this.reject.bind(this); this.then= this.then.bind(this); executor(this.Resolve, this.Reject); } resolve(value) { if (this.status === PENDING) { this.value = value; this.status = FULFILLED; } } reject(value) { if (this.status === PENDING) { this.value = value; this.status = REJECTED; } } then(onfulfilled, onrejected) { if (this.status === FULFILLED) { onfulfilled(this.value); } if (this.status === REJECTED) { onrejected(this.value); } } } const PENDING = "pending"; const FULFILLED = "fulfilled"; const REJECTED = "rejected"; const test = new myPromise((resolve, reject) => { resolve(100); }); test.then((data) => { console.log(data); }, (data) => { });
因?yàn)镻romise是一個(gè)構(gòu)造函數(shù),使用ES6的寫法,首先想到的就是有顯式constructor聲明的class。上面就是我們用class的實(shí)現(xiàn),可以看到這樣我們就實(shí)現(xiàn)了這個(gè)狀態(tài)機(jī),有status, value兩個(gè)屬性和resolve, reject, then三個(gè)函數(shù);同時(shí)它有pending, fulfilled和rejected三個(gè)狀態(tài),其中pending就可以切換為fulfilled或者rejected兩種。
運(yùn)行一下,輸出了100,但是現(xiàn)在其實(shí)不是一個(gè)異步處理方案,代碼先運(yùn)行了resolve(100)然后又運(yùn)行了then函數(shù),其實(shí)對(duì)于異步的情況沒有處理,不信的話就給resolve加一個(gè)setTimeout,好了,代碼又沒有輸出了。
2.2 實(shí)現(xiàn)異步設(shè)置狀態(tài)
作為一個(gè)異步處理的函數(shù),在使用的時(shí)候,我們肯定是會(huì)先設(shè)置好不同異步返回后的處理邏輯(即then的成功、失敗調(diào)用函數(shù)),然后安心等待異步執(zhí)行,最后再異步結(jié)束后,系統(tǒng)會(huì)自動(dòng)根據(jù)我們的邏輯選擇調(diào)用不同回調(diào)函數(shù)。換句話說,then函數(shù)要對(duì)status為pending的狀態(tài)進(jìn)行處理。處理的原理是設(shè)置兩個(gè)數(shù)組,在pending狀態(tài)下分別保存成功和失敗回調(diào)函數(shù),當(dāng)狀態(tài)改變后,再根據(jù)狀態(tài)去調(diào)用數(shù)組中保存的回調(diào)函數(shù)。
class myPromise {
constructor (executor) {
this.status = PENDING; this.value = ""; this.onfulfilledArr = []; this.onrejectedArr = []; this.resolve = this.resolve.bind(this); this.reject = this.reject.bind(this); this.then = this.then.bind(this); executor(this.resolve, this.reject);
}
resolve (value) {
if (this.status === PENDING) { this.value = value; this.onfulfilledArr.forEach(item => { item(this.value); }) this.status = FULFILLED; }
}
reject (value) {
if (this.status === PENDING) { this.value = value; this.onrejectedArr.forEach(item => { item(this.value); }) this.status = REJECTED; }
}
then (onfulfilled, onrejected) {
if (this.status === FULFILLED) { onfulfilled(this.value); } if (this.status === REJECTED) { onrejected(this.value); } if (this.status === PENDING) { this.onfulfilledArr.push(onfulfilled); this.onrejectedArr.push(onrejected); }
}
}
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
const test = new myPromise((resolve, reject) => {
setTimeout(() => {
resolve(100);
}, 2000)
});
test.then((data) => {
console.log(data);
},(data) => {});
可以這樣理解
new myPromise 有異步代碼
setTimeout(() => {
??? resolve(100);
}, 2000)
js是單線程的,這個(gè)時(shí)候會(huì)先把這個(gè)任務(wù)添加到定時(shí)觸發(fā)器線程中去(計(jì)時(shí)完畢后添加到事件隊(duì)列中,等待js引擎空閑后執(zhí)行),先去執(zhí)行下面的同步代碼
test.then((data) => {
??? console.log(data);
},(data) => {});
完成輸出及狀態(tài)改變。
但是Promise的一大特點(diǎn)就是可以鏈?zhǔn)秸{(diào)用,即test.then(success, fail).then(success, fail)...這就需要then返回一個(gè)新的Promise對(duì)象,而我們的程序現(xiàn)在明顯的是不支持的。那么繼續(xù)改一下。
2.3?實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用
再觀察一下鏈?zhǔn)秸{(diào)用,如果成功和失敗的函數(shù)中有返回值,這個(gè)值要作為參數(shù)傳給下個(gè)then函數(shù)的成功或失敗回調(diào)。所以我們要在返回的new Promise中調(diào)用相應(yīng)的函數(shù)。
class myPromise {
constructor (executor) {
this.status = PENDING; this.value = ""; this.onfulfilledArr = []; this.onrejectedArr = []; this.resolve = this.resolve.bind(this); this.reject = this.reject.bind(this); this.then = this.then.bind(this); executor(this.resolve, this.reject);
}
resolve (value) {
if (this.status === PENDING) { this.value = value; this.onfulfilledArr.forEach(item => { item(this.value); }) this.status = FULFILLED; }
}
reject (value) {
if (this.status === PENDING) { this.value = value; this.onrejectedArr.forEach(item => { item(this.value); }) this.status = REJECTED; }
}
then (onfulfilled, onrejected) {
if (this.status === FULFILLED) { const res = onfulfilled(this.value); return new Promise(function(resolve, reject) { resolve(res); }) } if (this.status === REJECTED) { const res = onrejected(this.value); return new Promise(function(resolve, reject) { reject(res); }) } if (this.status === PENDING) { const self = this; return new Promise(function(resolve, reject) { self.onfulfilledArr.push(() => { const res = onfulfilled(self.value) resolve(res); }); self.onrejectedArr.push(() => { const res = onrejected(self.value) reject(res); }); }) }
}
}
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
const test = new myPromise((resolve, reject) => {
setTimeout(() => {
resolve(100);
}, 2000)
});
test.then((data) => {
console.log(data);
return data + 5;
},(data) => {})
.then((data) => {
console.log(data)
},(data) => {});
再運(yùn)行一下,輸出100,105。好了,一個(gè)簡(jiǎn)單的Promise就實(shí)現(xiàn)好了。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/113705.html
摘要:一個(gè)后可以通過方法,指定和時(shí)的回調(diào)函數(shù)。構(gòu)造函數(shù)內(nèi)部要有一個(gè)值,用來保存上次執(zhí)行的結(jié)果值,如果報(bào)錯(cuò),則保存的是異常信息。因?yàn)槭且粋€(gè)構(gòu)造函數(shù),使用的寫法,首先想到的就是有顯式聲明的。 showImg(https://segmentfault.com/img/bVbffEu?w=530&h=253); Javascript語言的執(zhí)行環(huán)境是單線程(single thread)。所謂單線程,就...
摘要:意味著操作成功完成。狀態(tài)的對(duì)象可能觸發(fā)狀態(tài)并傳遞一個(gè)值給相應(yīng)的狀態(tài)處理方法,也可能觸發(fā)失敗狀態(tài)并傳遞失敗信息。測(cè)試用例測(cè)試用例方法返回一個(gè)帶有拒絕原因參數(shù)的對(duì)象。 Promise基本用法 Promise 對(duì)象是一個(gè)代理對(duì)象,被代理的值在Promise對(duì)象創(chuàng)建時(shí)可能是未知的。 它允許你為異步操作的成功和失敗分別綁定相應(yīng)的處理方法(handlers)。 這讓異步方法可以像同步方法那樣返回值...
摘要:它之后能夠被使用到很多場(chǎng)景中其他處理請(qǐng)求和響應(yīng)的方式,甚至任何需要生成自己的響應(yīng)的方式。總結(jié)到這里都講完了,其實(shí)沒什么難度,主要是自己項(xiàng)目中遇到了,但是中沒有這個(gè)方法啊。所以就想著實(shí)現(xiàn)了一個(gè),因?yàn)槠渌姆椒ㄒ捕挤庋b,不差這一個(gè)了。 Fetch 提供了對(duì)?Request?和?Response?(以及其他與網(wǎng)絡(luò)請(qǐng)求有關(guān)的)對(duì)象通用的定義。它之后能夠被使用到很多場(chǎng)景中:service wor...
摘要:等待的基本語法該關(guān)鍵字的的意思就是讓編譯器等待并返回結(jié)果。這里并不會(huì)占用資源,因?yàn)橐婵梢酝瑫r(shí)執(zhí)行其他任務(wù)其他腳本或處理事件。接下來,我們寫一個(gè)火箭發(fā)射場(chǎng)景的小例子不是真的發(fā)射火箭 本文由云+社區(qū)發(fā)表 本篇文章,小編將和大家一起學(xué)習(xí)異步編程的未來——async/await,它會(huì)打破你對(duì)上篇文章Promise的認(rèn)知,竟然異步代碼還能這么寫! 但是別太得意,你需要深入理解Promise后,...
閱讀 2560·2021-09-22 15:25
閱讀 2968·2021-09-14 18:03
閱讀 1218·2021-09-09 09:33
閱讀 1704·2021-09-07 09:59
閱讀 2933·2021-07-29 13:50
閱讀 1503·2019-08-30 15:44
閱讀 1719·2019-08-29 16:22
閱讀 1289·2019-08-29 12:49