成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

一個(gè)真實(shí)的Async/Await示例

habren / 3184人閱讀

摘要:如果不希望定義多余的外層變量,則需要在鏈中的每一個(gè)函數(shù)中都返回變量,這樣做顯然更加糟糕。

譯者按: 通過(guò)真實(shí)的代碼示例感受Async/Await的力量。

原文: Async/await - A thorough example

譯者: Fundebug

為了保證可讀性,本文采用意譯而非直譯。另外,本文版權(quán)歸原作者所有,翻譯僅用于學(xué)習(xí)。

既然Node.js 8已經(jīng)LTS了,我想大家是時(shí)候試一試Async/Await特性了,真的很好用!它可以幫助我們用同步的方式寫(xiě)異步代碼,極大地提高了代碼的可讀性。在過(guò)去的2年時(shí)間里,Promise給我們帶來(lái)了不少便利,同時(shí)也讓我們有一些失望。

這邊博客,我將介紹一個(gè)真實(shí)的代碼示例,它是一個(gè)REST API的controller。通過(guò)展示我們?nèi)绾螐腜romise切換到async/await,你講能夠體會(huì)到Async/Await的神奇之處!

Promise示例

下面是我的工作項(xiàng)目中真實(shí)的Controller代碼:

const BPromise = require("bluebird");

const { WrongCredentialsError, DBConnectionError, EmailError } = require("./../errors");

/**
 * Emulate an Express.js route call as an example
 */
loginController({}, { json: response => console.log(response) }, null)

function loginController (req, res, err) {
  const { email, password } = req;

  let user;

  BPromise.try(() => validateUserInput(req))
    .then(() => fetchUserByEmail(email))
    .then(fetchedUser => user = fetchedUser)
    .then(() => comparePasswords(req.password, user.password))
    .then(() => markLoggedInTimestamp(user.userId))
    .then(() => sendEmail(user.userId))
    .then(() => generateJWT(user))
    .then(token => res.json({ success: true, token }))
    .catch(WrongCredentialsError, () => res.json({ success: false, error: "Invalid email and/or password" }))
    .catch(EmailError, DBConnectionError, () => res.json({ success: false, error: "Unexpected error, please try again" }))
    .catch(() => res.json({ success: false }))
}

/**
 * Validate input from Request
 *
 * @param {Object} input
 * @throws {WrongCredentialsError}
 * @returns {Void}
 */
function validateUserInput(input) {
  if (!input.email || !input.password) {
    throw new WrongCredentialsError();
  }
}

/**
 * Fetch a User from the DB by Email
 *
 * @throws WrongCredentialsError
 * @throws DBConnectionError
 * @returns {BPromise}
 */
function fetchUserByEmail(email) {
  const user = {
    userId: "DUMMY_ID",
    email: "konmpar@gmail.com",
    password: "DUMMY_PASSWORD_HASH"
  }
  return new BPromise(resolve => resolve(user));
}

/**
 * Compare two password
 *
 * @param {String} inputPwd
 * @param {String} storedPwd
 * @throws {WrongCredentialsError}
 * @returns {Void}
 */
function comparePasswords(inputPwd, storedPwd) {
  if (hashPassword(inputPwd) !== storedPwd) {
    throw new WrongCredentialsError();
  }
}

/**
 * Hash password
 *
 * @param {String} password
 * @returns {String}
 */
function hashPassword(password) {
  return password;
}

/**
 * Mark a user"s logged in timestamp
 *
 * @param {String} userId
 * @throws DBConnectionError
 * @returns {BPromise}
 */
function markLoggedInTimestamp(userId) {
  return new BPromise(resolve => resolve());
}

/**
 * Send a follow up email
 *
 * @param {String} userId
 * @throws EmailError
 * @returns {BPromise}
 */
function sendEmail(userId) {
  return new BPromise(resolve => resolve());
}

/**
 * Generate a JWT token to send to the client
 *
 * @param {Object} user
 * @returns {BPromise}
 */
function generateJWT(user) {
  const token = "DUMMY_JWT_TOKEN";

  return new BPromise(resolve => resolve(token));
}

一些值得注意的要點(diǎn):

多余的外層變量
let user;

/* ... */
  .then(fetchedUser => user = fetchedUser)
  /* ... */
  .then(() => sendEmail(user.userId))
  /* ... */

可知,user是一個(gè)全局變量,因?yàn)槲倚枰赑romise鏈中使用它。如果不希望定義多余的外層變量,則需要在Promise鏈中的每一個(gè)函數(shù)中都返回user變量,這樣做顯然更加糟糕。

