隨便說說Promise

来源:https://www.cnblogs.com/cnyball/archive/2018/07/08/9280067.html
-Advertisement-
Play Games

為啥要說 promise ? 因為這是前端必須要掌握的一個知識,吹逼必備 同學們,開始上課了! 首先說說 Promise 是什麼? Promise 是JavaScript的第一個非同步標準模型,一個包含傳遞信息與狀態的對象,emmm...它的英語意思是承諾. so 它擁有的特點也有承諾的意思(兄弟們, ...


為啥要說 promise ?

因為這是前端必須要掌握的一個知識,吹逼必備

image

同學們,開始上課了!

Markdown

首先說說 Promise 是什麼?

Promise 是JavaScript的第一個非同步標準模型,一個包含傳遞信息與狀態的對象,emmm...它的英語意思是承諾.
so 它擁有的特點也有承諾的意思(兄弟們,拿好筆記本,劃重點):

  1. 對象的狀態不受外界影響,Promise 表示一個非同步的操作,它有三個狀態 Pending (進行時)、Reslove (已完成)、Rejected (失敗),只有非同步操作的結果,可以決定當前是哪一種狀態
  2. 一旦狀態改變就不會再接受改變,任何時候都可以得到這個結果。 Promise 對象的狀態改變,只有兩種可能,從 Pending 變為 Resolved 或者 Rejected。 只要這兩種情況發生,狀態就不會再改變了,就算狀態改變了,你再對 Promise 對象添加回調,也會立即得到結果,這和事件 event 不同,事件的特點是一點你錯過了它,再去監聽也不會得到結果的

那 Promise 為什麼會出現呢?

Promise 之前的非同步

先上一張圖讓大家感受下

Markdown

Promise之前的時候,我們用三個手段解決非同步問題

  1. 回調函數
  2. 觀察者模式(又稱發佈訂閱模式)
  3. 事件機制

回調函數是最簡單的非同步方式,它比較容易理解和部署,也是我們最常使用的,但是缺點也很明顯,不利於代碼的閱讀和維護,流程混亂。

觀察者模式和事件機制不多說,就是適用於多次同類型的非同步,不適用一次性的非同步

而 Promise 可以將非同步操作以同步操作的流程表達出來,

  1. 避免了層層回調函數。
  2. 如果使用回調函數, 你並不能知道對方是否執行你的回調函數,或太晚太早執行
  3. 錯誤也是非同步,會隱式傳遞給reject

老哥,說了這麼多,怎麼用啊?

先來個最簡單的Prmise

const p = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve('你好,兄弟') //設置成resolve狀態 即是成功
    },1e3)
})
p.then(res=>{
    console.log(res) // 1s後輸出 ==> 你好,兄弟
})

是不是看起來 so easy ?

下麵我們來實現一下最簡單的 Promise。 Promise只是一個普通的構造函數,用es3的語法也可以實現
所以在ie6都可以用,不過我們就使用es6的class來實現了

class myPromise {
  constructor(fn) {
    this.state = 'PENDING';
    this.message = '';
    this.fns = [];
    fn(this.resolve.bind(this), this.reject.bind(this));
  }
  resolve(res) {
    this.state = 'FULFILLED';
    this.message = res;
    this._onChange();
  }
  reject(err) {
    this.state = 'REJECTED';
    this.message = err;
    this._onChange();
  }
  then(onResolved, onRejected) {
    let self = this;
    return new myPromise((resolve, reject) => {
      self.fns.push([onResolved, onRejected, resolve, reject]);
      self._onChange();
    });
  }
  _onChange() {
    this.state !== 'PENDING' &&
      this.fns.forEach(v => {
        this._change(v);
      });
  }
  _change(arr) {
    let onResolved = arr[0],
      onRejected = arr[1],
      resolve = arr[2],
      reject = arr[3];
    switch (this.state) {
      case 'FULFILLED':
        if (typeof onResolved === 'function') {
          resolve(onResolved.call(null, this.message));
        } else {
          resolve(this.message);
        }
        break;
      case 'REJECTED':
        if (typeof onRejected === 'function') {
          resolve(onRejected.call(null, this.message));
        } else {
          reject(this.message);
        }
        break;
      default:
        break;
    }
  }
}

//老哥們註意,這隻是我自己寫的一個簡略的 Promise , 並不是真正的 Promise 的實現

const p = new myPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('你好,兄弟'); //1s後設置成resolve狀態 即是成功
  }, 1e3);
});
p.then(res => {
  console.log(res); // 1s後輸出 ==> 你好,兄弟
  return '1';
})
  .then(res => {
    console.log(res); // 1s後輸出 ==> '1'
  })
  .then(res => {
    console.log(res); // 1s後輸出 ==> undefined
  });

Promise.resolve / reject

Promise 還提供一個快速實例化 Promise ,可以傳入參數並且馬上觸發 Promise 鏈的執行

Promise.resolve = data =>
  new Promise((resolve, reject) => {
    resolve(data);
  });
