首頁 >web前端 >js教程 >ECMAScript6中Promise是什麼?有什麼用? (附範例)

ECMAScript6中Promise是什麼?有什麼用? (附範例)

不言
不言轉載
2018-10-24 11:44:472074瀏覽

這篇文章帶給大家的內容是關於ECMAScript6中Promise是什麼?有什麼用? (附範例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

剛學習完,有點粗略印象。整理記錄一下以便後續學習補充,加深理解。

Promise是什麼

Promise是建構函數,可以透過new來產生Promise物件。

Promise有什麼用

目前我的感受是:更方便來操作非同步流程,更明確直覺的控制事件的流程以及可以鍊式呼叫

Promise特點

摘自ES6入門

Promise物件有以下兩個特點。
(1)物件的狀態不受外界影響。 Promise物件代表一個非同步操作,有三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗)。只有非同步操作的結果,可以決定目前是哪一種狀態,任何其他操作都無法改變這個狀態。這也是Promise這個名字的由來,它的英語意思是“承諾”,表示其他手段無法改變。
(2)一旦狀態改變,就不會再變,任何時候都可以得到這個結果。 Promise物件的狀態改變,只有兩種可能:從pending變成fulfilled和從pending變成rejected。只要這兩種情況發生,狀態就凝固了,不會再變了,會一直維持這個結果,這時就稱為 resolved(已定型)。如果改變已經發生了,你再對Promise物件加入回呼函數,也會立即得到這個結果。這與事件(Event)完全不同,事件的特徵是,如果你錯過了它,再去監聽,是得不到結果的。

透過幾個簡單例子來理解它

透過new建構一個簡單的Promise物件

let p = new Promise((resolve, reject) => {});

