摘要:我們就可以升級以前所有的異步回調(diào)函數(shù)了。大體上來說,這套方案通過使用回調(diào)實(shí)例包裹原先的回調(diào)函數(shù),可以將原先復(fù)雜的嵌套展開鋪平,從而降低開發(fā)和維護(hù)的難度和成本。
Node.js 8 于上個(gè)月月底正式發(fā)布,帶來了很多新特性。其中比較值得注意的,便有 util.promisify() 這個(gè)方法。
util.promisify()如果你已經(jīng)很熟悉 Promise,請繼續(xù)往下看。如果你還不熟悉 Promise,可以先跳過去看下下章:Promise 介紹。
雖然 Promise 已經(jīng)普及,但是 Node.js 里仍然有大量依賴回調(diào)的異步函數(shù),如果我們把每個(gè)函數(shù)都封裝一遍,那真是齁麻煩齁麻煩的,比齁還麻煩。
所以 Node.js 8 就提供了 util.promisify() 這個(gè)方法,方便我們把原來的異步回調(diào)方法改成支持 Promise 的方法,接下來,想繼續(xù) .then().then().then() 搞隊(duì)列,還是 await 就看實(shí)際需要了。
我們看下范例,讓讀取目錄文件狀態(tài)的 fs.stat 支持 Promise:
const util = require("util"); const fs = require("fs"); const stat = util.promisify(fs.stat); stat(".") .then((stats) => { // Do something with `stats` }) .catch((error) => { // Handle the error. });
怎么樣,很簡單吧?按照文檔的說法,只要符合 Node.js 的回調(diào)風(fēng)格,所有函數(shù)都可以這樣轉(zhuǎn)換。也就是說,只要滿足下面兩個(gè)條件,無論是不是原生方法,都可以:
最后一個(gè)參數(shù)是回調(diào)函數(shù)
回調(diào)函數(shù)的參數(shù)為 (err, result),前面是可能的錯(cuò)誤,后面是正常的結(jié)果
結(jié)合 Await/Async 使用同樣是上面的例子,如果想要結(jié)合 Await/Async,可以這樣使用:
const util = require("util"); const fs = require("fs"); const stat = util.promisify(fs.stat); async function readStats(dir) { try { let stats = await stat(dir); // Do something with `stats` } catch (err) { // Handle the error. console.log(err); } } readStats(".");自定義 Promise 化處理函數(shù)
那如果現(xiàn)有的使用回調(diào)的函數(shù)不符合這個(gè)風(fēng)格,還能用 util.promisify() 么?答案也是肯定的。我們只要給函數(shù)增加一個(gè)屬性 util.promisify.custom,指定一個(gè)函數(shù)作為 Promise 化處理函數(shù),即可。請看下面的代碼:
const util = require("util"); // 這就是要處理的使用回調(diào)的函數(shù) function doSomething(foo, callback) { // ... } // 給它增加一個(gè)方法,用來在 Promise 化時(shí)調(diào)用 doSomething[util.promisify.custom] = function(foo) { // 自定義生成 Promise 的邏輯 return getPromiseSomehow(); }; const promisified = util.promisify(doSomething); console.log(promisified === doSomething[util.promisify.custom]); // prints "true"
如此一來,任何時(shí)候我們對目標(biāo)函數(shù) doSomething 進(jìn)行 Promise 化處理,都會得到之前定義的函數(shù)。運(yùn)行它,就會按照我們設(shè)計(jì)的特定邏輯返回 Promise 實(shí)例。
我們就可以升級以前所有的異步回調(diào)函數(shù)了。
Promise 介紹因?yàn)榉N種歷史原因,JS 當(dāng)中有大量異步函數(shù)。這些異步函數(shù),大多要依賴回調(diào)進(jìn)行處理(這里我覺得把事件偵聽算作回調(diào)也是合理的),但是回調(diào)嵌套層次一多,就會形成所謂的“回調(diào)陷阱”,讓開發(fā)者苦不堪言。
為了解決這個(gè)問題,開發(fā)社區(qū)經(jīng)過摸索,總結(jié)出來一套名為 Promise/A+ 的解決方案。大體上來說,這套方案通過使用 “Promise 回調(diào)實(shí)例”包裹原先的回調(diào)函數(shù),可以將原先復(fù)雜的嵌套展開、鋪平,從而降低開發(fā)和維護(hù)的難度和成本。
new Promise( (resolve, reject) => { // 構(gòu)建一個(gè) Promise 實(shí)例 someAsyncFunction( (err, result) => { // 調(diào)用原來的異步函數(shù) if (err) { // 發(fā)生錯(cuò)誤,進(jìn)入錯(cuò)誤處理模式 return reject(err); } resolve(result); // 一切正常,進(jìn)入隊(duì)列的下一環(huán)節(jié) }); }) .then( result => { // 下一環(huán)節(jié) return doSomething(result); }) .then( result2 => { // 又下一環(huán)節(jié) return doSomething2(result2); }) ... // 各種中間環(huán)節(jié) .catch( err => { // 錯(cuò)誤處理 console.log(err); });
ES2015(ES6)里包含了 Promise 標(biāo)準(zhǔn),如今已經(jīng)在大部分運(yùn)行時(shí)里實(shí)裝,我們可以放心大膽的使用它。而且,由于 Promise 不需要新的語法元素,所以即使在不支持原生 Promise 的環(huán)境里也可以使用類庫,比如 Q 或者 Bluebird,甚至 jQuery。
在小程序里也有效喲!
ES2017 增加了 Await/Async 語法,但請注意,Await 后面必須跟 Promise 實(shí)例才能實(shí)現(xiàn)異步。所以,大家還是把 Promise 的概念學(xué)好吧!
function resolveAfter2Seconds(x) { return new Promise(resolve => { setTimeout(() => { resolve(x); }, 2000); }); } async function f1() { var x = await resolveAfter2Seconds(10); console.log(x); // 10 } f1();
例子來源于 MDN。
如果你想進(jìn)一步學(xué)習(xí)使用 Promise,強(qiáng)烈推薦我的這次分享:Promise 的 N 種用法。可以幫助你一站式的學(xué)會使用 Promise。
PS2:剛才看到 Node.js 已經(jīng)發(fā)布 8.1 了,真快呀……新版本的 Changelog 在這里,已修復(fù)為主。
擴(kuò)展閱讀:util.promisify() in Node.js v8
官方文檔
官方文檔 自定義 Promise 化處理函數(shù)
同步發(fā)于 我的博客
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/87022.html
摘要:例如,的回調(diào)函數(shù)包含下面幾個(gè)參數(shù)轉(zhuǎn)換成之后,它的參數(shù)將會變成這樣一個(gè)對象通過內(nèi)部符號處理非標(biāo)準(zhǔn)回調(diào)函數(shù)。 Nodejs 8 有一個(gè)新的工具函數(shù) util.promisify()。他將一個(gè)接收回調(diào)函數(shù)參數(shù)的函數(shù)轉(zhuǎn)換成一個(gè)返回Promise的函數(shù)。 1、util.promisify()小例子 如果你給以下命令傳入文件路徑,則會輸出文件內(nèi)容 // echo.js const {promis...
摘要:自定義的化有那么一些場景,是不能夠直接使用來進(jìn)行轉(zhuǎn)換的,有大概這么兩種情況沒有遵循約定的回調(diào)函數(shù)返回多個(gè)參數(shù)的回調(diào)函數(shù)首先是第一個(gè),如果沒有遵循我們的約定,很可能導(dǎo)致的誤判,得不到正確的反饋。 util.promisify是在node.js 8.x版本中新增的一個(gè)工具,用于將老式的Error first callback轉(zhuǎn)換為Promise對象,讓老項(xiàng)目改造變得更為輕松。 在官方推...
摘要:一個(gè)包括文件緩存?zhèn)鬏攭嚎s模版引擎類型匹配等功能的靜態(tài)資源服務(wù)器,使用的內(nèi)置模塊實(shí)現(xiàn),可以通過鏈接訪問資源。二使用讀取資源文件我們的目的是搭建一個(gè)靜態(tài)資源服務(wù)器,當(dāng)訪問一個(gè)到資源文件或目錄時(shí),我們希望可以得到它。 一個(gè)包括文件緩存、傳輸壓縮、ejs 模版引擎、MIME 類型匹配等功能的 Node 靜態(tài)資源服務(wù)器,使用 Node 的內(nèi)置模塊實(shí)現(xiàn),可以通過鏈接訪問資源。 一、創(chuàng)建 HTTP Se...
摘要:控制臺將顯示回調(diào)地獄通常,回調(diào)只能由一個(gè)異步函數(shù)調(diào)用。更多資源使更友好規(guī)范使用異步函數(shù)簡化異步編碼旅程異步編程是一項(xiàng)在中無法避免的挑戰(zhàn)。 JavaScript經(jīng)常聲稱是_異步_。那是什么意思?它如何影響發(fā)展?近年來這種方法有何變化? 請思考以下代碼: result1 = doSomething1(); result2 = doSomething2(result1); 大多數(shù)語言都處理每...
摘要:控制臺將顯示回調(diào)地獄通常,回調(diào)只能由一個(gè)異步函數(shù)調(diào)用。更多資源使更友好規(guī)范使用異步函數(shù)簡化異步編碼旅程異步編程是一項(xiàng)在中無法避免的挑戰(zhàn)。 JavaScript經(jīng)常聲稱是_異步_。那是什么意思?它如何影響發(fā)展?近年來這種方法有何變化? 請思考以下代碼: result1 = doSomething1(); result2 = doSomething2(result1); 大多數(shù)語言都處理每...
閱讀 1229·2021-09-26 09:55
閱讀 3200·2019-08-30 15:55
閱讀 971·2019-08-30 15:53
閱讀 2297·2019-08-30 13:59
閱讀 2383·2019-08-29 13:08
閱讀 1111·2019-08-29 12:19
閱讀 3307·2019-08-26 13:41
閱讀 421·2019-08-26 13:24