異步的發展過程

原文: 異步的發展過程

 

發展過程

  • callback -> promise -> generator + co -> async + await(語法糖)

異步是不支持try/catch的,try/catch只在同步中使用

node支持異步

// 1.txt -> 周杰倫
// 2.txt -> 七里香
// node裏內置的fs方法
const fs = require('fs');

fs.readFile('1.txt', 'utf8', function (err, data) {
    fs.readFile(data, 'utf8', function (err, data) {
        console.log(data);
    });
});

高階函數

  • 定義: 函數可以作爲參數or函數可以作爲返回值,來實現個判斷數據類型的isType函數
function isType(type, value) {
  return Object.prototype.toString.call(value) === `[object ${type}]`;
}
console.log(isType('String', 'hello'));  // true
console.log(isType('Array', ['hi', 1, 2]));  // true
console.log(isType('Function', function (){});  // true

上面的isType函數雖然可以實現數據類型的判斷,但是每次都要傳遞多餘的參數

這樣寫起來很麻煩,其實下面還有更好的方法來減少參數

改良後的isType如下:

// 批量生產函數
function isType(type) {  // 偏函數  先預置進去
    return function(value) {
        return Object.prototype.toString.call(value) === `[object ${type}]`;
    }
}

const isArray = isType('Array');    // 判斷數組
const isString = isType('String');  // 判斷字符串
console.log(isArray([222]));         // true

像批量生產函數的這種實現,還有一種就是預置函數,預置函數的實現原理很簡單,當達到條件時再執行回調函數,像lodash裏的after方法一樣

function after(time, cb) {
    return function() {
        if (--time === 0) {
            cb();
        }
    }
}
// 舉個栗子吧,吃飯的時候,我很能吃,吃了三碗才能吃飽
let eat = after(3, function() {
    console.log('吃飽了');
});
eat();
eat();
eat();
// 只有執行三次吃的函數纔會觸發‘吃飽了’

前面說了好多別的,有點跑題了,繼續回來說異步的事

我現在還是有兩個文件,我要用fs去讀取,然後異步的問題就來了,我怎麼知道哪個先讀完,哪個後讀完。

好吧,其實我也不關心,我關心的是我要怎麼拿到這兩個文件裏的數據

說下我的思路吧:

一開始想直接放個數組來存取每次讀到的數據,但這個放在同步情況下沒問題 異步就不行了

我畢竟不知道哪個先讀取完,這個過程是無法判斷的

於是乎想到了個最簡單的方法,得利用函數了,把數據當做參數傳過去

// 寫一個輸出數據的函數
let arr = [];
function out(data) {
    arr.push(data);
    if (arr.length === 2) {
        console.log(arr);    // ['周杰倫', '七里香']
    }
}

fs.readFile('1.txt', 'utf8', function(err, data)  {
    out(data);
});
fs.readFile('2.txt', 'utf8', function(err, data)  {
    out(data);
});

以上代碼確實實現了把讀取的數據都拿到了

But還是有些小缺陷,out裏面的數字2是寫死的

如果又多了一個文件讀取,那就得改成3了,這很不夠酷

那麼,怎樣改比較好呢,還記得上面實現的after函數吧

現在來看看它的用處吧

// 用after函數去改造一下out函數
let out = after(2, function(arr) {
    console.log(arr);
});

function after(time, cb) {
    // result被引用了,形成了閉包,不會被回收掉
    let result = [];
    return function(data) {
        result.push(data);
        if (--time === 0) {
            cb(result);      // 可以緩存函數,當到達條件時執行
        }
    }
}

fs.readFile('1.txt', 'utf8', function(err, data)  { out(data); });
fs.readFile('2.txt', 'utf8', function(err, data)  { out(data); });

雖然after方法已經很好了,但是我們不能每次處理異步請求的時候,都手寫一遍after函數,這不科學,不合理

因此我們用上了promise

promise

從實際開發中,promise解決了回調地獄的問題,不會導致難以維護

then可以按照順序執行

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章