Promise.reject = err =>
  new Promise((resolve, reject) => {
    reject(err);
  });

Promise.all / race

Promise 還提供 all / race 用來處理數據的併發和競爭,要求是傳一個 Promise 數組作為參數,然後返回一個新的 Promise

all 是全部處理後再統一處理

Promise.all = arr =>
  new Promise((resolve, reject) => {
    let c = 0,
      l = arr.length,
      result = [];
    l === 0 && resolve(result);
    arr.forEach(pro => {
      Promise.resolve(pro).then(res => {
        result.push(res);
        c++;
        c === l && resolve(result);
      },
        err => {
          reject(err);
        }
      );
    });
  });

race 則是誰非同步時間短誰就會被處理

Promise.race = arr =>
  new Promise((resolve, reject) => {
    arr.forEach(pro => {
      Promise.resolve(pro).then(resolve, reject);
    });
  });

Promise.then / catch

Promise 的 then 函數我們也知道是怎麼用的,它始終以當前的結果返回一個新的Promise
而之前我們說到 Promise 的錯誤是非同步的 也直接調用到 reject,
那我們在 resolve 或者 reject 出現錯誤應該怎麼做呢? Promise 還提供一個catch 用來捕捉錯誤

Promise.catch = reject => this.then(undefined,reject)

怎麼用呢?

const p = new Promise((resolve, reject) => {
  //執行操作
  //..略
});

p.then(resolve, reject)
  .then(resolve, reject)
  .then(resolve, reject)
  .catch(err => {
    //如果以上出現錯誤會直接傳遞到此處執行錯誤處理
  });

Promise 和 setTimeout

說是非同步,那麼和我們最原始的 setTimeout 有什麼區別呢?
先讓我們看一道面試題目

console.log('a');

setTimeout(() => {
  console.log('b');
});

console.log('c');

new Promise((resolve, reject) => {
  console.log('d');
  resolve('e');
}).then(res => {
  console.log(res);
});

console.log('f');

輸出順序是什麼呢 ?

a => c => d => f => e => b

這裡就要關係到js的 EventLoop 機制了,這裡並不細說,只是拋個引子,有興趣的朋友可以去看看相關文章

結尾

到這裡就結束了,老哥們,要去搬磚了

Markdown

如果發現文章有什麼問題,可以留言哦
Markdown


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Sublime Text是一款輕量級的易於使用的前端編寫軟體,個人比較推薦。 找到Sublime的官網,下載對應的版本後,點擊安裝。安裝完成後需要下載相應的插件才能進行更加 有效率的開發工作。編寫前端的插件常用的就是Emmet。 首先在Sublime中使用快捷鍵ctrl+shift+p進入頁面,輸入 ...
  • 隨著業務的增加,可能存在這麼一種需求,就是需要從h5中直接跳轉到app。如果沒有安裝app的話,則提示到應用市場或者app store下載安裝。不過問題就在這個地方,單純的用h5是沒有方法判斷是否安裝過app的,不過這些是難不倒程式員的,他們通常會用這種代碼來解決 其實代碼很簡單,先去跳轉公司無線組 ...
  • 1.行內元素和塊級元素?img算什麼?行內元素怎麼轉化為塊級元素? 2.將多個元素設置為同一行?清除浮動有幾種方式? 3.怪異盒模型box-sizing?彈性盒模型|盒佈局? 4.簡述幾個css hack? 5.href和src區別? title和alt 6.transform?animation? ...
  • 最近新開了一個Node項目,採用TypeScript來開發,在資料庫及路由管理方面用了不少的裝飾器,發覺這的確是一個好東西。裝飾器是一個還處於草案中的特性,目前木有直接支持該語法的環境,但是可以通過 babel 之類的進行轉換為舊語法來實現效果,所以在TypeScript中,可以放心的使用@Deco ...
  • 1.viewport標簽 基本語法: <meta name=”viewport” content=”width=device-width,initial-scale=1” /> 上面這行代碼的意思是,面積的100%,網頁寬度預設等於屏幕寬度(width=device-width), 原始縮放比例(i ...
  • 作為程式員(更高大尚的稱謂:研軟體研發)的我們,無論是用Javascript,還是.net, java語言,肯定都遇到過記憶體泄漏的問題。只不過他們都有GC機制來幫助程式員完成記憶體回收的事情,如果你是C++開發者(你懂的)。。。。。,如果你是前端開發者,肯定在使用Javascript(你或者會說,Js ...
  • 一、記憶體泄漏 由於某些原因不再需要的記憶體沒有被操作系統或則空閑記憶體池回收。編程語言中有多種管理記憶體的方式。這些方式從不同程度上會減少記憶體泄漏的幾率,高級語言嵌入了一個名為垃圾收集器的軟體,其工作是跟蹤記憶體分配和使用,以便找到不再需要分配記憶體的時間,在這種情況下,它將自動釋放它。然而,該過程是近似的, ...
  • https://blog.csdn.net/qq_24472595/article/details/70053863 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...