Javascript基礎之-Promise

轉載自: http://www.lht.ren/article/3/

Promise是什么呢?根據ecma-262的定義:

Promise是一個被用于延時計算的最終結果的占位符

(A Promise is an object that is used as a placeholder for the eventual results of a deferred (and possibly asynchronous) computation.)

這個怎么理解呢

比如說,我要去麥當勞買點吃的,下單以后人家會先給你一個訂單號,等人家外賣做好了,會提示你,并用那個訂單小票來換取你真正的食物,在這時候,那個訂單小票就是你這頓飯的占位符。

回到Promise,它有三種狀態,分別為完成,拒絕和待決議,

而待決議的狀態代表它還沒有被完成或者是拒絕,也就是說,如果它一直都是處于待決議的狀態,意味著代碼永遠都不會繼續往下執行

所以下面這段代碼永遠都執行不到finish

new Promise((resolve, reject) => {console.log('waiting');document.writeln('waiting');
}).then((msg) => {console.log('finish');
});

也就是意味著,必須顯示的執行resolve()或者是reject,程序才會繼續往下執行。

那怎么解決這個問題呢,其實很簡單,決議一下就好了嘛,哈哈~~

或者給Promise設置一個超時時間,看下面的代碼:

function timeoutPromise(delay) {return new Promise( function(resolve,reject){setTimeout( function(){reject( "Timeout!" );}, delay );} );
}
Promise.race([new Promise(() => {console.log('waiting...');}),timeoutPromise(3000)
]).catch((msg) => {console.log(msg);
})

這段代碼呢,會先等待5秒,然后會打印出一個錯誤"Timeout",在這里,Promise.race()實際上就是競態的,誰先決議,其余的就會被拋棄。所以咱們三秒鐘后決議一個拒絕,剩下那個promise自動被拋棄了

說到錯誤處理了,思考下面的代碼:

new Promise((resolve, reject) => {foo.bar();
}).then((msg) => {console.log(msg);
}, null).then((msg) => {console.log(msg);
}, (err) => {console.log(err);
});

這段代碼,很明顯foo不是對象,所以會報ReferenceError,所以呢,會自動決議為reject,然后他緊接著的那個then沒有拒絕處理回調,然后接著往下傳遞錯誤,直到有reject回調為止,假如一直都沒有reject回調呢,他就會在全局拋出一個未捕獲的異常。

那么如果在Promise決議多次呢,實際上只有第一次決議生效,也就是說,只能有一種決議生效,又成功又失敗,或者成功多次,失敗多次聽著就不靠譜是吧,思考下面的代碼

new Promise((resolve, reject) => {resolve();reject();console.log('exec finish');
}).then((msg) => {console.log('resolve');
}, (err) => {console.log('reject');
});

運行結果是輸出exec finish 和resolve,因為第一次決議為resolve, 所以reject決議就被拋棄了

大家想一下,決議后對應的then里面的回調函數是同步還是異步的呢,思考下面這個問題:

console.log(0);
let p = new Promise((resolve, reject) => {console.log(1);resolve();console.log(2);
})
console.log(3);
p.then((msg) => {console.log(4);
});
console.log(5);

他的結果是 1 2 3 5 4

答案很顯然啦,是異步的!實際上當決議以后,就會把它放到一個異步隊列里調用

那為什么要這么設計呢,會給我們帶來什么好處呢,思考下面這個問題

function getResult() {console.log(a);
}
function opt() {if (isAsync) {setTimeout(() => {getResult();}, 0);} else {getResult();}
}
var a = 0;
var isAsync = false;
opt();
a++;
isAsync = true;
opt();
a++;

他的結果輸出的是0 2,那為什么不是0, 1,實際上就是因為由于同步和異步的的不確定性導致的,也叫zalgo,所以呢,要想消除他們的不確定性,必須就讓他里面的代碼要么都是同步,要么都是異步,這也是then為什么是異步的原因了

關于then,還有一個問題,就是then的返回值是什么,來繼續看問題

var p = Promise.resolve( 21 );
var p2 = p.then( function(v){return v * 2;
});
console.log(p2);

通過他的結果,你很容易就能看出來,then的返回值是一個Promise,那么,這個then回調是不是可以這么理解呢?

function callback() {return Promise.resolve(42);
}

如果是的話,那么咱們就研究一下Promise.resolve()的特性,然后then()同理就可以是吧

那么我們現在就研究一下Promise.resolve()的一些特性:

