美文网首页JavaScript
[JavaScript] 异步循环模式

[JavaScript] 异步循环模式

作者: 何幻 | 来源:发表于2017-12-14 21:36 被阅读38次

1. 循环

要想循环执行一段代码,一般有两种方式,迭代或者递归。

(1)迭代方式

const f = () => {
    for (let i = 0; i < 10; i++) {
        console.log(i);
    }
};

(2)递归方式

const f = i => {
    if (i > 9) {
        return;
    }

    console.log(i);
    f(i + 1);
};

f(0);

以上是循环执行同步代码的常用方法。
但是要想循环执行包含异步操作的代码就不太容易了。

2. 异步

在包含异步代码时,如果使用for循环,将无法保证顺序。

const f = () => {
    for (let i = 0; i < 10; i++) {
        setTimeout(() => console.log(i), Math.random() * 1000);
    }
};

f();

以上代码由于会在随机时间后将任务加入事件队列,
所以,并不会保证顺序执行。

要想保证顺序,我们就必须手动将它们串起来,
让前面的异步代码执行完了之后,再执行后面的异步代码。

常用方法是使用递归,

const f = i => {
    if (i > 9) {
        return;
    }

    setTimeout(() => {
        console.log(i);
        f(i + 1);
    }, Math.random() * 1000);
};

f(0);

3. 递归模式

以上递归函数有一个缺点,那就是递归函数的名字不能修改,
如果只修改了递归函数的名字,而没有修改对它的递归调用,就会出错。

虽然我们可以通过Y combinator来对匿名函数进行递归运算,
但实际用起来会比较繁琐,涉及的理论知识也不容易理解。

const y = k => (g => g(g))(f => n => k(f(f))(n));
const f = y(next => i => {
    if (i > 9) {
        return;
    }

    setTimeout(() => {
        console.log(i);
        next(i + 1);
    }, Math.random() * 1000);
});

f(0);

有一个办法就是模仿Y combinator,
提取递归模式,构造一个高阶函数来完成递归,让接口更友好一些。

const recursion = (p0, fn) => fn(p0, p1 => recursion(p1, fn));

recursion(0, (i, next) => {
    if (i > 9) {
        return;
    }

    setTimeout(() => {
        console.log(i);
        next(i + 1);
    }, Math.random() * 1000);
});

其中next是一个函数,调用它会导致(i, next)=>{ }重新被调用。
这样我们就不必担心递归函数的名字问题了,
而且recursion还同样适用于包含异步代码的函数。

4. async function

ES 2017引入了async function
它返回一个promise,并且还可以在其中await一个promise。

const f = async () => {
    console.log(1);
    await new Promise(res => setTimeout(res, 1000));
    console.log(2);
};

f();

这段代码会在打印1之后等待1s,然后再打印2

(1)异步迭代

有了async function,我们就可以对异步代码进行迭代了,

const f = async () => {
    for (let i = 0; i < 10; i++) {
        await new Promise(res => setTimeout(() => {
            console.log(i);
            res();
        }, Math.random() * 1000));
    }
};

f();

(2)异步递归

同样对于异步代码,也就容易编写递归函数了。

const f = async i => {
    if (i > 9) {
        return;
    }

    await new Promise(res => setTimeout(() => {
        console.log(i);
        res();
    }, Math.random() * 1000));

    await f(i + 1);
};

f(0);

参考

ECMAScript 2017 Language Specification
MDN: async function
Y combinator

相关文章

  • [JavaScript] 异步循环模式

    1. 循环 要想循环执行一段代码,一般有两种方式,迭代或者递归。 (1)迭代方式 (2)递归方式 以上是循环执行同...

  • Javascript异步编程

    同步模式与异步模式 事件循环与消息队列   JavaScript 单线程指的是浏览器中负责解释和执行 JavaSc...

  • JavaScript之异步概述

    1,异步(什么是异步,异步出现的原因,异步解决的问题,如何实现异步,什么时候需要异步模式。) JavaScript...

  • JavaScript异步编程

    目录 JavaScript采用单线程模式工作的原因 单线程的优势和弊端 同步模式与异步模式同步模式异步模式同步模式...

  • JS异步编程(2)-异步核心Event loop

    Event loop 是 JavaScript 异步编程的核心,通过事件循环机制,让单线程的 JavaScript...

  • JavaScript 异步编程

    同步模式与异步模式 时间循环与消息队列 异步编程的几种方式 Primise异步方案 宏任务 /微任务队列 Ge...

  • JavaScript 异步模式

    Promises Promises做了点小事,就是把回调函数从传递给其他函数的参数中提取出来(之前回调函数都是作为...

  • javascript 执行上下文

    javascript 是单线程语言 javascript 是异步执行的,通过事件循环的方式进行 js引擎执行过程分...

  • JavaScript是如何工作的:事件循环和异步编程的崛起 +

    摘要: 深度理解JS事件循环!!! 原文:JavaScript是如何工作的:事件循环和异步编程的崛起+ 5种使用 ...

  • js任务管理和promise

    任务管理 JavaScript是单线程。JavaScript在处理异步操作时,利用的是事件循环机制。 主线程中的任...

网友评论

    本文标题:[JavaScript] 异步循环模式

    本文链接:https://www.haomeiwen.com/subject/vozkwxtx.html