搜尋
首頁web前端js教程如何將 JavaScript 回呼轉換為 Promise?方法介紹

如何將 JavaScript 回呼轉換為 Promise?方法介紹

在幾年前,回呼是 JavaScript 中實作執行非同步程式碼的唯一方法。回調本身幾乎沒有什麼問題,最值得注意的是「回調地獄」。

在 ES6 中引入了 Promise 作為這些問題的解決方案。最後透過引入  async/await  關鍵字來提供更好的體驗並提高了可讀性。

即使有了新的方法,但仍然有許多使用回呼的原生模組和函式庫。在本文中,我們將討論如何將 JavaScript 回呼轉換為 Promise。 ES6 的知識將會派上用場,因為我們將會使用 展開操作符之類的功能來簡化要做的事情。

什麼是回呼

回呼是一個函數參數,剛好是一個函數本身。雖然我們可以創建任何函數來接受另一個函數,但回調主要用於非同步操作。

JavaScript 是一種解釋性語言,一次只能處理一行程式碼。有些任務可能需要很長時間才能完成,例如下載或讀取大檔案等。 JavaScript 將這些運行時間很長的任務轉移到瀏覽器或 Node.js 環境中的其他進程。這樣它就不會阻止其他程式碼的執行。

通常非同步函數會接受回呼函數,所以完成之後可以處理其資料。

舉個例子,我們將寫一個回呼函數,這個函數會在程式成功從硬碟讀取檔案之後執行。

所以需要準備一個名為sample.txt 的文字文件,其中包含以下內容:

Hello world from sample.txt

然後寫一個簡單的Node.js 腳本來讀取文件:

const fs = require('fs');

fs.readFile('./sample.txt', 'utf-8', (err, data) => {
    if (err) {
        // 处理错误
        console.error(err);
          return;
    }
    console.log(data);
});