如果向Promise.resolve()傳遞一個非Promise,非thenable的立即值,就會立即得到這個值填充的Promise,這個有三個關鍵字,非Promise,非thenable和立即值

如果向Promise.resolve()傳遞一個真正的promise,那么就會返回這個Promise,又一個例子,很好理解

var p = Promise.resolve(42);
var p2 = Promise.resolve(p);
console.log(p === p2);   // true

如果向Promise.resolve()傳遞一個非Promise的thenable值,那么就會展開這個值,并且在展開過程會持續到提取出一個具體的Promise最終值

大家應該會有一點疑惑,thenable是什么,這段話是什么意思

var obj = {then(resolve, reject) {resolve(42);}
};
Promise.resolve(obj).then((msg) => {console.log(msg);  //42
});

好了,Promise.resolve()特性講完了,then返回值同理

同理完了以后呢,就會出現一些比較有意思的用法

首先就是鏈式調用,比如說

var p = Promise.resolve( 21 );
var p2 = p.then( function(v){console.log( v ); // 21// 用值42填充p2return v * 2;
} );
// 連接p2
p2.then( function(v){console.log( v ); // 42
} );

很簡單吧,就不贅述了。

還有一個比較有意思,就是Promise實現同步執行,也就是前一個then如果是異步的話,它必須操作完成后,才會執行后面的then,常見的寫法是這樣的

new Promise((resolve, reject) => {setTimeout(() => {console.log('exec in promise it');resolve();}, 1000);
}).then(() => {return new Promise((resolve, reject) => {setTimeout(() => {console.log('exec in then it');resolve();}, 1000);});
});

這個先過一秒輸出第一句話,再過一秒輸出第二句話

這個的原理實際上剛剛Promise.resolve()的第二條,如果返回的是Promise,那么會直接返回這個Promise,在這里,直接返回return的這個Promise后,就會等待這個Promise決議,在一秒后決議完,就執行后面的then

最后一個有關then的知識點了:

一個Promise決議后,這個Promise上所有的通過then()注冊的回調都會在下一個異步時間節點上依次被立即調用,這些回掉中任意一個都無法影響或者延誤對其他回調的調用

var p = new Promise((resolve, reject) => {resolve();
});
p.then( function(){p.then( function(){console.log( "C" );} );console.log( "A" );
} );
p.then( function(){console.log( "B" );
} );
// a b c

這個的重點實際上是這些決議回調都被加入到了一個隊列中,輸出的順序正好實際上就代表了他們加入隊列后的先后順序

參考書籍《你不知道的Javascript中卷》

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/281031.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/281031.shtml
英文地址,請注明出處:http://en.pswp.cn/news/281031.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

linux進階命令2

linux進階命令2 壓縮1.壓縮的概念1)壓縮的目的: 在網絡傳遞文件時,可以先將文件壓縮,然后傳遞壓縮后的文件,從而減少網絡帶寬。 接受者接受文件后,解壓即可。2)壓縮的類型 有損壓縮、無損壓縮。…

PHP經常使用正則表達式匯總

1. 平時做站點常常要用正則表達式,以下是一些解說和樣例,僅供大家參考和改動使用: 2. "^\d$"  //非負整數(正整數 0) 3. "^[0-9]*[1-9][0-9]*$"  //正整數 4. "^((-\d)|…

psa name_Windows 10安全性PSA:啟用自動商店更新

psa nameMicrosoft sometimes distributes important security updates through the Microsoft Store. That’s the lesson we’re learning in July 2020, when Microsoft sent an important update for Windows 10’s HEVC codecs not via Windows Update but via the Store.…

C# ListView 簡單命令例子

編寫工具常用到ListView控件,能簡單列出選項,常用到流程校驗顯示。這里介紹簡答顯示,添加與刪除功能。 1.添加表頭,與顯示。 this.listView1.Columns.Add("隊列", 40, HorizontalAlignment.Left);this.listView1.Column…

C#并行編程-Task

什么是異步同步和異步主要用于修飾方法。當一個方法被調用時,調用者需要等待該方法執行完畢并返回才能繼續執行,我們稱這個方法是同步方法;當一個方法被調用時立即返回,并獲取一個線程執行該方法內部的業務,調用者不用…

手機照片丟失或誤刪如何恢復

手機照片丟失或誤刪如何恢復?我們每個人從剛出生就開始拍照片,一周歲照片、二周歲照片、三周歲照片等,因為照片可以記錄我們從小到大的模樣和變化。無意照片對我們每個人來說都很重要,如果手機突然壞以前的照片都找不到了怎么辦呢…

