面試答題萬金油方法論順序(高級前端面試套路)- 該技術要解決什么問題-why
- 該技術是怎么解決它的-how
- 該技術有什么優點(對比其他技術) - pros
- 該技術有什么缺點-cons
- 如何解決這些缺點-more
promise 要解決什么問題要解決回調地獄
那么問題來了,回調地獄真的是個問題么?
有沒有可能是這個程序員水平不行
回調地獄
回調不地獄
現狀水平差的人就是多Promise 有什么優點- 有兩個主要的優點
- 把【函數里的函數】編程【then 下面的 then】(鏈式)
減少縮進減少縮進1/2減少縮進2/2
- 錯誤處理單獨放到一個函數里
- 如果不處理,就一直等到往后拋
消滅 if(err)消滅if err
用戶怎么用 Promise搖骰子回調
搖骰子promise
Promise 的完整 API 是什么?- Promise 是一個類
- JS 里類是特殊的函數
- 類屬性: length(可忽略)
- 類方法: all/allSettled/race/reject/resolve
- 對象屬性: then(重要)/finally/catch
- 對象內部屬性: state=pending/fulfilled/reject
API 的規則是什么- Promise/A+規格文檔
- JS 的 Promise 的公開標準
- 有中文翻譯,但是不保證其準確性
- 開始寫代碼
- 按照文檔寫測試用例
- 先讓用例失敗
- 然后讓用例通過
- 直到把文檔的所有情況都考慮清楚
使用 chai- 更牛 X 的測試方案
- 步驟
- yarn global add ts-node mocha 全局安裝
- 創建目錄 promise-demo(名字隨意)
- yarn init -y 或者 npm init -y
- yarn add chai mocha --dev
- yarn add @types/chai @types/mocha --dev
- 創建 test/index.ts
- mocha -r ts-node/register test/index.ts 運行測試
// 測試起手代碼import * as chai from "chai";const assert = chai.assert;describe("", () => { it("", () => {});});
- describe,it 的意思見下圖
- 確認 mocha 可以成功使用
describe("Promise", () => { it("可以測試相等", () => { assert(1 === 1); });});
- 然后輸入mocha -r ts-node/register test/index.ts 運行測試
- mocha 的作用就是提供 describe,it 和漂亮的輸出的一個庫
- chai 就是提供 assert 的使用
- 在 package.json 中配置,就不需要這么長命令了
"scripts": { "test": "mocha -r ts-node/register test/**/*.ts" },
- yarn test 發現報錯,因為 yarn 在本地找依賴,而 typescript 和 ts-node 是全局的,所以進行本地安裝,基本腳手架就搭建完成了
新建 src/promise.ts,開始寫代碼,并完成第一個測試用例describe("Promise", () => { it("是一個類", () => { // assert(typeof Promise === 'function'); // 檢測是不是函數 // assert(typeof Promise.prototype === "object"); // 檢測是不是對象 assert.isFunction(Promise); // chai.assert 可以對以上兩句的簡寫 assert.isObject(Promise.prototype); });});
測試用例 2,new Promise() 必須接收一個函數,不是一個函數就報錯// 測試用例describe("Promise", () => { it("是一個類", () => { // assert(typeof Promise === 'function'); // 檢測是不是函數 // assert(typeof Promise.prototype === "object"); // 檢測是不是對象 assert.isFunction(Promise); // chai.assert 可以對以上兩句的簡寫 assert.isObject(Promise.prototype); }); it("new Promise() 必須接收一個函數,不是一個函數就報錯", () => { assert.throw(() => { // assert.throw預測某個東西會報錯,接收一個函數 // @ts-ignore new Promise(1); // 函數體里就是要報錯的東西,這里的意思是預測new Promise會報錯 }); assert.throw(() => { // assert.throw預測某個東西會報錯,接收一個函數 // @ts-ignore new Promise(false); // 函數體里就是要報錯的東西,這里的意思是預測new Promise會報錯 }); });});// 源代碼class Promise2 { constructor(fn) { if (typeof fn !== "function") { throw new Error("我只接收函數"); } }}
實現測試用例 3,new Promise(fn)會生成一個對象,對象有 then 方法it("new Promise(fn)會生成一個對象,對象有then方法", () => { const promise = new Promise(() => {}); assert.isFunction(promise.then);});class Promise2 { constructor(fn) { if (typeof fn !== "function") { throw new Error("我只接收函數"); } } then() {}}export default Promise2;
實現測試用例 4,new Promise(fn) 中的 fn 立即執行it("new Promise(fn) 中的 fn 立即執行", () => { let called = false; const promise = new Promise(() => { called = true; }); // @ts-ignore assert(called === true);});class Promise2 { constructor(fn) { if (typeof fn !== "function") { throw new Error("我只接收函數"); } fn(); } then() {}}
實現測試用例 5,new Promise(fn)中的 fn 執行的時候接收 resolve 和 reject 兩個函數it("new Promise(fn)中的fn執行的時候接收 resolve 和 reject 兩個函數", () => { let called = false; const promise = new Promise((resolve, reject) => { called = true; assert.isFunction(resolve); assert.isFunction(reject); }); // @ts-ignore assert(called);});class Promise2 { constructor(fn) { if (typeof fn !== "function") { throw new Error("我只接收函數"); } fn( () => {}, () => {} ); } then() {}}
測試用例 6,測試 promise.then(success)中的 success 會在 resolve 被調用的時候,執行。這里會涉及執行時機的問題,resolve 立即執行所引發的問題,resolve 執行的時候 then 還沒有綁定到 promise 上去it("promise.then(success)中的success 會在 resolve被調用的時候,執行", (done) => { // done 表示等待的執行 let called = false; const promise = new Promise((resolve, reject) => { // 該函數沒有執行 assert(called === false); // 之前不是true console.log("resolve"); resolve(); assert(called === true); // resolve 之后是true,證明resolve()調用了succeed console.log("代碼執行了"); // 該函數執行了 }); // @ts-ignore promise.then(() => { called = true; });});class Promise2 { succeed = null; // 對象的屬性, 類的屬性要加static fail = null; resolve = () => { this.succeed(); }; reject = () => { this.fail(); }; constructor(fn) { if (typeof fn !== "function") { throw new Error("我只接收函數"); } fn(this.resolve.bind(this), this.reject.bind(this)); } then(succeed, fail) { this.succeed = succeed; // 存到對象的屬性上 this.fail = fail; }}
通過增加 setTimeout 讓 resolve 等一會,并且不能立即去測試 assert 為 true,但是這樣做需要在測試用例上加上 done,因為有等待執行的代碼,done 的意思告訴 mocha 測試完了,可以檢查測試結果了。最終實現 promise.then(success)中的 success 會在 resolve 被調用的時候執行。it("new Promise(fn)中的fn執行的時候接收 resolve 和 reject 兩個函數", () => { let called = false; const promise = new Promise((resolve, reject) => { called = true; assert.isFunction(resolve); assert.isFunction(reject); }); // @ts-ignore assert(called);});class Promise2 { succeed = null; // 對象的屬性, 類的屬性要加static fail = null; constructor(fn) { if (typeof fn !== "function") { throw new Error("我只接收函數"); } fn( () => { setTimeout(() => { this.succeed(); }, 0); }, () => { setTimeout(() => { this.fail(); }, 0); } ); } then(succeed, fail) { this.succeed = succeed; // 存到對象的屬性上 this.fail = fail; }}
class Promise2 { succeed = null; // 對象的屬性, 類的屬性要加static fail = null; resolve = () => { setTimeout(() => { this.succeed(); }, 0); }; reject = () => { setTimeout(() => { this.fail(); }, 0); }; constructor(fn) { if (typeof fn !== "function") { throw new Error("我只接收函數"); } fn(this.resolve, this.reject); } then(succeed, fail) { this.succeed = succeed; // 存到對象的屬性上 this.fail = fail; }}
使用 sinon 測試函數,sinon-chai 是讓 sinon 和 chai 合作- 安裝
- yarn add sinon sinon-chai --dev
- yarn add @types/sinon @types/sinon-chai --dev
- 引入并使用 sinon-chai
import * as sinon from "sinon";import * as sinonChai from "sinon-chai";chai.use(sinonChai);
it("new Promise(fn) 中的 fn 立即執行", () => { let fn = sinon.fake(); const promise = new Promise(fn); assert(fn.called);});
- 改寫測試代碼,把之前各種變量改寫成 sinon.fake
it("new Promise(fn) 中的 fn 立即執行", () => { let fn = sinon.fake(); new Promise(fn); assert(fn.called);});it("new Promise(fn)中的fn執行的時候接收 resolve 和 reject 兩個函數", (done) => { new Promise((resolve, reject) => { assert.isFunction(resolve); assert.isFunction(reject); done(); });});it("promise.then(success)中的success 會在 resolve被調用的時候,執行", (done) => { // done 表示等待的執行 const success = sinon.fake(); const promise = new Promise((resolve, reject) => { // 該函數沒有執行 // assert(called === false); // 之前不是ture assert.isFalse(success.called); resolve(); setTimeout(() => { assert.isTrue(success.called); done(); }); // 該函數執行了 }); // @ts-ignore promise.then(success);});
測試用例 7,測試 fail,和測試用例 6 對應it("promise.then(null, fail)中的fail 會在 reject被調用的時候,執行", (done) => { // done 表示等待的執行 const fail = sinon.fake(); const promise = new Promise((resolve, reject) => { // 該函數沒有執行 // assert(called === false); // 之前不是ture assert.isFalse(fail.called); reject(); setTimeout(() => { assert.isTrue(fail.called); done(); }); // 該函數執行了 }); // @ts-ignore promise.then(null, fail);});
接下來照著 PromiseA+規范做
總結
以上是生活随笔為你收集整理的方法 手写promise_高级前端养成37js专精06之手写promise(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。