成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【JS基礎】從JavaScript中的for...of說起(下) - async和await

hufeng / 1240人閱讀

摘要:基礎從中的說起上和在異步操作中使用和是一件比較費勁的事情,而給我們提供了更為簡便的和。表達式會暫停當前的執(zhí)行,等待處理完成。若正常處理,其回調(diào)的函數(shù)參數(shù)作為表達式的值,繼續(xù)執(zhí)行。若處理異常,表達式會把的異常原因拋出。

寫在前面
本文首發(fā)于公眾號:【符合預期的CoyPan】

在上一篇文章中,梳理了javascript中的兩個重要概念:iterator和generator,并且介紹了兩者在異步操作中的應用。

【JS基礎】從JavaScript中的for...of說起(上) - iterator 和 generator

在異步操作中使用iterator和generator是一件比較費勁的事情,而ES2017給我們提供了更為簡便的async和await。

async和await async

mdn上說:async function 聲明用于定義一個返回 AsyncFunction 對象的異步函數(shù)。異步函數(shù)是指通過事件循環(huán)異步執(zhí)行的函數(shù),它會通過一個隱式的 Promise 返回其結果。

簡單來說,如果你在一個函數(shù)前面使用了async關鍵字,那么這個函數(shù)就會返回一個promise。如果你返回的不是一個promise,JavaScript也會自動把這個值"包裝"成Promise的resolve值。例如:

// 返回一個promise
async function aa() {
    return new Promise(resolve => {
        setTimeout(function(){
            resolve("aaaaaa");
        }, 1000);
    });
}

aa().then(res => {
    console.log(res); // 1s后輸出 "aaaaaa"
});

typeof aa === "function"; // true
Object.prototype.toString(aa) === "[object AsyncFunction]"; // true
Object.prototype.toString(aa()) === "[object Promise]"; // true



// 返回一個非promise
async function a() {
    return 1;
}
const b = a(); 
console.log(b); // Promise?{: 1}

a().then(res => {
    console.log(res); // 1
})

async 函數(shù)拋出異常時,Promise 的 reject 方法也會傳遞這個異常值。例如下面的例子:

async function a(){
    return bbb;
}

a()
.then(res => {
    console.log(res);
})
.catch( e => {
    console.log(e); // ReferenceError: bbb is not defined
});
await

await 操作符用于等待一個Promise 對象。它只能在異步函數(shù) async function 中使用。await 表達式會暫停當前 async function 的執(zhí)行,等待 Promise 處理完成。若 Promise 正常處理(fulfilled),其回調(diào)的resolve函數(shù)參數(shù)作為 await 表達式的值,繼續(xù)執(zhí)行 async function。若 Promise 處理異常(rejected),await 表達式會把 Promise 的異常原因拋出。另外,如果 await 操作符后的表達式的值不是一個 Promise,則返回該值本身??聪旅娴睦樱?/p>

const p = function() {
    return new Promise(resolve => {
        setTimeout(function(){
            resolve(1);
        }, 1000);
    });
};

const fn = async function() {
    const res = await p();
    console.log(res); 
    const res2 = await 2;
    console.log(res2);
};

fn(); // 1s后,會輸出1, 緊接著,會輸出2


// 把await放在try catch中捕獲錯誤
const p2 = function() {
    return new Promise(resolve => {
        console.log(ppp);
        resolve();
    });
};

const fn2 = async function() {
    try {
        await p2();
    } catch (e) {
        console.log(e); // ppp is not defined
    }
};

fn2();

當代碼執(zhí)行到await語句時,會暫停執(zhí)行,直到await后面的promise正常處理。這和我們之前講到的generator一樣,可以讓代碼在某個地方中斷。只不過,在generator中,我們需要手動寫代碼去執(zhí)行generator,而await則是像一個自帶執(zhí)行器的generator。某種程度上,我們可以理解為:await就是generator的語法糖??聪旅娴拇a:

const p = function() {
    return new Promise(resolve, reject=>{
        setTimeout(function(){
            resolve(1);
        }, 1000);
    });
};

const f = async function() {
    const res = await p();
    console.log(res);
}

我們使用babel對這段代碼進行轉(zhuǎn)化,得到以下的代碼:

function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }

var p = function p() {
    return new Promise(resolve, function (reject) {
        setTimeout(function () {
            resolve(1);
        }, 1000);
    });
};

var f = function () {
    var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
        var res;
        return regeneratorRuntime.wrap(function _callee$(_context) {
            while (1) {
                switch (_context.prev = _context.next) {
                    case 0:
                        _context.next = 2;
                        return p();

                    case 2:
                        res = _context.sent;

                        console.log(res);

                    case 4:
                    case "end":
                        return _context.stop();
                }
            }
        }, _callee, this);
    }));

    return function f() {
        return _ref.apply(this, arguments);
    };
}();

通過變量名可以看到,babel也是將async await轉(zhuǎn)換成了generator來進行處理的。

任務隊列

以下的場景其實是很常見的:

我們有一堆任務,我們需要按照一定的順序執(zhí)行這一堆任務,拿到最終的結果。這里,把這一堆任務稱為一個任務隊列。

js中的隊列其實就是一個數(shù)組。

同步任務隊列

任務隊列中的函數(shù)都是同步函數(shù)。這種情況比較簡單,我們可以采用reduce很方便的遍歷。

const fn1 = function(i) {
    return i + 1;
};
const fn2 = function(i) {
    return i * 2;
};
const fn3 = function(i) {
    return i * 100;
};
const taskList = [fn1, fn2, fn3];
let a = 1;
const res = taskList.reduce((sum, fn) => {
    sum = fn(sum);
    return sum;
}, a); 

console.log(res); // 400
異步任務隊列

任務隊列中的函數(shù)都是異步函數(shù)。這里,我們假設所有的函數(shù)都是以Promise的形式封裝的。現(xiàn)在,需要依次執(zhí)行隊列中的函數(shù)。假設異步任務隊列如下:

const fn1 = function() {
    return new Promise( resolve => {
        setTimeout(function(){
            console.log("fn1");
            resolve();
        }, 2000);
    });
};
const fn2 = function() {
    return new Promise( resolve => {
        setTimeout(function(){
            console.log("fn2");
            resolve();
        }, 1000);
    });
};
const fn3 = function() {
    console.log("fn3");
    return Promise.resolve(1);
};
const taskList = [fn1, fn2, fn3];

可以使用正常的for循環(huán)或者for...of... 來遍歷數(shù)組,并且使用async await來執(zhí)行代碼(注:不要使用forEach,forEach不支持這種場景)

// for循環(huán)
(async function(){
    for(let i = 0; i < taskList.length; i++) {
        await taskList[i]();
    }
})();

// for..of..
(async function(){
    for(let fn of taskList) {
        await fn();
    }
})();
koa2洋蔥模型實現(xiàn)原理

koa2,大家都不陌生了。koa2的洋蔥模型,是怎么實現(xiàn)的呢?先來看下面的代碼:

const Koa = require("koa");
const app = new Koa();

// logger

app.use(async (ctx, next) => {
  console.log(1);
  await next();
  console.log(2);
  const rt = ctx.response.get("X-Response-Time");
  console.log(`${ctx.method} ${ctx.url} - ${rt}`);
});

// x-response-time

app.use(async (ctx, next) => {
  console.log(3);
  const start = Date.now();
  await next();
  console.log(4);
  const ms = Date.now() - start;
  ctx.set("X-Response-Time", `${ms}ms`);
});

// response

app.use(async ctx => {
  console.log(5);
  ctx.body = "Hello World";
});

app.listen(3000);

// 訪問node時,代碼輸出如下:
// 1
// 3
// 5 
// 4 
// 2
// GET / - 6ms

其實實現(xiàn)起來很簡單,app.use就是將所有的回調(diào)函數(shù)都塞進了一個任務隊列里面,調(diào)用await next()的時候,會直接執(zhí)行隊列里面下一個任務,直到下一個任務執(zhí)行完成,才會接著執(zhí)行后續(xù)的代碼。我們來簡單實現(xiàn)一下最基本的邏輯:

class TaskList {
    constructor(){
        this.list = [];
    }
    use(fn) {
        fn && this.list.push(fn);
    }
    start() {
        const self = this;
        let idx = -1;
        const exec = function() {
            idx++;
            const fn = self.list[idx];
            if(!fn) {
                return Promise.resolve();
            }
            return Promise.resolve(fn(exec))
        }
        exec();
    }
} 