for (let i = 0; i <p>運行程式碼後將會輸出:</p><pre class="brush:php;toolbar:false">0
...
8
9
Hello world from sample.txt

如果這段程式碼,應該在執行回呼之前看到0..9 被輸出到控制台。這是因為 JavaScript 的非同步管理機制。在讀取檔案完畢之後,輸出檔案內容的回調才會被呼叫。

順便說明一下,回呼也可以在同步方法中使用。例如  Array.sort()  會接受一個回呼函數,這個函數允許你自訂元素的排序方式。

接受回呼的函數稱為「高階函數」。

現在我們有了一個更好的回呼方法。那麼們繼續看看什麼是 Promise。

什麼是 Promise

在 ECMAScript 2015(ES6)中引入了 Promise,用來改善在非同步程式設計方面的體驗。顧名思義,JavaScript 物件最終將傳回的「值」或「錯誤」應該是一個 Promise。

一個 Promise 有 3 個狀態:

  • Pending(待處理): 用來指示非同步操作尚未完成的初始狀態。
  • Fulfilled(已完成):表示非同步操作已成功完成。
  • Rejected(拒絕):表示非同步操作失敗。

大多數Promise 最終看起來像這樣:

someAsynchronousFunction()
    .then(data => {
        // promise 被完成
        console.log(data);
    })
    .catch(err => {
        // promise 被拒绝
        console.error(err);
    });

Promise 在現代JavaScript 中非常重要,因為它們與ECMAScript 2016 中引入的 async/await 關鍵字一起使用。使用 async / await 就不需要再用回呼或 then()catch() 來寫非同步程式碼。

如果要改寫前面的例子,應該是這樣:

try {
    const data = await someAsynchronousFunction();
} catch(err) {
    // promise 被拒绝
    console.error(err);
}

這看起來很像「一般」的同步 JavaScript。大多數流行的JavaScript庫和新專案都把 Promises 與 async/await 關鍵字放在一起使用。

但是,如果你要更新現有的程式庫或遇到舊的程式碼,則可能會對將基於回呼的 API 遷移到基於 Promise 的 API 感興趣,這樣可以改善你的開發體驗。

來看看將回呼轉換為 Promise 的幾種方法。

將回呼轉換為Promise

Node.js Promise

#大多數在Node.js 中接受回呼的非同步函數(例如fs 模組)有標準的實作方式:把回呼當作最後一個參數傳遞。

例如這是在不指定文字編碼的情況下用fs.readFile() 讀取檔案的方法:

fs.readFile('./sample.txt', (err, data) => {
    if (err) {
        console.error(err);
          return;
    }
    console.log(data);
});

注意:如果你指定utf-8 作為編碼,那麼得到的輸出就是一個字串。如果不指定得到的輸出是 Buffer

另外傳給這個函數的回呼應接受 Error,因為它是第一個參數。之後可以有任意數量的輸出。

如果你需要轉換為 Promise 的函數遵循這些規則,那麼可以用 util.promisify ,這是一個原生 Node.js 模組,其中包含對 Promise 的回呼。

先導入ʻutil`模組:

const util = require('util');

然後用promisify 方法將其轉換為Promise:

const fs = require('fs');
const readFile = util.promisify(fs.readFile);

現在,把新建立的函數用作promise:

readFile('./sample.txt', 'utf-8')
    .then(data => {
        console.log(data);
    })
    .catch(err => {
        console.log(err);
    });

另外也可以用下面這個範例中給的async/await 關鍵字:

const fs = require('fs');
const util = require('util');

const readFile = util.promisify(fs.readFile);

(async () => {
    try {
        const content = await readFile('./sample.txt', 'utf-8');
        console.log(content);
    } catch (err) {
        console.error(err);
    }
})();

你只能在用async 建立的函數中使用await 關鍵字,這也是為什麼要使用函數包裝器的原因。函數包裝器也被稱為立即呼叫的函數表達式。

如果你的回调不遵循这个特定标准也不用担心。 util.promisify() 函数可让你自定义转换是如何发生的。

注意: Promise 在被引入后不久就开始流行了。 Node.js 已经将大部分核心函数从回调转换成了基于 Promise 的API。

如果需要用 Promise 处理文件,可以用 Node.js 附带的库(https://nodejs.org/docs/lates...)。

现在你已经了解了如何将 Node.js 标准样式回调隐含到 Promise 中。从 Node.js 8 开始,这个模块仅在 Node.js 上可用。如果你用的是浏览器或早期版本版本的 Node,则最好创建自己的基于 Promise 的函数版本。

创建你自己的 Promise

让我们讨论一下怎样把回调转为  util.promisify() 函数的 promise。

思路是创建一个新的包含回调函数的 Promise 对象。如果回调函数返回错误,就拒绝带有该错误的Promise。如果回调函数返回非错误输出,就解决并输出 Promise。

先把回调转换为一个接受固定参数的函数的 promise 开始:

const fs = require('fs');

const readFile = (fileName, encoding) => {
    return new Promise((resolve, reject) => {
        fs.readFile(fileName, encoding, (err, data) => {
            if (err) {
                return reject(err);
            }

            resolve(data);
        });
    });
}

readFile('./sample.txt')
    .then(data => {
        console.log(data);
    })
    .catch(err => {
        console.log(err);
    });

新函数 readFile() 接受了用来读取 fs.readFile() 文件的两个参数。然后创建一个新的 Promise 对象,该对象包装了该函数,并接受回调,在本例中为 fs.readFile()

要  reject  Promise 而不是返回错误。所以代码中没有立即把数据输出,而是先 resolve 了Promise。然后像以前一样使用基于 Promise 的 readFile() 函数。

接下来看看接受动态数量参数的函数:

const getMaxCustom = (callback, ...args) => {
    let max = -Infinity;

    for (let i of args) {
        if (i > max) {
            max = i;
        }
    }

    callback(max);
}

getMaxCustom((max) => { console.log('Max is ' + max) }, 10, 2, 23, 1, 111, 20);

第一个参数是 callback 参数,这使它在接受回调的函数中有点与众不同。

转换为 promise 的方式和上一个例子一样。创建一个新的 Promise 对象,这个对象包装使用回调的函数。如果遇到错误,就 reject,当结果出现时将会 resolve

我们的 promise 版本如下:

const getMaxPromise = (...args) => {
    return new Promise((resolve) => {
        getMaxCustom((max) => {
            resolve(max);
        }, ...args);
    });
}

getMaxCustom(10, 2, 23, 1, 111, 20)
    .then(max => console.log(max));

在创建 promise 时,不管函数是以非标准方式还是带有许多参数使用回调都无关紧要。我们可以完全控制它的完成方式,并且原理是一样的。

总结

尽管现在回调已成为 JavaScript 中利用异步代码的默认方法,但 Promise 是一种更现代的方法,它更容易使用。如果遇到了使用回调的代码库,那么现在就可以把它转换为 Promise。

在本文中,我们首先学到了如何 在Node.js 中使用 utils.promisfy() 方法将接受回调的函数转换为 Promise。然后,了解了如何创建自己的 Promise 对象,并在对象中包装了无需使用外部库即可接受回调的函数。这样许多旧 JavaScript 代码可以轻松地与现代的代码库和混合在一起。

更多编程相关知识,请访问:编程学习!!

以上是如何將 JavaScript 回呼轉換為 Promise?方法介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:segmentfault。如有侵權,請聯絡admin@php.cn刪除
es6数组怎么去掉重复并且重新排序es6数组怎么去掉重复并且重新排序May 05, 2022 pm 07:08 PM

去掉重复并排序的方法:1、使用“Array.from(new Set(arr))”或者“[…new Set(arr)]”语句,去掉数组中的重复元素,返回去重后的新数组;2、利用sort()对去重数组进行排序,语法“去重数组.sort()”。

JavaScript的Symbol类型、隐藏属性及全局注册表详解JavaScript的Symbol类型、隐藏属性及全局注册表详解Jun 02, 2022 am 11:50 AM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于Symbol类型、隐藏属性及全局注册表的相关问题,包括了Symbol类型的描述、Symbol不会隐式转字符串等问题,下面一起来看一下,希望对大家有帮助。

原来利用纯CSS也能实现文字轮播与图片轮播!原来利用纯CSS也能实现文字轮播与图片轮播!Jun 10, 2022 pm 01:00 PM

怎么制作文字轮播与图片轮播?大家第一想到的是不是利用js,其实利用纯CSS也能实现文字轮播与图片轮播,下面来看看实现方法,希望对大家有所帮助!

JavaScript对象的构造函数和new操作符(实例详解)JavaScript对象的构造函数和new操作符(实例详解)May 10, 2022 pm 06:16 PM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于对象的构造函数和new操作符,构造函数是所有对象的成员方法中,最早被调用的那个,下面一起来看一下吧,希望对大家有帮助。

JavaScript面向对象详细解析之属性描述符JavaScript面向对象详细解析之属性描述符May 27, 2022 pm 05:29 PM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于面向对象的相关问题,包括了属性描述符、数据描述符、存取描述符等等内容,下面一起来看一下,希望对大家有帮助。

javascript怎么移除元素点击事件javascript怎么移除元素点击事件Apr 11, 2022 pm 04:51 PM

方法:1、利用“点击元素对象.unbind("click");”方法,该方法可以移除被选元素的事件处理程序;2、利用“点击元素对象.off("click");”方法,该方法可以移除通过on()方法添加的事件处理程序。

foreach是es6里的吗foreach是es6里的吗May 05, 2022 pm 05:59 PM

foreach不是es6的方法。foreach是es3中一个遍历数组的方法,可以调用数组的每个元素,并将元素传给回调函数进行处理,语法“array.forEach(function(当前元素,索引,数组){...})”;该方法不处理空数组。

整理总结JavaScript常见的BOM操作整理总结JavaScript常见的BOM操作Jun 01, 2022 am 11:43 AM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于BOM操作的相关问题,包括了window对象的常见事件、JavaScript执行机制等等相关内容,下面一起来看一下,希望对大家有帮助。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中