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