国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

深入前端-JavaScript異步編程

raise_yang / 1578人閱讀

摘要:缺點無法取消當處于狀態時,無法得知目前進展到哪一個階段錯誤不能被生成器什么是函數是提供的一種異步編程解決方案,語法行為與傳統函數完全不同函數有多種理解角度。

JavaScript的執行機制在上篇文章中進行了深入的探討,那么既然是一門單線程語言,如何進行良好體驗的異步編程呢
回調函數Callbacks

當程序跑起來時,一般情況下,應用程序(application program)會時常通過API調用庫里所預先備好的函數。但是有些庫函數(library function)卻要求應用先傳給它一個函數,好在合適的時候調用,以完成目標任務。這個被傳入的、后又被調用的函數就稱為回調函數(callback function)。

什么是異步

"調用"在發出之后,這個調用就直接返回了,所以沒有返回結果。換句話說,當一個異步過程調用發出后,調用者不會立刻得到結果。而是在"調用"發出后,"被調用者"通過狀態、通知來通知調用者,或通過回調函數處理這個調用。異步調用發出后,不影響后面代碼的執行。
簡單說就是一個任務分成兩段,先執行第一段,然后轉而執行其他任務,等做好了準備,再回過頭執行第二段。
在異步執行的模式下,每一個異步的任務都有其自己一個或著多個回調函數,這樣當前在執行的異步任務執行完之后,不會馬上執行事件隊列中的下一項任務,而是執行它的回調函數,而下一項任務也不會等當前這個回調函數執行完,因為它也不能確定當前的回調合適執行完畢,只要引它被觸發就會執行,

地獄回調階段

異步最早的解決方案是回調函數,如事件的回調,setInterval/setTimeout中的回調。但是回調函數有一個很常見的問題,就是回調地獄的問題
下面這幾種都屬于回調

事件回調

Node API

setTimeout/setInterval中的回調函數

ajax 請求

異步回調嵌套會導致代碼難以維護,并且不方便統一處理錯誤,不能 try catch會陷入回調地獄

fs.readFile(A, "utf-8", function(err, data) {
    fs.readFile(B, "utf-8", function(err, data) {
        fs.readFile(C, "utf-8", function(err, data) {
            fs.readFile(D, "utf-8", function(err, data) {
                //....
            });
        });
    });
});

ajax(url, () => {
    // 處理邏輯
    ajax(url1, () => {
        // 處理邏輯
        ajax(url2, () => {
            // 處理邏輯
        })
    })
})

Promise解決地獄回調階段

Promise 一定程度上解決了回調地獄的問題,Promise 最早由社區提出和實現,ES6 將其寫進了語言標準,統一了用法,原生提供了Promise對象。

Promise存在三個狀態(state)pending、fulfilled、rejected

pending(等待態)為初始態,并可以轉化為fulfilled(成功態)和rejected(失敗態)

成功時,不可轉為其他狀態,且必須有一個不可改變的值(value)

失敗時,不可轉為其他狀態,且必須有一個不可改變的原因(reason)

new Promise((resolve, reject)=>{resolve(value)}) resolve為成功,接收參數value,狀態改變為fulfilled,不可再次改變。

new Promise((resolve, reject)=>{reject(reason)}) reject為失敗,接收參數reason,狀態改變為rejected,不可再次改變。

若是executor函數報錯 直接執行reject();

Promise 是一個構造函數,new Promise 返回一個 promise對象
const promise = new Promise((resolve, reject) => {
       // 異步處理
       // 處理結束后、調用resolve 或 reject
});
then方法注冊 當resolve(成功)/reject(失敗)的回調函數
// onFulfilled 參數是用來接收promise成功的值,
// onRejected 參數是用來接收promise失敗的原因
//兩個回調返回的都是promise,這樣就可以鏈式調用
promise.then(onFulfilled, onRejected); 
const promise = new Promise((resolve, reject) => {
   resolve("fulfilled"); // 狀態由 pending => fulfilled
});
promise.then(result => { // onFulfilled
    console.log(result); // "fulfilled" 
}, reason => { // onRejected 不會被調用
    
})
then方法的鏈式調用

Promise對象的then方法返回一個新的Promise對象,因此可以通過鏈式調用then方法。then方法接收兩個函數作為參數,第一個參數是Promise執行成功時的回調,第二個參數是Promise執行失敗時的回調。兩個函數只會有一個被調用,函數的返回值將被用作創建then返回的Promise對象。這兩個參數的返回值可以是以下三種情況中的一種:

return 一個同步的值 ,或者 undefined(當沒有返回一個有效值時,默認返回undefined),then方法將返回一個resolved狀態的Promise對象,Promise對象的值就是這個返回值。

return 另一個 Promise,then方法將根據這個Promise的狀態和值創建一個新的Promise對象返回。

throw 一個同步異常,then方法將返回一個rejected狀態的Promise, 值是該異常。