煩人的Promise鏈
/* ... */
BPromise.try(() => validateUserInput(req))
/* ... */

一個(gè)Promise鏈必須從Promise開(kāi)始,但是validateUserInput函數(shù)并沒(méi)有返回Promise,這時(shí)需要使用Bluebird。我也知道這樣寫(xiě)比較奇怪...

討厭的Bluebird

我在很多地方都使用了Bluebird,如果不用它的話(huà),代碼會(huì)更加臃腫。所謂DRY,即Don"t repeat yourself,我們可以使用Bluebird去盡量簡(jiǎn)化代碼。但是,Bluebird是一個(gè)第三方依賴(lài),如果出問(wèn)題了怎么辦?去掉Bluebird應(yīng)該更好!

JavaScript太靈(gui)活(yi)了,出了BUG你也不知道,不妨接入Fundebug線上實(shí)時(shí)監(jiān)控。

Async/Await示例

當(dāng)我放棄Promise,使用Async/Await之后,代碼是這樣的:

const { WrongCredentialsError, DBConnectionError, EmailError } = require("./../errors");

/**
 * Emulate an Express.js route call as an example
 */
loginController({}, { json: response => console.log(response) }, null)

/**
 *
 * @param {Object} req
 * @param {Object} res
 * @param {Object} err
 * @returns {Void}
 */
async function loginController(req, res, err) {
  const { email, password } = req.email;

  try {
    if (!email || !password) {
      throw new WrongCredentialsError();
    }

    const user = await fetchUserByEmail(email);

    if (user.password !== hashPassword(req.password)) {
      throw new WrongCredentialsError();
    }

    await markLoggedInTimestamp(user.userId);
    await sendEmail(user.userId);

    const token = await generateJWT(user);

    res.json({ success: true, token });

  } catch (err) {
    if (err instanceof WrongCredentialsError) {
      res.json({ success: false, error: "Invalid email and/or password" })
    } else if (err instanceof DBConnectionError || err instanceof EmailError) {
      res.json({ success: false, error: "Unexpected error, please try again" });
    } else {
      res.json({ success: false })
    }
  }
}

/**
 * Fetch a User from the DB by Email
 *
 * @throws WrongCredentialsError
 * @throws DBConnectionError
 * @returns {Promise}
 */
function fetchUserByEmail(email) {
  const user = {
    userId: "DUMMY_ID",
    email: "konmpar@gmail.com",
    password: "DUMMY_PASSWORD_HASH"
  }
  return new Promise(resolve => resolve(user));
}

/**
 * Hash password
 *
 * @param {String} password
 * @returns {String}
 */
function hashPassword(password) {
  return password;
}

/**
 * Mark a user"s logged in timestamp
 *
 * @param {String} userId
 * @throws DBConnectionError
 * @returns {Promise}
 */
function markLoggedInTimestamp(userId) {
  return new Promise(resolve => resolve());
}

/**
 * Send a follow up email
 *
 * @param {String} userId
 * @throws EmailError
 * @returns {Promise}
 */
function sendEmail(userId) {
  return new Promise(resolve => resolve());
}

/**
 * Generate a JWT token to send to the client
 *
 * @param {Object} user
 * @returns {Promise}
 */
function generateJWT(user) {
  const token = "DUMMY_JWT_TOKEN";

  return new Promise(resolve => resolve(token));
}

哈哈?。?!

沒(méi)有外層變量

現(xiàn)在,所有函數(shù)都在同一個(gè)作用域中調(diào)用,不再需要.then函數(shù)。因此,我們不再需要定義多余的全局變量,也不需要做多余的變量賦值。

沒(méi)有多余的函數(shù)

Promise示例中的同步函數(shù)validateInputcomparePasswords的代碼可以與異步函數(shù)寫(xiě)在一起,因此可以不再需要定義多帶帶的函數(shù),代碼更少。

可讀性更高

異步代碼采用同步方式來(lái)寫(xiě),同時(shí)減少了代碼量,可讀性大大提高。

不再需要Bluebird

原生的Promise可以替代Bluebird,且不再需要Bluebird的try方法了。

結(jié)論

作為程序員,我們應(yīng)該努力完善代碼。Async/Await可以帶來(lái)很大好處,幫助我們寫(xiě)出可讀性更高的代碼。如果你堅(jiān)持使用Promise,不妨看看如何在Promise鏈中共享變量?。

如果你對(duì)Async/Await感興趣的話(huà),可以看看這些博客:

重構(gòu):從Promise到Async/Await

Async/Await替代Promise的6個(gè)理由

