文 / 景朝霞
來源公號 / 朝霞的光影筆記
ID / zhaoxiajingjing
❥❥❥❥點個贊,讓我知道你來過~❥❥❥❥
Promise 能夠解決的問題javascript
// 此處使用node舉例,不會沒關係,先混個臉熟。再見就不陌生了呀 let fs = require('fs'); // 異步讀取文件 fs.readFile('./name', function (err, data){ if(err){} fs.readFile(data, function (err, address){ if(err){} fs.readFile(address, function (err, product){ // 1)深陷在回調地域中不能抽身 if(err){ // 2)捕獲錯誤。OMG,我哪裏錯了?!?!告訴我,確定改~ } }); }); }); // 3) 你的名字、你的地址。都告訴我,驚喜纔會送到你面前呀~ fs.readFile('./name', function (err, data){}); fs.readFile('./address', function (err, data){});
- pending 等待態
- fulfilled 成功態
- rejected 失敗態
【等待態 -> 成功態】 or 【等待態 -> 失敗態】二選一,你來定。java
console.log('一封情書'); let p = new Promise((resolve, reject)=>{ console.log('executor請說出你的選擇:'); resolve('你中意我~(*^▽^*)'); reject('你發了好人卡(╥﹏╥)o'); }); p.then((value)=>{ console.log('成功態', value); }, (reason) => { console.log('失敗態', reason); }); console.log('紙短情長');
console.log('-----一封情書-----'); let p = new Promise((resolve, reject) => { console.log('executor 請說出你的選擇:'); resolve('你中意我~(*^▽^*)'); reject('你發了好人卡(╥﹏╥)o'); }); p.then((value) => { console.log('成功態---', value); }, (reason) => { console.log('失敗態---', reason); }).then((value) => { console.log('---愛你一萬年~(*^▽^*)'); }, (reason) => { console.log('---傷心老是不免的o(╥﹏╥)o'); }); console.log('~~~紙短情長~~~');
zhaoxiajingjing
let fs = require('fs'); let p = new Promise((resolve, reject)=>{ fs.readFile('./name.txt', 'utf8', function (err, data){ if(err){ return reject(err); } resolve(data); }); }); p.then((value)=>{ console.log('成功了', value); }, (reason)=>{ console.log('失敗了', reason); });
下面的例子輸出什麼呢?node
let fs = require('fs'); function read(filePath) { return new Promise((resolve, reject) => { fs.readFile(filePath, 'utf8',function(err, data){ if(err) { return reject(err); } resolve(data); }); }); } read('./name.txt') // then-1 .then(function (data) { console.log('data①', data); return new Promise((resolve, reject) => { reject('錯誤了'); }); }) // then-2 .then((data) => { console.log('data②', data); }, err => { console.log('err②', err); }) // then-3 .then((data) => { console.log('data③', data); }, (err) => { console.log('err③', err); });
OK,提煉一下重點: git
代碼1,傳送門~es6
const PENDING = 'pending'; const SUCCESS = 'fulfilled'; const FAIL = 'rejected'; class Promise{ constructor(execuotr){ const status = PENDING; // 我等着你給答案~ this.value; this.reason; let resolve = (value)=>{ if(status === PENDING) { this.status = SUCCESS; // 你中意我~ this.value = value; } }; let reject = (reason)=>{ if(status === PENDING) { this.status = FAIL; // 你發了好人卡 this.reason = reason; } }; // 是同步的哦~ try { executor(resolve, reject); } catch (e) { reject(e); } } then(onFulfilled, onRejected){ if(this.status === SUCCESS) { onFulfilled(this.value); // 愛你一萬年~ } if(this.status === FAIL) { onRejected(this.reason); // 傷心老是不免的 } } }
Promise 是個容器,裏面能夠放一些異步的請求,請求成功了走成功態,請求失敗了走失敗態。固然,你要反過來走也能夠噠~github
代碼2,傳送門~npm
const PENDING = 'pending'; const SUCCESS = 'fulfilled'; const FAIL = 'rejected'; class Promise { constructor(executor){ this.status = PENDING; this.value; this.reason; // 用來存儲 訂閱的內容的 this.onSuccessCallbacks = []; this.onFailCallbacks = []; let resolve = (value)=>{ if(this.status === PENDING) { this.status = SUCCESS; this.value = value; this.onSuccessCallbacks.forEach(fn => fn()); } }; let reject = (reason)=>{ if(this.status === PENDING) { this.status = FAIL; this.reason = reason; this.onFailCallbacks.forEach(fn => fn()); } }; try { executor(resolve, reject); } catch (e) { reject(e); } } then(onFulfilled, onRejected){ if(this.status === SUCCESS){ onFulfilled(this.value); } if(this.status === FAIL){ onRejected(this.reason); } // 當Promise裏面有異步請求控制狀態改變時,會先走到then方法裏面 if(this.status === PENDING) { this.onSuccessCallbacks.push(()=>{ onFulfilled(this.value); }); this.onFailCallbacks.push(()=>{ onRejected(this.reason); }); } } }
Promise 裏面有異步請求時候,會先走到 then方法裏面了。此時,須要把成功態回調和失敗態回調先存儲起來,等到異步請求回來之後變動了狀態,再觸發執行。promise
Promise 一輩子只能改變一次狀態。那麼,Promise 的鏈式調用then方法,說明每次都會返回一個新的Promise。瀏覽器
代碼3,傳送門~併發
const SUCCESS = 'fulfilled'; const FAIL = 'rejected'; const PENDING = 'pending'; class Promise { constructor(executor) { // ... executor 代碼 } then(onFulfilled, onRejected) { let promise2; promise2 = new Promise((resolve, reject)=>{ if (this.status === SUCCESS) { try { // 用 try catch 捕獲同步的報錯 // 成功態的回調的返回值 x // 【問題】 若是 x 是一個promise,那麼須要取得x執行後的結果 let x = onFulfilled(this.value); resolve(x); } catch (e) { reject(e); } } if (this.status === FAIL) { try { let x = onRejected(this.reason); resolve(x); } catch (e) { reject(e); } } if (this.status === PENDING) { this.onSuccessCallbacks.push(()=>{ try { let x = onFulfilled(this.value); resolve(x); } catch (e) { reject(e); } }); this.onFailCallbacks.push(()=>{ try { let x = onRejected(this.reason); resolve(x); } catch (e) { reject(e); } }); } }); return promise2; } }
如何判斷 x 是Promise,仍是一個普通值?【參考規範 https://promisesaplus.com "Promise A+" 2.2.7】
const SUCCESS = 'fulfilled'; const FAIL = 'rejected'; const PENDING = 'pending'; function resolvePromise(promise2, x, resolve, reject) { // 死循環了,容錯 if(promise2 === x) { return reject('TypeError: Chaining cycle detected for promise~~~~'); } // 判斷 x 類型 if(typeof x === 'function' || (typeof x === 'object' && x != null)) { // 這個纔有多是 promise try { let then = x.then; if(typeof then === 'function') { // 此時,認爲就是個promise // 若是promise是成功的,那麼結果向下傳遞,若是失敗了就傳到下一個失敗裏面去 then.call(x, y=>{ resolvePromise(promise2, y, resolve, reject); }, r => { reject(r); }); } else { resolve(x); } } catch (e) { reject(e); } } else { // x 確定不是一個promise resolve(x); } } class Promise { constructor(executor) { // ... executor 代碼 } then(onFulfilled, onRejected) { let promise2; promise2 = new Promise((resolve, reject) => { if (this.status === SUCCESS) { // 用定時器模擬此時promise2已經能獲取到了 setTimeout(() => { try { let x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }); } // 其餘狀況同理,先以一個爲例說明 }); return promise2; } }
Promise 給你的承諾,一句情話:一個 Promise 一輩子只改變一次狀態
const SUCCESS = 'fulfilled'; const FAIL = 'rejected'; const PENDING = 'pending'; function resolvePromise(promise2, x, resolve, reject) { // 死循環了,容錯 if(promise2 === x) { return reject('TypeError: Chaining cycle detected for promise~~~~'); } let called; if(typeof x === 'function' || (typeof x === 'object' && x != null)) { try { let then = x.then; if(typeof then === 'function') { then.call(x, y=>{ if(called) return; called = true; resolvePromise(promise2, y, resolve, reject); }, r => { if(called) return; called = true; reject(r); }); } else { resolve(x); } } catch (e) { if(called) return; called = true; reject(e); } } else { resolve(x); } } class Promise { constructor(executor) { // .... executor 的代碼 } then(onFulfilled, onRejected) { let promise2; promise2 = new Promise((resolve, reject) => { if (this.status === SUCCESS) { // 用定時器模擬此時promise2已經能獲取到了 setTimeout(() => { try { let x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }); } // 其餘狀況同理,先以一個爲例說明 }); return promise2; } }
let p = new Promise((resolve, reject)=>{ resolve(1000); }); p.then().then().then(data => { console.log(data); });
值能夠傳過去
const SUCCESS = 'fulfilled'; const FAIL = 'rejected'; const PENDING = 'pending'; function resolvePromise(promise2, x, resolve, reject) { // ... 判斷 x 的值 } class Promise { constructor(executor) { // ... executor 代碼 } then(onFulfilled, onRejected) { // 值穿透 onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val; onRejected = typeof onRejected === 'function' ? onRejected : err => {throw err}; // ... promise2 的判斷 } }
promises-aplus-tests
用來測試當前的庫是否符合規範npm i promises-aplus-tests -g
promises-aplus-tests 文件名
Promise 是一個構造函數,是個類。默認高版本瀏覽器,node都自帶了。不用考慮兼容性,放心大膽的使用吧!若是真不兼容,那就用es6-promise包本身是一套吧~
Promise A+
上面的內容,還須要一部分容錯。就是當executor 裏面的有一個promise的時候,執行的結果。
let Promise = require('./promise.js'); let p = new Promise((resolve, reject)=>{ resolve(new Promise((resolve, reject)=>{ reject(404); })); }); p.then(value => console.log(1, value), reason => console.log(2, reason)); // 輸出: // 2 404
在同步執行時,resolve 的value是一個Promise,那麼須要等它的結果。
const SUCCESS = 'fulfilled'; const FAIL = 'rejected'; const PENDING = 'pending'; function resolvePromise(promise2, x, resolve, reject) { // ... 校驗x } class Promise { constructor(executor) { // ... code let resolve = (value) => { if (value instanceof Promise) { return value.then(resolve, reject); } if (this.status === PENDING) { this.status = SUCCESS; this.value = value; this.onSuccessCallbacks.forEach(fn => fn()); } }; // ... code } then(onFulfilled, onRejected) { // ... then 方法 } } module.exports = Promise;
在這裏,一塊兒成長~