一、 Promise的一點理解(理解出現錯誤請大家糾正)
1.需要知道的前提知識(回調函數、異步)
- 回調函數(簡單來說):一個函數在另一個函數中被調用。而且可以當參數傳給其他函數。參考來自:http://https://blog.csdn.net/wanghaoyingand/article/details/118006235
`
舉例:
你點外賣,剛好你要吃的食物沒有了,於是你在店老板那里留下了你的電話,過了幾天店里有了,店員就打了你的電話,然后你接到電話后就跑到店里買了。在這個例子里,你的電話號碼就叫回調函數,你把電話留給店員就叫登記回調函數,店里后來有貨了叫做觸發了回調關聯的事件,店員給你打電話叫做調用回調函數,你到店里去取貨叫做響應回調事件。
`
因為setTimeout()本身不是異步的,只是類似異步,異步:指某段程序執行時不會阻塞其它程序執行,其表現形式為程序的執行順序不依賴程序本身的書寫順序,相反則為同步。
其優勢在於不阻塞程序的執行,從而提升整體執行效率。
現實生活中的一個例子
打電話是同步 發消息是異步
關於為什么setTimeout類似異步卻不是異步。詳情請參考該文章,講得非常通透徹底愛了愛了(里面還講到了evenloop-事件循環,還有一些異步操作的原理,你必須看不然接下來我說的任務隊列那些你不懂):http://https://www.jianshu.com/p/4c377e876dac
切入正題
<body>
<script>
const fn1 = (callback) => {
console.log('1');
callback();
}
//相當於這里有這樣的代碼 function(callback){console.log('加油');} let定義變量是使用完就回收。
/*形參
定義:全稱"形式參數",用於定義方法的時候使用的參數,目的用來接收調用該方法時傳遞的參數。
說明:只有在被調用時才會分配內存單元,在調用結束,即刻釋放所分配的內存單元。因此,只在方法內才有效。
*/
fn1(function() {
console.log('加油');//先打印出來是1,然后傳參數里面再打印出加油
});
/*
const fn1 = (callback) => {
console.log('1');
}
const fn2 = (callback) => {
console.log('2');
}
fn1();//先執行fn1,
fn2();//再執行fn2 同步,都在執行棧那里,
-------------------------------------------嘿嘿手動分割線
const fn3 = (callback) => {
console.log('3');
setTimeout(() => {
console.log('2秒后執行完成');
}, 2000)
}
const fn4 = (callback) => {
console.log('2');
setTimeout(() => {
console.log('1秒后執行完成');//記住文件越大讀取的速度越慢。
}, 1000)
}
fn3();
fn4();//結果為2 3 1秒后執行完成 2秒后執行完成
//(側面說明了當執行棧中所有的任務執行完了,去看任務隊列中有setTimeout()這個需要執行的事件 ,
//結束它們的等待,進入執行棧時它還是先要看setTimeout()第二個參數設置的秒數的 ,
//然后它挑最短的時間開始執行。
//當然要挑最短的執行了,它結束完,好運行下一個,這樣等待的進程就少一些嘛。
*/
</script>
</body>
(我大哥的圖借用一下)
此時:
當運行(注意這里請去掉fn1/2/3/4中的callback())
fn1();
fn2();
fn3();
fn4();//結果為1 3 2 4,因為fn1 和fn3中沒有單線程 Windows.setTimeout()這個方法,所以它們被放到了執行棧,他們就按部就班執行,按照代碼順序執行。
想讓代碼按順序執行就得這樣調用:
fn1 (function () { //先執行fn1(這里傳了參數為function 的函數)相當於 let callback = function () {},
//按代碼順序執行,里面嵌套調用了fn2,
//所以它執行完fn1之后就必須去執行fn2,里面有setTimeout(),
//它也必須要等上幾秒,然后執行完,fn2,fn2里面又嵌套fn3以此下去到fn4函數,就是函數不停的調用嘛。
fn2(function () {
fn3(function () {
fn4(function () {
console.log('結束');
})//這種后面超級多的括號代碼不美觀,
})//況且當你啥時候不小心刪了幾個括號,
})//還得慢慢看差幾個補上來,
})//當函數調用賊多的時候,這個括號不得把人嚇死,
//這個有個很適合它的名字叫回調地獄--Callback Hell
promise出現了挽救一下這個回調地獄
-
ES2015正式發布(也就是ES6,ES6是它的乳名),其中Promise被列為正式規范。作為ES6中最重要的特性之一,我們有必要掌握並理解透徹。
-
所謂Promise,簡單說就是一個容器,里面保存着某個未來才會結束的事件(通常是一個異步操作)的結果。從語法上說,Promise 是一個對象,從它可以獲取異步操作的消息。Promise 提供統一的 API,各種異步操作都可以用同樣的方法進行處理。----你就記住它是個容器,然后里面保存着某個未來才會執行結束的事件結果(異步操作結果,就是未來才會結束的,它呆在任務隊列呢結果要等到執行棧執行他了才出來。)
-
它有兩個參數,一個是resolve-解決也就是成功和reject-拒絕也就是失敗。它們是兩個函數,由 JavaScript 引擎提供,(其中resolve為從pending(進行中狀態)變為fulfilled(已成功)(在異步操作成功時調用,並將異步操作的結果,作為參數傳遞出去;),reject為從pending變為rejected(已失敗)。看下面有的,
-
primise是個容器/對象,里面放着一個某個事件的結果該結果未來才知道--就是結果信息,promise(一個函數( resolve,reject))--promise對象接收一個函數作為參數,其中函數里面包含着兩個參數,resolve,和reject,這兩個參數又是兩個函數,但是這兩個函數由 JavaScript 引擎提供,不用自己寫。
內容: Promise構造函數接受一個函數作為參數,該函數的兩個參數分別是resolve和reject。它們是兩個函數,由 JavaScript 引擎提供,不用自己部署。
內容: resolve函數的作用是,將Promise對象的狀態從“未完成”變為“成功”(即從 pending 變為 resolved),在異步操作成功時調用,並將異步操作的結果,作為參數傳遞出去;reject函數的作用是,將Promise對象的狀態從“未完成”變為“失敗”(即從 pending 變為 rejected),在異步操作失敗時調用,並將異步操作報出的錯誤,作為參數傳遞出去。
參考博主文章:http://https://www.cnblogs.com/lvdabao/p/es6-promise-1.html
參考文章(更多具體請看這個連接,超級詳細~阮一峰):http://https://es6.ruanyifeng.com/#docs/promise
promise是什么:console.dir(Promise)(控制台打印出來就知道了)
這么一看就明白了,Promise是一個構造函數,它有all、reject、resolve這幾個眼熟的方法,原型上有then、catch等也很眼熟的方法。那么Promise new出來的對象肯定就有then、catch方法。
內容:1.Promise對象有以下兩個特點。
(1)對象的狀態不受外界影響。Promise對象代表一個異步操作,有三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗)。只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。這也是Promise這個名字的由來,它的英語意思就是“承諾”,表示其他手段無法改變。
(2)一旦狀態改變,就不會再變,任何時候都可以得到這個結果。Promise對象的狀態改變,只有兩種可能:從pending變為fulfilled和從pending變為rejected。只要這兩種情況發生,狀態就凝固了,不會再變了,會一直保持這個結果,這時就稱為 resolved(已定型)。如果改變已經發生了,你再對Promise對象添加回調函數,也會立即得到這個結果。這與事件(Event)完全不同,事件的特點是,如果你錯過了它,再去監聽,是得不到結果的。
圖來記憶一下
注意,為了行文方便,本章后面的resolved統一只指fulfilled狀態,不包含rejected狀態。
有了Promise對象,就可以將異步操作以同步操作的流程表達出來,避免了層層嵌套的回調函數。此外,Promise對象提供統一的接口,使得控制異步操作更加容易。
Promise也有一些缺點。首先,無法取消Promise,一旦新建它就會立即執行,無法中途取消。其次,如果不設置回調函數,Promise內部拋出的錯誤,不會反應到外部。第三,當處於pending狀態時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)。
如果某些事件不斷地反復發生,一般來說,使用 Stream 模式是比部署Promise更好的選擇。(stream不懂)
基本用法
ES6 規定,Promise對象是一個構造函數,用來生成Promise實例。
下面代碼創造了一個Promise實例。
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 異步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
Promise構造函數接受一個函數作為參數,該函數的兩個參數分別是resolve和reject。它們是兩個函數,由 JavaScript 引擎提供,不用自己部署。
resolve函數的作用是,將Promise對象的狀態從“未完成”變為“成功”(即從 pending 變為 resolved),在異步操作成功時調用,並將異步操作的結果,作為參數傳遞出去;reject函數的作用是,將Promise對象的狀態從“未完成”變為“失敗”(即從 pending 變為 rejected),在異步操作失敗時調用,並將異步操作報出的錯誤,作為參數傳遞出去。
Promise實例生成以后,可以用then方法分別指定resolved狀態和rejected狀態的回調函數。
promise.then(function(value) {
// success
}, function(error) {
// failure
});
then方法可以接受兩個回調函數作為參數。第一個回調函數是Promise對象的狀態變為resolved時調用,第二個回調函數是Promise對象的狀態變為rejected時調用。這兩個函數都是可選的,不一定要提供。它們都接受Promise對象傳出的值作為參數。
---------------23:30回宿舍了
------------15:28更
var p = new Promise(function(resolve, reject) {
//做一些異步操作
setTimeout(function() {
console.log('執行完成');
resolve('隨便什么數據');
}, 2000);
});//結果2秒后執行完成,setTimeout()這個類似異步操作,還沒有調用,傳參resolve('隨便什么數據)就執行了出來
then方法的使用:
懶得打字,看
文章:
看這個鏈接有catch等方法的調用