Async/Await是這樣簡(jiǎn)化JavaScript代碼的

版權(quán)聲明:
轉(zhuǎn)載時(shí)請(qǐng)注明作者Fundebug以及本文地址:
https://blog.fundebug.com/2018/01/31/a-real-async-await-example/

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/107433.html

相關(guān)文章

  • 重學(xué)前端學(xué)習(xí)筆記(十七)--Promise里代碼為什么比setTimeout先執(zhí)行?

    摘要:版本以及之前,本身還沒(méi)有異步執(zhí)行代碼的能力,宿主環(huán)境傳遞給引擎,然后按順序執(zhí)行,由宿主發(fā)起任務(wù)。采納引擎術(shù)語(yǔ),把宿主發(fā)起的任務(wù)稱(chēng)為宏觀任務(wù),把引擎發(fā)起的任務(wù)稱(chēng)為微觀任務(wù)?;居梅ㄊ纠幕卣{(diào)是一個(gè)異步的執(zhí)行過(guò)程。 筆記說(shuō)明 重學(xué)前端是程劭非(winter)【前手機(jī)淘寶前端負(fù)責(zé)人】在極客時(shí)間開(kāi)的一個(gè)專(zhuān)欄,每天10分鐘,重構(gòu)你的前端知識(shí)體系,筆者主要整理學(xué)習(xí)過(guò)程的一些要點(diǎn)筆記以及感悟,完整的...

    pinecone 評(píng)論0 收藏0
  • 重學(xué)前端學(xué)習(xí)筆記(十七)--Promise里代碼為什么比setTimeout先執(zhí)行?

    摘要:版本以及之前,本身還沒(méi)有異步執(zhí)行代碼的能力,宿主環(huán)境傳遞給引擎,然后按順序執(zhí)行,由宿主發(fā)起任務(wù)。采納引擎術(shù)語(yǔ),把宿主發(fā)起的任務(wù)稱(chēng)為宏觀任務(wù),把引擎發(fā)起的任務(wù)稱(chēng)為微觀任務(wù)?;居梅ㄊ纠幕卣{(diào)是一個(gè)異步的執(zhí)行過(guò)程。 筆記說(shuō)明 重學(xué)前端是程劭非(winter)【前手機(jī)淘寶前端負(fù)責(zé)人】在極客時(shí)間開(kāi)的一個(gè)專(zhuān)欄,每天10分鐘,重構(gòu)你的前端知識(shí)體系,筆者主要整理學(xué)習(xí)過(guò)程的一些要點(diǎn)筆記以及感悟,完整的...

    zorpan 評(píng)論0 收藏0
  • 重學(xué)前端學(xué)習(xí)筆記(十七)--Promise里代碼為什么比setTimeout先執(zhí)行?

    摘要:版本以及之前,本身還沒(méi)有異步執(zhí)行代碼的能力,宿主環(huán)境傳遞給引擎,然后按順序執(zhí)行,由宿主發(fā)起任務(wù)。采納引擎術(shù)語(yǔ),把宿主發(fā)起的任務(wù)稱(chēng)為宏觀任務(wù),把引擎發(fā)起的任務(wù)稱(chēng)為微觀任務(wù)?;居梅ㄊ纠幕卣{(diào)是一個(gè)異步的執(zhí)行過(guò)程。 筆記說(shuō)明 重學(xué)前端是程劭非(winter)【前手機(jī)淘寶前端負(fù)責(zé)人】在極客時(shí)間開(kāi)的一個(gè)專(zhuān)欄,每天10分鐘,重構(gòu)你的前端知識(shí)體系,筆者主要整理學(xué)習(xí)過(guò)程的一些要點(diǎn)筆記以及感悟,完整的...

    xiongzenghui 評(píng)論0 收藏0
  • 重構(gòu):從Promise到Async/Await

    摘要:一方面,這里替代的是異步代碼的編寫(xiě)方式,并非完全拋棄大家心愛(ài)的,地球人都知道是基于的,不用太傷心另一方面,是基于回調(diào)函數(shù)實(shí)現(xiàn)的,那也沒(méi)有替代回調(diào)函數(shù)咯重構(gòu)代碼之后,我仍然用到了庫(kù)。 摘要: 夸張點(diǎn)說(shuō),技術(shù)的發(fā)展與歷史一樣,順之者昌,逆之者亡。JS開(kāi)發(fā)者們,趕緊擁抱Async/Await吧! GitHub倉(cāng)庫(kù): Fundebug/promise-asyncawait 早在半年多之前,...

    zhangfaliang 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<