解決層層回調問題
//對應上面第一個node讀取文件的例子
function read(url) {
    return new Promise((resolve, reject) => {
        fs.readFile(url, "utf8", (err, data) => {
            if(err) reject(err);
            resolve(data);
        });
    });
}
read(A).then(data => {
    return read(B);
}).then(data => {
    return read(C);
}).then(data => {
    return read(D);
}).catch(reason => {
    console.log(reason);
});
//對應第二個ajax請求例子
ajax(url)
  .then(res => {
      console.log(res)
      return ajax(url1)
  }).then(res => {
      console.log(res)
      return ajax(url2)
  }).then(res => console.log(res))

可以看到,Promise在一定程度上其實改善了回調函數的書寫方式,最明顯的一點就是去除了橫向擴展,無論有再多的業務依賴,通過多個then(...)來獲取數據,讓代碼只在縱向進行擴展;另外一點就是邏輯性更明顯了,將異步業務提取成單個函數,整個流程可以看到是一步步向下執行的,依賴層級也很清晰,最后需要的數據是在整個代碼的最后一步獲得。
所以,Promise在一定程度上解決了回調函數的書寫結構問題,但回調函數依然在主流程上存在,只不過都放到了then(...)里面,和我們大腦順序線性的思維邏輯還是有出入的。

Promise缺點

無法取消 Promise

當處于pending狀態時,無法得知目前進展到哪一個階段

錯誤不能被 try catch

生成器Generators/ yield 什么是Generator

Generator 函數是 ES6 提供的一種異步編程解決方案,語法行為與傳統函數完全不同
Generator 函數有多種理解角度。語法上,首先可以把它理解成,Generator 函數是一個狀態機,封裝了多個內部狀態。
執行 Generator 函數會返回一個遍歷器對象,也就是說,Generator 函數除了狀態機,還是一個遍歷器對象生成函數。返回的遍歷器對象,可以依次遍歷 Generator 函數內部的每一個狀態。形式上,Generator 函數是一個普通函數,但是有兩個特征。

一是,function關鍵字與函數名之間有一個星號;

二是,函數體內部使用yield表達式,定義不同的內部狀態

Generator調用方式

Generator 函數的調用方法與普通函數一樣,也是在函數名后面加上一對圓括號。不同的是,調用 Generator 函數后,該函數并不執行,返回的也不是函數運行結果,而是一個指向內部狀態的指針對象,也就是上一章介紹的遍歷器對象(Iterator Object)。
下一步,必須調用遍歷器對象的next方法,使得指針移向下一個狀態。也就是說,每次調用next方法,內部指針就從函數頭部或上一次停下來的地方開始執行,直到遇到下一個yield表達式(或return語句)為止。換言之,Generator 函數是分段執行的,yield表達式是暫停執行的標記,而next方法可以恢復執行。

function* foo () {  
  var index = 0;
  while (index < 2) {
    yield index++; //暫停函數執行,并執行yield后的操作
  }
}
var bar =  foo(); // 返回的其實是一個迭代器

console.log(bar.next());    // { value: 0, done: false }  
console.log(bar.next());    // { value: 1, done: false }  
console.log(bar.next());    // { value: undefined, done: true }  
了解Co

可以看到上個例子當中我們需要一步一步去調用next這樣也會很麻煩,這時我們可以引入co來幫我們控制
Co是一個為Node.js和瀏覽器打造的基于生成器的流程控制工具,借助于Promise,你可以使用更加優雅的方式編寫非阻塞代碼。
Co 函數庫約定,yield 命令后面只能是 Thunk 函數或 Promise 對象,而 async 函數的 await 命令后面,可以跟 Promise 對象和原始類型的值(數值、字符串和布爾值,但這時等同于同步操作)。
說白了就是幫你自動執行你的Generator不用手動調用next

解決異步問題

我們可以通過 Generator 函數解決回調地獄的問題,可以把之前的回調地獄例子改寫為如下代碼:

const co = require("co");
co(
function* read() {
    yield readFile(A, "utf-8");
    yield readFile(B, "utf-8");
    yield readFile(C, "utf-8");
    //....
}
).then(data => {
    //code
}).catch(err => {
    //code
});
function *fetch() {
    yield ajax(url, () => {})
    yield ajax(url1, () => {})
    yield ajax(url2, () => {})
}
let it = fetch()
let result1 = it.next()
let result2 = it.next()
let result3 = it.next()
終極解決方案Async/ await
async 函數是Generator 函數的語法糖,是對Generator做了進一步的封裝。
Async特點

當調用一個 async 函數時,會返回一個 Promise 對象。

    async function async1() {
      return "1"
    }
    console.log(async1()) // -> Promise {: "1"}

當這個 async 函數返回一個值時,Promise 的 resolve 方法會負責傳遞這個值;

當 async 函數拋出異常時,Promise 的 reject 方法也會傳遞這個異常值。

async 函數中可能會有 await 表達式,這會使 async 函數暫停執行,等待 Promise 的結果出來,然后恢復async函數的執行并返回解析(resolved)。

內置執行器。 Generator 函數的執行必須靠執行器,所以才有了 co 函數庫,而 async 函數自帶執行器。也就是說,async 函數的執行,與普通函數一模一樣,只要一行。

