Promise 對象promise
是 JavaScript 的異步操做解決方案,爲異步操做提供統一接口。app
目前 JavaScript 原生支持 Promise 對象異步
它起到代理做用(proxy),充當異步操做與回調函數之間的中介,使得異步操做具有同步操做的接口。函數
Promise 可讓異步操做寫起來,就像在寫同步操做的流程,而沒必要一層層地嵌套回調函數。spa
function f1(resolve, reject) { // 異步代碼... } var p1 = new Promise(f1);
// 構造函數接受一個回調函數 做爲參數,裏面是異步操做的代碼。而後,返回的就是一個 Promise 實例Promisef1()f1()p1
var p1 = new Promise(f1); p1.then(f2);
f1() 的異步操做執行完成,就會執行 f2()
prototype
// 傳統寫法 step1(function (value1) { step2(value1, function(value2) { step3(value2, function(value3) { step4(value3, function(value4) { // ... }); }); }); }); // Promise 的寫法 (new Promise(step1)).then(step2).then(step3).then(step4);
var promise = new Promise(function (resolve, reject) { // ... if (/* 異步操做成功 */){ resolve(value); } else { /* 異步操做失敗 */ reject(new Error()); } });
// 該函數的兩個參數分別是 和 。它們是兩個函數,由 JavaScript 引擎提供,不用本身實現resolvereject
resolve() 函數設計
做用是,將Promise實例的狀態從「未完成」變爲「成功」(即從pending變爲fulfilled)代理
在異步操做成功時調用,並將異步操做的結果,做爲參數傳遞出去。code
reject函數對象
做用是,將Promise實例的狀態從「未完成」變爲「失敗」(即從pending變爲rejected)
在異步操做失敗時調用,並將異步操做報出的錯誤,做爲參數傳遞出去。
function timeout(ms) { return new Promise((resolve, reject) => { setTimeout(resolve, ms, 'done'); }); } timeout(100)
上面代碼中,timeout(100) 返回一個 Promise 實例。100毫秒之後,該實例的狀態會變爲 fulfilled
var p1 = new Promise(function (resolve, reject) { resolve('成功'); }); p1.then(console.log, console.error); // "成功" var p2 = new Promise(function (resolve, reject) { reject(new Error('失敗')); }); p2.then(console.log, console.error); // Error: 失敗
p1 和 p2 都是Promise 實例,它們的 then() 方法綁定兩個回調函數:成功時的回調函數 console.log,失敗時的回調函數 console.error(能夠省略)。
p1 的狀態變爲成功,p2 的狀態變爲失敗
對應的回調函數會收到異步操做傳回的值,而後在控制檯輸出
var preloadImage = function (path) { return new Promise(function (resolve, reject) { var image = new Image(); image.onload = resolve; image.onerror = reject; image.src = path; }); };
調用
preloadImage('https://example.com/my.jpg') .then(function (e) { document.body.append(e.target) }) .then(function () { console.log('加載成功') })
new Promise(function (resolve, reject) { resolve(1); }).then(console.log); console.log(2); // 2 // 1
// 上面代碼會先輸出 2,再輸出 1 。
// 由於 console.log(2)是同步任務,而 then 的回調函數屬於異步任務,必定晚於同步任務執行
setTimeout(function() { console.log(1); }, 0); new Promise(function (resolve, reject) { resolve(2); }).then(console.log); console.log(3); // 3 // 2 // 1
輸出結果是321。這說明 then 的回調函數的執行時間,早於setTimeout(fn, 0)。
由於 then 是本輪事件循環執行,setTimeout(fn, 0)在下一輪事件循環開始時執行