javascript非同步的發展

PlayerWho發表於2018-01-18

需求:有三個api,已知第一個api的地址 "1",從第一個api裡獲取第二個api的地址,從第二個api裡獲取第三個api的地址。 用fs模組模擬請求api。

api的資料結構
{
  "msg":"This is x", //message
  "data":{
    "api":"x"        //api的地址
  }
}
複製程式碼

回撥函式

  • 傳統方式,符合傳統js程式設計
  • 可讀性差
  • 容易形成回撥地獄
let fs = require('fs');
function getApi(api, callBack) {
    fs.readFile(`./${api}.json`, "utf8", (err, data) => {
        if (err) {
            console.log(err);
        } else {
            const api = JSON.parse(data);
            callBack(api);
        }
    });
}
getApi('1',(api)=>{
    console.log(api.msg);
    getApi(api.data.api,(api)=>{
        console.log(api.msg);
        getApi(api.data.api,(api)=>{
            console.log(api.msg);
        })
    })
});
複製程式碼

事件訂閱

  • 釋出訂閱模式,每次請求訂閱事件,得到資料後,釋出事件
  • 如果請求api很多,要訂閱很多事件
  • 程式碼冗餘,不方便維護
let fs = require('fs');
function getApi(api, callBack) {
    fs.readFile(`./${api}.json`, "utf8", (err, data) => {
        if (err) {
            console.log(err);
        } else {
            const api = JSON.parse(data);
            callBack(api);
        }
    });
}
function Event() {
    this.event = {};
}
Event.prototype.on = function (type,callBack) {
    if(this.event[type]){
        this.event[type].push(callBack);
    }else{
        this.event[type] = [callBack];
    }
};
Event.prototype.emit = function (type,...data) {
    this.event[type].forEach((item)=>item(...data));
};
let event = new Event();
event.on('api1',function () {
    getApi(1, function (api) {
        console.log(api.msg);
        event.emit('api2',api.data.api);
    });
});
event.on('api2',function (api) {
    getApi(api, function (api) {
        console.log(api.msg);
        event.emit('api3',api.data.api);
    });
});
event.on('api3',function (api) {
    getApi(api, function (api) {
        console.log(api.msg);
    });
});
event.emit('api1');
複製程式碼

Promise

  • 鏈式呼叫,程式碼易讀
let fs = require('fs');
//Promise
function getApi(api) {
    return new Promise(function (resolve,reject) {
        fs.readFile(`./${api}.json`, "utf8", (err, data) => {
            if (err) {
                reject(err);
            } else {
                const api = JSON.parse(data);
                resolve(api);
            }
        });
    });
}
getApi(1).then(function (data) {
   console.log(data.msg);
   return getApi(data.data.api);
}).then(function (data) {
    console.log(data.msg);
    return getApi(data.data.api);
}).then(function (data) {
    console.log(data.msg);
});
複製程式碼

Generator

  • 執行next(),返回物件,key分別是value,done。value是yield 語句後面的內容,done表示是否還有next可以執行
  • 以 let api2 = yield getApi(api1) 為例api2是next傳入的引數。
  • 個人感覺不如promise好用。。。(歡迎來噴,交流學習)
let fs = require('fs');
//generator
function getApi(api) {
    return new Promise(function (resolve,reject) {
        fs.readFile(`./${api}.json`, "utf8", (err, data) => {
            if (err) {
                reject(err);
            } else {
                const api = JSON.parse(data);
                resolve(api);
            }
        });
    });
}
function* gen(api1) {
    //api1 api2 ap3 是接收使用者輸入的
    let api2 = yield getApi(api1);
    let api3 = yield getApi(api2);
    yield getApi(api3);
}
let g = gen(1);
let api1 = g.next();
api1.value.then(function (data) {
    console.log(data.msg);
    return data
}).then(function (data) {
    let api2 = g.next(data.data.api).value;
    return api2;
}).then(function (data) {
    console.log(data.msg);
    let api3 = g.next(data.data.api).value;
    return api3;
}).then(function (data) {
    console.log(data.msg);
});
複製程式碼

async

  • Generator的語法糖,比Generator易讀、容易理解
  • 程式碼同步寫,同步執行
let fs = require('fs');
// async await
function getApi(api) {
    return new Promise(function (resolve, reject) {
        fs.readFile(`./${api}.json`, "utf8", (err, data) => {
            if (err) {
                reject(err);
            } else {
                const api = JSON.parse(data);
                resolve(api);
            }
        });
    });
}
async function executor(api) {
    let api1, api2, api3;
    await getApi(api).then(function (data) {
        api1 = data;
        console.log(api1.msg);
    });
    await getApi(api1.data.api).then(function (data) {
        console.log(data.msg);
        api2 = data;
    });
    await (function () {
        if (api2.data) {
            getApi(api2.data.api).then(function (data) {
                console.log(data.msg);
            });
        }
    })();
}
executor(1);
複製程式碼

小結

小結不是小姐。個人理解,async是趨勢,Promise比Generator好用。媽媽再也不會擔心回撥地獄啦

原始碼

相關文章