更廣的適用性。co 模塊約定,yield 命令后面只能是 Thunk 函數或 Promise對象。而 async 函數的 await 命令后面則可以是 Promise 或者 原始類型的值(Number,string,boolean,但這時等同于同步操作)

await特點

await 操作符用于等待一個Promise 對象。它只能在異步函數 async function 中使用。

[return_value] = await expression;

await 表達式會暫停當前 async function 的執行,等待 Promise 處理完成。若 Promise 正常處理(fulfilled),其回調的resolve函數參數作為 await 表達式的值,繼續執行 async function。

若 Promise 處理異常(rejected),await 表達式會把 Promise 的異常原因拋出。

另外,如果 await 操作符后的表達式的值不是一個 Promise,則返回該值本身。

重點:遇到 await 表達式時,會讓 async 函數 暫停執行,等到 await 后面的語句(Promise)狀態發生改變(resolved或者rejected)之后,再恢復 async 函數的執行(再之后 await 下面的語句),并返回解析值(Promise的值)

為什么await可以暫停執行并等到Promise的狀態改變再恢復執行呢

promise就是做這件事的 , 它會自動等到Promise決議以后的返回值,resolve(...)或者reject(...)都可以。
async內部會在promise.then(callback),回調函數里調用 next()... (還有用Thunk的, 也是為了做這個事的);

Async執行方式

簡單說 , async/awit 就是對上面gennerator自動化流程的封裝 , 讓每一個異步任務都是自動化的執行 , 當第一個異步任務readFile(A)執行完如上一點說明的, async內部自己執行next(),調用第二個任務readFile(B);

這里引入ES6阮一峰老師的例子
const fs = require("fs");

const readFile = function (fileName) {
  return new Promise(function (resolve, reject) {
    fs.readFile(fileName, function(error, data) {
      if (error) return reject(error);
      resolve(data);
    });
  });
};


async function read() {
    await readFile(A);//執行到這里停止往下執行,等待readFile內部resolve(data)后,再往下執行
    await readFile(B);
    await readFile(C);
    //code
}

//這里可用于捕獲錯誤
read().then((data) => {
    //code
}).catch(err => {
    //code
});
參考文章

http://es6.ruanyifeng.com/

https://juejin.im/post/5aa786...

https://juejin.im/post/5b83cb...

https://juejin.im/post/596e14...

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/106061.html

相關文章

  • ES6-7

    摘要:的翻譯文檔由的維護很多人說,阮老師已經有一本關于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。 JavaScript Promise 迷你書(中文版) 超詳細介紹promise的gitbook,看完再不會promise...... 本書的目的是以目前還在制定中的ECMASc...

    mudiyouyou 評論0 收藏0
  • JavaScript 異步

    摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。寫一個符合規范并可配合使用的寫一個符合規范并可配合使用的理解的工作原理采用回調函數來處理異步編程。 JavaScript怎么使用循環代替(異步)遞歸 問題描述 在開發過程中,遇到一個需求:在系統初始化時通過http獲取一個第三方服務器端的列表,第三方服務器提供了一個接口,可通過...

    tuniutech 評論0 收藏0
  • javascript知識點

    摘要:模塊化是隨著前端技術的發展,前端代碼爆炸式增長后,工程化所采取的必然措施。目前模塊化的思想分為和。特別指出,事件不等同于異步,回調也不等同于異步。將會討論安全的類型檢測惰性載入函數凍結對象定時器等話題。 Vue.js 前后端同構方案之準備篇——代碼優化 目前 Vue.js 的火爆不亞于當初的 React,本人對寫代碼有潔癖,代碼也是藝術。此篇是準備篇,工欲善其事,必先利其器。我們先在代...

    Karrdy 評論0 收藏0
  • 雙十二大前端工程師讀書清單

    摘要:本文最早為雙十一而作,原標題雙大前端工程師讀書清單,以付費的形式發布在上。發布完本次預告后,捕捉到了一個友善的吐槽讀書清單也要收費。這本書便從的異步編程講起,幫助我們設計快速響應的網絡應用,而非簡單的頁面。 本文最早為雙十一而作,原標題雙 11 大前端工程師讀書清單,以付費的形式發布在 GitChat 上。發布之后在讀者圈群聊中和讀者進行了深入的交流,現免費分享到這里,不足之處歡迎指教...

    happen 評論0 收藏0
  • 雙十二大前端工程師讀書清單

    摘要:本文最早為雙十一而作,原標題雙大前端工程師讀書清單,以付費的形式發布在上。發布完本次預告后,捕捉到了一個友善的吐槽讀書清單也要收費。這本書便從的異步編程講起,幫助我們設計快速響應的網絡應用,而非簡單的頁面。 本文最早為雙十一而作,原標題雙 11 大前端工程師讀書清單,以付費的形式發布在 GitChat 上。發布之后在讀者圈群聊中和讀者進行了深入的交流,現免費分享到這里,不足之處歡迎指教...

    余學文 評論0 收藏0

發表評論

0條評論

raise_yang

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<