const test1 = function() {
    return new Promise( resolve => {
        setTimeout(function(){
            console.log("fn1");
            resolve();
        }, 2000);
    });
};

const taskList = new TaskList();

taskList.use(async next => {
    console.log(1);
    await next();
    console.log(2);
});
taskList.use(async next => {
    console.log(3);
    await test1();
    await next();
    console.log(4);
});
taskList.use(async next => {
    console.log(5);
    await next();
    console.log(6);
});
taskList.use(async next => {
    console.log(7);
});
taskList.start();

// 輸出: 1、3、fn1、5、7、6、4、2
寫在后面

可以看到,使用async和await進行異步操作,可以使代碼看起來更為清晰,簡單。我們可以用同步代碼的方式來書寫異步代碼。本文還探究了前端開發(fā)中很常見的任務隊列的相關問題。通過本文和上一篇文章,我自己也對js中的異步操作有了更深入,更全面的認識。符合預期。

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/103557.html

相關文章

  • JS基礎JavaScript中的for...of說起(上) - iterator gene

    摘要:當這個迭代器的方法被首次后續(xù)調(diào)用時,其內(nèi)的語句會執(zhí)行到第一個后續(xù)出現(xiàn)的位置為止,后緊跟迭代器要返回的值。在這個回調(diào)函數(shù)里,我們使用第一個請求返回的,再次發(fā)起一個請求。 寫在前面 本文首發(fā)于公眾號:符合預期的CoyPan 后續(xù)文章:【JS基礎】從JavaScript中的for...of說起(下) - async和await 先來看一段很常見的代碼: const arr = [1, 2, ...

    wslongchen 評論0 收藏0
  • JavaScript 的 4 種數(shù)組遍歷方法: for VS forEach() VS for/in

    摘要:對于,除非使用箭頭函數(shù),它的回調(diào)函數(shù)的將會變化。使用測試下面的代碼,結果如下打印打印要點使用的規(guī)則要求所有回調(diào)函數(shù)必須使用箭頭函數(shù)。 譯者按: JS 騷操作。 原文:For vs forEach() vs for/in vs for/of in JavaScript 譯者: Fundebug 本文采用意譯,版權歸原作者所有 我們有多種方法來遍歷 JavaScript 的數(shù)組或者...

    joyqi 評論0 收藏0
  • JavaScript異步編程:Generator與Async

    摘要:從開始,就在引入新功能,來幫助更簡單的方法來處理異步編程,幫助我們遠離回調(diào)地獄。而則是為了更簡潔的使用而提出的語法,相比這種的實現(xiàn)方式,更為專注,生來就是為了處理異步編程。 從Promise開始,JavaScript就在引入新功能,來幫助更簡單的方法來處理異步編程,幫助我們遠離回調(diào)地獄。 Promise是下邊要講的Generator/yield與async/await的基礎,希望你已...

    leon 評論0 收藏0
  • ES2018 新特征之:異步迭代器 for-await-of

    摘要:不幸的是,迭代器不能用來表示這樣的數(shù)據(jù)源。即使是的迭代器也是不夠的,因為它的是異步的,但是迭代器需要同步確定狀態(tài)。異步迭代器一個異步迭代器就像一個迭代器,除了它的方法返回一個的。 ES2018 新特性 異步迭代器(本文) 正則表達式反向(lookbehind)斷言 正則表達式 Unicode 轉(zhuǎn)義 非轉(zhuǎn)義序列的模板字符串 正則表達式 s/dotAll 模式 正則表達式命名捕獲組 對...

    klivitamJ 評論0 收藏0
  • JavaScript基礎——深入學習async/await

    摘要:等待的基本語法該關鍵字的的意思就是讓編譯器等待并返回結果。這里并不會占用資源,因為引擎可以同時執(zhí)行其他任務其他腳本或處理事件。接下來,我們寫一個火箭發(fā)射場景的小例子不是真的發(fā)射火箭 本文由云+社區(qū)發(fā)表 本篇文章,小編將和大家一起學習異步編程的未來——async/await,它會打破你對上篇文章Promise的認知,竟然異步代碼還能這么寫! 但是別太得意,你需要深入理解Promise后,...

    張金寶 評論0 收藏0

發(fā)表評論

0條評論

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