Promise
是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大。javascript
參考java
理解:node
Es6將promise歸入本身規範的時候,也遵循了一個相應的標準 — ``Promise A+規範。git
將其概括爲4321規範
github
4:4大術語 3:3種狀態 2:2種事件 1:1個對象npm
解決(fulfill)
:指一個 promise 成功時進行的一系列操做,如狀態的改變、回調的執行。雖然規範中用 fulfill 來表示解決,但在後世的 promise 實現多以 resolve 來指代之。編程
拒絕(reject)
:指一個 promise 失敗時進行的一系列操做。數組
終值(eventual value)
:所謂終值,指的是 promise 被解決時傳遞給解決回調的值,因爲 promise 有一次性的特徵,所以當這個值被傳遞時,標誌着 promise 等待態的結束,故稱之終值,有時也直接簡稱爲值(value)。promise
據因(reason)
:也就是拒絕緣由,指在 promise 被拒絕時傳遞給拒絕回調的值。dom
針對每種狀態的規範
等待態(Pending) 處於等待態時,promise 需知足如下條件:
執行態(Fulfilled)
處於執行態時,promise 需知足如下條件:
拒絕態(Rejected)
處於拒絕態時,promise 需知足如下條件:
針對3種狀態,只有以下兩種轉換方向:
在狀態轉換的時候,就會觸發事件。
若是是
pending –> fulfiied
,就會觸發onFulFilled
事件 若是是pendeing –> rejected
,就會觸發onRejected
事件
就是指promise對象
let p = new Promise(function (resolve,reject) {
reject("no");
})
console.log('p :', p);
複製代碼
回調函數中的兩個參數,其做用就是用於轉換狀態:
resolve,將狀態從pending –> fullFilled reject,將狀態從pending –> rejected
在狀態轉換的時候,就會觸發事件
。
若是是pending –> fulfiied,就會觸發onFulFilled事件
若是是pendeing –> rejected,就會觸發onRejected事件
針對事件的註冊,Promise對象提供了then
方法,以下:
const fs = require("fs");
let p = new Promise(function (resolve,reject) {
fs.readFile("03-js基礎/a.txt","utf8",(err,date)=>{
if(err){
reject(err);
}else{
resolve(date);
}
});
});
p.then(result=>{
console.log('result :', result);
}).catch(err=>{
console.log('err :', err);
});
複製代碼
let p = new Promise((resolve,reject)=>{
setTimeout(()=>{
let num = Math.random();
if(num>0.5){
resolve("success");
}else{
reject("fail");
}
},1000);
});
p.then(result=>{
console.log('result :', result);
},err=>{
console.log('err :', err);
})
複製代碼
const fs = require("fs");
function readFile(file){
return new Promise((resolve,reject)=>{
fs.readFile("file","utf8",(err,date)=>{
if(err){
reject(err);
}else{
resolve(date);
}
});
});
}
readFile("a.txt").then(result=>{
console.log('result :', result);
},err=>{
console.log('err :', err);
})
複製代碼
all:全部 race:競賽
all和race都是Promise構造器對象的靜態方法。直接使用Promise調用,以下:
promise
對象。當有多個異步操做的時候,常常會有以下兩種需求:(有點相似於運算符中的 邏輯與 和 邏輯或)
確保全部的異步操做完成以後,才進行某個操做,只要有一個失敗,就不進行
只要有一個異步操做文章,就裏面執行某個操做。
all使用以下
若有錯誤,以下
reac的用法
針對第三方的promise庫,有兩個知名的庫:
以bluebird爲例,在服務端演示其用法
。
第一步,安裝
第二步,使用
能夠進入Github中更有層次的學習原理,本人在github中 逐步的封裝了基礎版promise
,升級版promise
,完整版的promise
,
Github地址:github.com/quyuandong/…
示例
源碼
// 定義當前promise的狀態
const PENDING = 'PENDING'
const RESOLVED = 'RESOLVED'
const REJECTED = 'REJECTED'
//=================================================================
// promise對象
class Promise {
constructor(exector) {
// 初始化status爲等待狀態
this.status = PENDING;
// 成功的值
this.value = undefined;
// 失敗的緣由
this.reason = undefined;
// 存儲成功的回調函數
this.onResolvedCallbacks = [];
// 存儲失敗的回調函數
this.onRejectedCallbacks = [];
// 成功的處理函數
let resolve = (value) => {
if (this.status == PENDING) {
this.value = value; //存儲成功的值
this.status = RESOLVED; //將當前的狀態修改成成功狀態
this.onResolvedCallbacks.forEach(fn => fn())
}
}
// 失敗的處理函數
let reject = (reason) => {
if (this.status == PENDING) {
this.reason = reason; //存儲失敗的緣由
this.status = REJECTED; //將當前的狀態修改成失敗狀態
this.onRejectedCallbacks.forEach(fn => fn())
}
}
// 當pormise拋出異常時
try {
exector(resolve, reject) //當即執行函數
} catch (e) {
reject(e)
}
}
/** * 參數: * @param {*} onFulfilled 失敗狀態 * @param {*} onRejected 成功狀態 * * 說明: * promise的鏈式,能夠一直.then下去,須要then返回一個promise * onFulfilled與onRejected的返回值,多是一個promise 也多是一個普通值 * 若是是promise,就採用它的狀態 * 若是是普通值,這個值就做爲下一個then成功的結果 * */
then(onFulfilled, onRejected) {
// 防止then中沒有函數 p.then().then().then()...
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
/** * 建立一個promise,並返回一個promise,使得能夠then能夠進行鏈式調用 * settimeout做用: 使得該方法中,能夠獲取到promise2 * try做用: 處理onfulfilled可能拋出一個異常 */
let promise2 = new Promise((resolve, reject) => {
// 成功狀態的處理方法-------同步操做(執行器中沒有異步代碼)
if (this.status == RESOLVED) {
setTimeout(() => {
try {
let x = onFulfilled(this.value);// x多是promise 也多是普通值
// 假如x是promise(有本身的狀態),須要讓pormise2擁有x一樣的狀態
resolvePromise(promise2, x, resolve, reject); // 處理promise2和x的關係
} catch (e) {
reject(e)
}
}, 0);
}
// 失敗狀態的處理方法-------同步操做(執行器中沒有異步代碼)
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0)
}
// 等待狀態,將成功與失敗的的操做進行保存-------同步操做(執行器中有異步代碼)
if (this.status === PENDING) {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0)
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0)
})
}
})
return promise2;
}
}
//=================================================================
// 處理promise2和x的關係 ,x是onFulfilled或onRejected的返回值
function resolvePromise(promise2, x, resolve, reject) {
// 若是 x === promise2,則是會形成循環引用,本身等待本身完成,則報「循環引用」錯誤
if (promise2 === x) {
return reject(new TypeError('my Chaining cycle detected for promise'))
}
// 防止屢次調用
let called;
// x是一個對象(不包含null)或是一個函數時
if (x !== null && (typeof x === "object" || typeof x === "function")) {
try {
// 有可能x上會被手動地加上一個then屬性
let then = x.then;
if (typeof then === 'function') { // x是一個promise時
// 至關於 x.then(y=>{},r=>{})
then.call(x, y => {
if (called) return;
called = true;
// 遞歸,解決返回值裏面扔是promise的問題
resolvePromise(promise2, y, resolve, reject)
}, r => {
if (called) return;
called = true;
// 採用promise失敗結果向下傳遞
reject(r)
})
} else { // 此時x是一個對象,即返回的是一個對象
resolve(x)
}
} catch (e) { //當x拋出一個異常時
if (called) return;
reject(e)
}
} else { //x 是一個普通的值
resolve(x)
}
}
//=================================================================
// resolve靜態方法
Promise.resolve = function (val) {
return new Promise((resolve, reject) => {
resolve(val)
});
}
//=================================================================
// reject靜態方法
Promise.resolve = function (val) {
return new Promise((resolve, reject) => {
reject(val)
});
}
//=================================================================
// race靜態方法
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(resolve, reject)
}
});
}
//=================================================================
// all方法(獲取全部的promise,都執行then,把結果放到數組,一塊兒返回)
Promise.all = function (promises) {
let arr = [];
let y = 0;
function processData(index, data) {
arr[i] = data;
y++;
if (y == promises.length) {
return arr;
};
};
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(data => {
processData(i, data)
}, reject)
}
})
}
//================================================================
//
/** * 驗證promise的正確性 * 1,先在後面加上下述代碼 * 2,npm 有一個promises-aplus-tests插件 npm i promises-aplus-tests -g 能夠全局安裝 * 3,命令行 promises-aplus-tests [js文件名] 便可驗證 */
// 目前是經過他測試 他會測試一個對象
// 語法糖
Promise.defer = Promise.deferred = function () {
let dfd = {}
dfd.promise = new Promise((resolve,reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
//=================================================================
// 導出一個promise
module.exports = Promise;
/** * 注意:當在promise中出現異步的時候,必須先將then中成功和失敗的回調函數 * 先進行保存,當promise中的狀態發生改變的時候,纔再進行執行 */
複製代碼