ES6指南

ECMAScript是JavaScript基于的标准,通常缩写为ES。了解关于ECMAScript的一切以及ES6(又称ES2015)中添加的功能。 箭头函数 新的this作用域 Promises 生成器 let和const 类 构造函数 Super 取值器和存值器 模块 导入模块 导出模块 模板字符串 默认参数 展开运算符 解构赋值 增强的对象字面量 更简洁的语法来包含变量 原型 super() 动态属性 for-of循环 Map和Set 新的字符串方法 新的对象方法 ECMAScript 2015,也称为ES6,是ECMAScript标准的基本版本。 与最新的标准修订相隔4年发布,ECMAScript 5.1,它也标志着从版本号转换为年份的变化。 因此不应该称为ES6(尽管每个人都这样称呼),而应该称为ES2015。 ES5的制定历经了10年,从1999年到2009年,因此它也是一次基本而非常重要的语言修订,但现在已经过去了很长时间,没有必要讨论ES5之前的代码是如何工作的了。 由于ES5.1和ES6之间过去了很长时间,因此发布版本中充满了重要的新功能和对JavaScript程序开发中推荐最佳实践的重大变化。要了解ES2015有多么基础,请记住,随着这个版本,规范文档从250页增加到了~600页。 本文描述了最重要的变化。 箭头函数 自引入以来,箭头函数改变了大多数JavaScript代码的外观(和工作原理)。 从视觉上看,这是一个简单而受欢迎的变化,从: const something = function something() { //... } 到 const something = () => { //... } 如果函数体只有一行代码,只需: const something = () => doSomething() 此外,如果只有一个参数,可以写成: const something = param => doSomething(param) 这并不是一个破坏性的变化,常规的function仍然像以前一样工作。 新的this作用域 箭头函数的this作用域是从上下文继承的。...

Fetch API

了解所有關於 Fetch API 的知識,這是一種基於 Promise 的異步網路請求的現代方法。 介紹 Fetch API 使用 Fetch 捕捉錯誤 Response 物件 Metadata headers status statusText url 內容主體 Request 物件 請求標頭 POST 請求 如何取消 Fetch 請求 尋找更多資訊? 介紹 Fetch API 自從 IE5 在1998年釋出以來,我們在瀏覽器中有使用 XMLHttpRequest (XHR) 這個選項進行異步網路請求。 在幾年之後,GMail 和其他豐富的應用程式廣泛使用它,使得這種方法變得非常受歡迎,甚至需要一個名稱,AJAX。 直接使用 XMLHttpRequest 一直都很麻煩,所以通常會被某些庫抽象化,而 jQuery 就有其自己的相關幫助方法: jQuery.ajax() jQuery.get() jQuery.post() 它們對於使得這一切變得更加容易特別有著巨大的影響,尤其是在保證它們在舊版瀏覽器上的兼容性方面。 Fetch API 就是一種現代化的異步網路請求方法,並使用 Promises 作為其基礎。 Fetch 在主要的瀏覽器上有著良好的支援,除了 IE。 由 GitHub 提供的 polyfill https://github.com/github/fetch 讓我們可以在任何瀏覽器上使用 fetch。 使用 Fetch 開始使用 Fetch 發送 GET 請求非常簡單:...

JavaScript 事件循環

事件循環是理解 JavaScript 最重要的方面之一。本文將以簡單的方式解釋它。 介紹 阻塞事件循環 調用堆棧 簡單的事件循環解釋 排隊執行函數 消息隊列 ES6 任務隊列 介紹 了解 JavaScript 的事件循環是非常重要的。 我已經用 JavaScript 編程多年了,但我從來沒有完全理解它的運作原理。不知道這個概念的詳細細節是完全正常的,但通常還是有助於了解它的運作方式,而且你可能對此有點好奇。 本文旨在解釋 JavaScript 的內部細節,介紹單線程如何處理異步函數。 JavaScript 代碼在單線程運行,一次只能做一件事。 這是一個實際上非常有用的限制,因為它簡化了編程,不必擔心並發問題。 只需要注意如何編寫代碼,避免阻塞線程的任何操作,如同步網絡調用或無限循環。 通常情況下,大多數瀏覽器每個瀏覽器選項卡都有一個事件循環,以使每個過程都是獨立的,避免無限循環或繁重處理的網頁阻塞整個瀏覽器。 環境管理多個並發的事件循環,以處理 API 調用。Web Workers 也在自己的事件循環中運行。 你主要需要關注的是,你的代碼會在單個事件循環中運行,要以此為依據編寫代碼,避免對其進行阻塞。 阻塞事件循環 任何需要太長時間才能將控制權歸還給事件循環的 JavaScript 代碼都會阻塞頁面中的任何 JavaScript 代碼的執行,甚至會阻塞 UI 线程,用戶無法進行點擊、滾動頁面等操作。 在 JavaScript 中,幾乎所有 I/O 原語都是非阻塞的。網絡請求、Node.js 文件系統操作等都是非阻塞的。阻塞是例外,這就是為什麼 JavaScript 在回調、近來在 promises 和 async/await 上投入了大量資源的原因。 調用堆棧 調用堆棧是一個 LIFO(「後進先出」)隊列。 事件循環不斷檢查 調用堆棧 是否有需要運行的函數。 在此過程中,它將堆棧中找到的所有調用放入調用堆棧並按順序執行。 你可能熟悉調試器或瀏覽器控制台中的錯誤堆棧跟踪,瀏覽器會在堆棧中查找函數名以通知你當前調用的函數: 簡單的事件循環解釋 舉個例子: 我將使用 foo、bar 和 baz 作為隨機名稱。請輸入任意名稱以替換它們 const bar = () => console....

JavaScript中的延遲和承諾(+ Ember.js示例)

承諾是一種相對較新的處理異步的方式,它可以非常有助於結構化代碼。 警告:此帖子已經過時並且可能不反映最新的技術水平。 請查看我的Promises guide和我的async/await guide。 承諾是事件的對象表示方式。在其生命週期中,當調用時,承諾從待定狀態轉換為已解決或已拒絕狀態,或者它也可以永遠保持待定狀態而不解決。 它是一種對JavaScript事件的新方法,但我認為它生成的代碼更易讀且更少出錯。目前,在JavaScript中有兩種稍有不同的主要承諾實現:遵循Promises/A規範的庫和jQuery。 首先,我將考慮jQuery,因為它無處不在且我使用它,所以如果您不希望使用另外一個外部庫,可以使用它。 介紹jQuery Promise 讓我們介紹延遲的概念。首先,延遲是一個承諾,除了您可以觸發一個延遲(解決或拒絕它)之外,通過承諾,您只能添加回調,並且它將由其他東西觸發。如果您希望,承諾是延遲的“只收聽”部分。 這是一個清晰的例子: var promise = $('div.alert').fadeIn().promise(); 您現在可以添加.done()和.fail()來處理回調。這只是一個調用示例,使用承諾的動畫已經成為jQuery 1.8中的一個真正的東西,同時帶有進度的回調。 另一個例子是AJAX調用: var promise = $.get(url); promise.done(function(data) {}); 延遲是您可以創建的東西,設置回調並解決的東西,例如: var deferred = new $.Deferred(); deferred.done(function(data) { console.log(data) }); deferred.resolve('some data'); 延遲的狀態可以使用.resolve()或.reject()觸發。一旦延遲狀態已經更改為最終階段(已解決/已拒絕),它就無法再改變。 var deferred = new $.Deferred(); deferred.state(); // "pending" deferred.resolve(); deferred.state(); // "resolved" 我們可以將以下回調附加到一個承諾: .done() // 當承諾成功執行時運行 .fail() // 當承諾失敗時運行 .always() // 無論什麼情況下都運行 可以使用.then()一起調用這些回調,如下所示: promise.then(doneFunc, failFunc, alwaysFunc); 這只是對承諾和延遲的jQuery實現的介紹。讓我們寫一些真實世界的例子。 (如果在node中執行,可以使用$ = require('jquery');導入jQuery) 一些jQuery示例 例如,這裡我們執行一個函數,當它完成時調用dfd.resolve()。類似於使用回調,但更具結構性和可重用性。...

Node.js事件循環

事件循環是了解Node.js最重要的方面之一。 為什麼這個很重要?因為它解釋了Node.js為什麼可以是非同步的並且具有非阻塞的I/O,也解釋了Node.js的"殺手級應用",這正是使它變得如此成功的原因。 Node.js的JavaScript代碼運行在單個線程上,一次只能發生一件事。 這實際上是一種很有幫助的限制,因為它簡化了編程,不需要擔心並發問題。 您只需注意如何編寫代碼,避免阻塞線程的任何事情,例如同步網絡調用或無限循環。 總的來說,在大多數瀏覽器中,每個瀏覽器標簽都有一個事件循環,以確保每個進程都是隔離的,避免網頁中的無限循環或重型處理導致整個瀏覽器被阻塞。 環境管理多個並發的事件循環,以處理API調用等。Web Worker也運行在它們自己的事件循環中。 您只需要關心您的代碼將運行在一個單獨的事件循環上,並根據這一點來編寫代碼,以避免阻塞它。 阻塞事件循環 任何需要太長時間才能將控制權交還給事件循環的JavaScript代碼將會阻塞頁面上的任何JavaScript代碼的執行,甚至阻塞UI線程,使用戶無法點擊、滾動頁面等。 在JavaScript中,幾乎所有的I/O原語都是非阻塞的,例如網絡請求、文件系統操作等。阻塞是例外,這就是為什麼JavaScript在很大程度上基於回調,最近則是基於Promise和async/await的原因。 調用堆疊 調用堆疊是一個後進先出(LIFO)的隊列。 事件循環會不斷檢查調用堆疊,以查看是否有需要運行的函數。 在這個過程中,它將找到的每個函數調用添加到調用堆疊中,並按順序執行每個函數。 您可能熟悉調試器或瀏覽器控制台中的錯誤堆疊跟踪,瀏覽器通過查找調用堆疊中的函數名稱來告訴您哪個函數產生了當前的調用,如下圖所示: 一個簡單的事件循環解釋 讓我們舉個例子: const bar = () => console.log('bar') const baz = () => console.log('baz') const foo = () => { console.log('foo') bar() baz() } foo() 這段代碼將打印出: foo bar baz 如預期一樣。 當代碼運行時,首先調用foo(),在foo()內部,我們首先調用bar(),然後調用baz()。 此時,調用堆疊如下: 事件循環在每次迭代時檢查調用堆疊,並執行其中的所有函數,直到調用堆疊為空。 排隊函數的執行 上面的示例看起來很正常,沒有什麼特別之處,JavaScript找到要執行的東西,按順序執行它們。 讓我們來看看如何延遲一個函數,直到堆疊清空。 setTimeout(() => {}, 0)的用法是調用一個函數,但是在代碼中的其他函數執行完畢之後再執行它。 請看下面的例子: const bar = () => console.log('bar') const baz = () => console.log('baz') const foo = () => { console....

在 Svelte 模板中解析 Promises

學習如何在 Svelte 模板中處理 Promises Promises 是一種在 JavaScript 中處理異步事件的強大工具。 ES2017 中相對較新引入的 await 語法使得使用 Promises 更加簡單。 Svelte 在模板中提供了 {#await} 語法,以直接處理模板層級的 Promises。 我們可以等待 Promises 解析,並為 Promise 的各種狀態(未解析、已解析和被拒絕)定義不同的 UI。 這是它的工作原理。我們定義一個 Promise,然後使用 {#await} 區塊等待其解析。 一旦 Promise 解析完成,結果將傳遞給 {:then} 區塊: <script> const fetchImage = (async () => { const response = await fetch('https://dog.ceo/api/breeds/image/random') return await response.json() })() </script> {#await fetchImage} <p>...等待中</p> {:then data} <img src={data.message} alt="狗圖片" /> {/await} 您可以通過添加 {:catch} 區塊來檢測 Promise 的拒絕: {#await fetchImage} <p>...等待中</p> {:then data} <img src={data....

如何使用 Node.js 的 fs 模組與 async/await

Node.js 內建的模組以往被稱為非 promise-based 模組。 這是由於在 promise 之前,這些模組就已經存在了。 我們已經有了 promisify 有一段時間了。但我最近發現 Node.js 提供了一個新的基於 promise 的 API。 我以為這是新功能,但它其實已經在 Node.js 10(2018年)中引入了,已經過了一段時間! 目前這個功能只適用於 fs 內建模組。 我不確定這是否很快就會移植到其他原生模組。 以下是如何使用它: import * as fs from 'node:fs/promises'; | 注意到現在可以使用 node:fs 约定来識別內建模組。 現在你可以使用任何 fs 方法,使用 promises 或 await: const posts = await fs.readdir('content');

如何使用Async和Await與Array.prototype.map()

結合async/await和map()的使用可能有點棘手。了解如何使用。 您想在map()調用中執行一個異步函數,對數組的每個元素執行操作並取回結果。 該如何做到這一點? 這是正確的語法: const list = [1, 2, 3, 4, 5] //... 填充了數值的數組 const functionThatReturnsAPromise = item => { //返回一個Promise的函數 return Promise.resolve('ok') } const doSomethingAsync = async item => { return functionThatReturnsAPromise(item) } const getData = async () => { return Promise.all(list.map(item => doSomethingAsync(item))) } getData().then(data => { console.log(data) }) 主要要注意的是Promise.all()的使用,當所有的Promise都被解析時,它才會被解析。 list.map()返回一個Promise列表,所以在result中,我們將得到當我們運行的所有內容都被解析時的值。 請記住,在調用await的任何代碼周圍都必須包裹在一個async函數中。 有關Promise的詳細信息,請參見Promises文章,以及async/await指南。 使用這些占位符函數名稱來展示示例可能很難理解,所以這是一個簡單的例子,展示了如何使用這種技巧,這是我為Twitter克隆版本編寫的Prisma數據刪除函數,首先刪除推文,然後刪除用戶: export const clearData = async (prisma) => { const users = await prisma.user.findMany({}) const tweets = await prisma....

如何在 Node.js 的回調函數中使用 promises 和 await

大部分的 Node.js API 在還沒有 promises 的時候就已經建立了,在這些 API 中,使用了回調函數的解決方案。 一般的 Node.js API 使用方式如下: doSomething(param, (err, result) => { }) 這個也同樣適用於一些庫,例如 node-redis。當我在一個項目中使用它時,到了某個時候我真的需要把所有的回調函數都移除掉,因為我有太多層次的嵌套回調函數,這種情況下就會陷入所謂的 “回調地獄”。 另外,有時候必須避免使用回調函數,因為你需要從函數中返回函數調用的結果。如果這個結果是通過回調函數返回的,那麼想要獲取結果的唯一方法就是將它作為另一個函數的參數返回,進而持續進行回調函數的操作。 const myFunction = () => { doSomething(param, (err, result) => { return result //無法從 `myFunction` 中返回這個結果 }) } const myFunction = callback => { doSomething(param, (err, result) => { callback(result) //不行 }) } myFunction(result => { console.log(result) }) 但是,有一個簡單的解決方案,這也是由 Node.js 自身提供的。我們可以通過使用內置的 util 模塊中的 promisify 方法 “promisify” 一個不支援 promises 的函數(以及相應的 async/await 語法)。...

如何在Node.js中使用MongoDB

在本教程中,我將向您展示如何從Node.js與MongoDB數據庫進行互動。 如果您對MongoDB不熟悉,請查閱我們的基礎指南,以及如何安裝和使用它的指南:) 我們將使用官方的mongodb npm套件。如果您已經有一個正在進行中的Node.js項目,可以使用以下命令來安裝它: npm install mongodb 如果您從頭開始,請在終端中創建一個新的文件夾,然後運行npm init -y來啟動新的Node.js項目,然後運行npm install mongodb命令。 連接到MongoDB 您需要引入mongodb套件,然後從中獲取MongoClient對象。 const mongo = require('mongodb').MongoClient 創建MongoDB服務器的URL。如果您在本地使用MongoDB,URL將是類似mongodb://localhost:27017的形式,因為27017是默認端口。 const url = 'mongodb://localhost:27017' 然後使用mongo.connect()方法來獲取對MongoDB實例客戶端的引用。 mongo.connect(url, { useNewUrlParser: true, useUnifiedTopology: true }, (err, client) => { if (err) { console.error(err) return } // ... }) 現在,您可以使用client.db()方法選擇數據庫。 const db = client.db('kennel') 創建並獲取集合 您可以使用db.collection()方法獲取集合。如果集合還不存在,它將被創建。 const collection = db.collection('dogs') 向集合插入數據 在app.js中添加以下函數,它使用insertOne()方法將一個對象添加到dogs集合中。 collection.insertOne({name: 'Roger'}, (err, result) => { }) 您可以使用insertMany()來添加多個項目,將數組作為第一個參數傳入。 collection.insertMany([{name: 'Togo'}, {name: 'Syd'}], (err, result) => { }) 查找所有文檔 使用集合上的find()方法來獲取添加到集合中的所有文檔。...