傳入的兩個參數是用來控制Promise物件的狀態,我們印一下p看它的狀態:
Promise {__proto__: Promise[[PromiseStatus]]: "pending"[[PromiseValue]]: undefined這就是初始狀態pending
resolve, reject可以控制Promise的狀態

//resolve()
let p = new Promise((resolve, reject) => resolve("123")); //Promise {<resolved>: "123"}
//reject()
let p = new Promise((resolve, reject) => reject("123")); //reject()后是返回一个失败状态的Promise,不需要用catch来捕获不写catch会报错
p.catch(data => console.log(data));    
console.log(p);    //Promise {<rejected>: "123"}   123

提到了catch那就有還有一個then
 說一直白點:then(f1, f2)可以填入兩個函數參數,一個參數就是將resolve中參數代入f1來執行,第二個參數將reject中參數代入f2來執行;第二個參數可以用catch來代替,並且它更加強大,catch能捕獲then()中的報錯

let p = new Promise((resolve, reject) => {
    
    let n = Math.ceil(Math.random() * 10);
    n > 5 ? resolve(n) : reject(n);
});
p.then(
    data => console.log(data),
    data => console.log(data),
)

用catch代替,並捕獲then的錯誤

let p = new Promise((resolve, reject) => {
    
    resolve("yes")
});
p.then(
    data => {console.log(data),console.log(a)}

).catch(data => console.log(data));
//yes
//ReferenceError: a is not defined

因為then處理後返回的還是Promise對象,這樣方便鍊式調用,then中都沒有return,怎麼會有Promise對象的呢?

then或catch即使未明確指定回傳值, 它們也總是自動包裝一個新的fulfilled狀態的promise物件。

我們印一下會發現:Promise {<resolved>: undefined}
  那麼我們可以顯示的return一個Promise物件看看,

let p = new Promise((resolve, reject) => resolve("yes"));
p.then(data => Promise.resolve("第二个Promise")).then(data => console.log(data));   //第二个Promise

可以看到p.then(data => Promise.resolve("第二個Promise"))回傳Promise物件是Promise {<resolved>: "第二個Promise"}且將value值作為參數傳入到第二個then中來執行

Promise.resolve(value | promise | thenable)建立Promise物件
  第一參數空或原始值,建立後的Promise對象狀態直接為resolved狀態

Promise.resolve('f')
// 等价于
new Promise(resolve => resolve('f'))

第二值得注意的是具有then方法的物件

let thenable = {
    then :(resolve, reject) => resolve("thenable")
}

let p = Promise.resolve(thenable);
console.log(p);

Promise物件狀態由->   第三參數為實例化的Promise對象,

let p1 = new Promise((resolve, reject) => false);
let p = Promise.resolve(p1);
console.log(p);</p>
<p>p狀態與p1狀態一致的</p>
<p>Promise.reject(value)建立Promise物件<br>   與resolve不同的是:直接將value原樣作為參數傳入</p>
<pre class="brush:php;toolbar:false">const thenable = {
  then(resolve, reject) {
    reject('出错了');
  }
};

Promise.reject(thenable)
.catch(e => {
  console.log(e === thenable)
})

catch方法的參數不是reject拋出的「出錯了」這個字串,而是thenable物件。

Promise.all

將多個Promise 實例,包裝成一個新的Promise 實例;const p = Promise.all([p1, p2, p3]);

(1)只有p1、p2、p3的狀態都變成fulfilled,p的狀態才會變成fulfilled,此時p1、p2、p3的回傳值組成一個數組,傳遞給p的回呼函數。

(2)只要p1、p2、p3之中有一個被rejected,p的狀態就變成rejected,此時第一個被reject的實例的回傳值,會傳遞給p的回呼函數。

會等all中的物件全部執行完後將陣列傳入回呼函數then中

let p = new Promise((resolve, reject) => setTimeout(() => resolve('p'),1000));
let p1 = new Promise((resolve, reject) => setTimeout(() => resolve('p2'),2000));
let p2 = new Promise((resolve, reject) => setTimeout(() => resolve('p3'),3000));
Promise.all([p, p1, p2]).then(data => console.log(data)).catch(data => console.log(data));    // ["p", "p2", "p2"]
let p = new Promise((resolve, reject) => resolve('p'));
let p1 = new Promise((resolve, reject) => reject('p2'));
let p2 = new Promise((resolve, reject) => resolve('p2'));
Promise.all([p, p1, p2]).then(data => console.log(data)).catch(data => console.log(data));   //p2

Promise.race
與all不同的是:只要p1、p2、p3之中有一個實例率先改變狀態,p的狀態就跟著改變。那個率先改變的 Promise 實例的回傳值,就傳遞給p的回呼函數。

let p = new Promise((resolve, reject) => setTimeout(() => resolve('p'),1000));
let p1 = new Promise((resolve, reject) => setTimeout(() => resolve('p2'),2000));
let p2 = new Promise((resolve, reject) => setTimeout(() => resolve('p3'),3000));
Promise.race([p, p1, p2]).then(data => console.log(data)).catch(data => console.log(data));   //p

Promise物件的回呼函數與setTimeout的順序問題

An event loop has one or more task queues. A task queue is an ordered list of tasks, which are algorithms that are responsible for such work as: events, parsing, callbacks, using a resource, reacting to DOM manipulation…Each event loop has a microtask queue. A microtask is a task that is originally to be queued on the microtask queue rather than a task queue.
  浏览器(或宿主环境) 遵循队列先进先出原则, 依次遍历macrotask queue中的每一个task, 不过每执行一个macrotask, 并不是立即就执行下一个, 而是执行一遍microtask queue中的任务, 然后切换GUI线程重新渲染或垃圾回收等.
  Event Loop (事件循环)拥有如下两种队列
  macrotask queue, 指的是宏任务队列, 包括rendering, script(页面脚本), 鼠标, 键盘, 网络请求等事件触发, setTimeout, setInterval, setImmediate(node)等等.
  microtask queue, 指的是微任务队列, 用于在浏览器重新渲染前执行, 包含Promise, process.nextTick(node), Object.observe, MutationObserver回调等.
  process.nextTick > promise.then > setTimeout ? setImmediate

setTimeout(function () {
  console.log('three');
}, 0);

Promise.resolve().then(function () {
  console.log('two');
});

console.log('one');

// one
// two
// three

上面代码中,setTimeout(fn, 0)在下一轮“事件循环”开始时执行,Promise.resolve()在本轮“事件循环”结束时执行,console.log('one')则是立即执行,因此最先输出。

setTimeout(function() {
  console.log(4)
}, 0);
new Promise(function(resolve) {
  console.log(1);
  for (var i = 0; i < 10000; i++) {
    i == 9999 && resolve()
  }
  console.log(2);
}).then(function() {
  console.log(5)
});
console.log(3);  //1 2 3 5 4

以上是ECMAScript6中Promise是什麼?有什麼用? (附範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除