C++學習筆記(二)——交換函數(swap)

這次我們要透過一個簡單的函數swap深入理解函數傳參的本質以及在C中如何選擇傳參方式。 先來看第一段程序: void swap(int x, int y) {int temp y;y x;x temp; } 通過main函數的調用,我們發現x,y并未實現交換: int main() {int x 1;int y…

大數據背后是個萬億市場

2014年的GDP中消費占比已經超過了50%,標志著中國經濟正在向市場經濟轉型,消費占GDP50%-70%是中等發達國家向市場經濟過渡的一個表現,未來中國經濟增長最大的引擎應該來源于消費,特別是個人消費。中國正在經歷經濟結構調…

ipad iphone開發_如何將iPhone或iPad置于恢復模式

ipad iphone開發If your iDevice starts acting strangely and you’ve run through the gamut of normal troubleshooting fixes, Recovery Mode may be your answer. This lets you easily reset the device and re-install iOS using iTunes. 如果您的iDevice開始運行異常&a…

從三層架構說起,談談對歷史項目的小改造

web development項目背景說明最近接手一個 “老” 項目的需求修改,項目整體基于 .net core 3.1 平臺,以傳統的三層架構為基礎構建。了解需求后,逐步對原有項目框架進行大概的了解,主要是熟悉一些框架的開發規范,基本工…

C# message簡單實現窗口間信息接收與發送

剛接觸windows 不同程序 窗口消息傳遞,不理解IntPtr SendMessage(int hWnd, int msg, IntPtr wParam, IntPtr lParam)這函數怎么用?消息內容怎么傳遞過去,還遇到需要message結構體?IntPtr怎么用呢? 但實際只是用來傳個…

在Kubernetes集群上部署和管理JFrog Artifactory

JFrog Artifactory是一個artifacts倉庫管理平臺,它支持所有的主流打包格式、構建工具和持續集成(CI)服務器。它將所有二進制內容保存在一個單一位置并提供一個接口,這使得用戶在整個應用程序開發和交付過程中,能更易于…

已知思科ASA設備漏洞仍在其新版本中存在

近日,名為“Shadow Brokers(影子經紀人)”的黑客組織聲稱成功入侵了跟NSA相關的Equation Group(方程式組織)的計算機系統,并成功竊取到了大量的機密信息以及黑客工具。隨后,“Shadow Brokers”黑客組織將60%的泄漏文件在網上進行了公布&#…

Yii Listview

轉載于:https://www.cnblogs.com/xiong63/p/8546376.html

Git 操作筆記/pip換源

pip換源 阿里云的源,在cmd命令行中輸入上述命令即可 pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ 還原commit 不可逆 1.git log2.選擇某次提交的commit ID3.使用git reset --hard commit ID 遠程查看與斷開 git remote -vgit remote rem…

.NET 7 的 AOT 到底能不能杠反編譯?

一:背景 1.講故事在B站,公眾號上發了一篇 AOT 的文章后,沒想到反響還是挺大的,都稱贊這個東西能抗反編譯,可以讓破解難度極大提高,可能有很多朋友對逆向不了解,以為用 ILSpy,Reflector,DnSpy 這…

google hdr+_更好的隱私權控制使Google+死了

google hdrEarlier this year, Google started a project to review third-party developer access to Google accounts through the use of APIs. It found a security breach surrounding Google, and is now shutting the service down, at least for consumers. 今年年初&a…

新0-Day漏洞或將給Linux桌面發行版帶來浩劫

Linux 的各個發行版都一直強調安全及其相關元素,比如防火墻、滲透測試、沙盒、無痕上網和隱私等等,但事實上可能并沒有想象中的那么安全。安全研究員 Chris Evans 公開了其發現的針對 Linux 桌面發行版的 0day 漏洞,利用特制的音頻文件入侵 L…

php中把美國時間轉為北京時間的自定義

我的服務器北京時間,php調用的時間: date.timezone "America/Chicago" 這是美國這邊的一個時間,有的時候跟北京相差13個小時,有的時候跟北京時間相差14個小時,所以很不好處理,現在php函數就能處…

C# DataTable筆記

文章轉載自http://www.cnblogs.com/Sandon/p/5175829.html 感謝博主Sandon。 為了方便以后編程查看,特把文章復制過來。 創建表 //創建一個空表 DataTable dt new DataTable(); //創建一個名為"Table_New"的空表 DataTable dt new DataTable("Tabl…