【js】js 异步机制详解 Generator / Async / Promise

这篇具有很好参考价值的文章主要介绍了【js】js 异步机制详解 Generator / Async / Promise。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

三种语法功能放在一起,是因为他们都有相似特点:

  • 维护某种状态
  • 在未来恢复状态并执行

本文重点回答以下几个问题:

  • 为什么 Generator 和 Async 函数的 代码执行流 都可以简化成树形结构?
  • async 函数为什么返回一个 promise?返回了怎样一个 promise?
  • async 函数如何优雅的转换成 promise 函数?
    Generator 用法和思考

基本生成器

generator 是生成器,从生成器的行为来看,它就是一个迭代器。

function* foo(end) {
    var idx = 0;
    while (idx < end) {
        yield idx; // 保存当前状态并返回 当前idx
        idx += 5;
    }
}


const iterator = foo(20);
// iterator.next().value 手动迭代
for (let val of iterator) { // 输出 0 到 19
    console.log(val);
}

对应到生成器函数中,他会在 yield 的时候保存当前函数的状态。那么,函数的状态保存在哪? 习惯了 C 函数的我们很难想象如何将状态保存在函数中。可能协程和 setjmp/longjmp 可以辅助我们思考生成器的实现,但还是不能直接对应到生成器函数的行为。比如:生成器需要记录如下信息

  • Idx 的大小, end 大小
  • pc 指针在 第 5 行

想在 c 语言中保存上述信息是不容易的。是因为函数在 js 是第一类值,上述的信息便可以保存在函数值本身内。对应quickjs 相当于将 pc 指针 和 参数 信息,local_buf,保存在对应的函数对象 (实际上保存在 StackFrame 中) 内,而 cur_ref 信息 quickjs 本身就已经保存了。而 c/c++ 语言的函数没有类似功能。

嵌套多层迭代器

  • 树形生成器结构。讲 yield 这种语法,是因为它跟 async 的执行流非常像,但会可以看到
  • 使用树形生成器生成 0 ~ 20 的值
    【js】js 异步机制详解 Generator / Async / Promise,javascript,前端,开发语言
function* inner(index) {
  var i = 0;
  while (i < 5) {
      yield index + i;
      i++;
  }
}

// 错误的生成器用法,但是启发我们思考,这样的用法,是不是很像 await?
// function* foo(index) {
//   while (index < 20) {
//     yield inner(index);
//     index += 5;
//   }
// }

// 正确版本
function* foo1(index) {
    while (index < 20) {
        var it = inner(index);
        for (let val of it) {
            yield val;
        }
        index += 5;
    }
}

// 语法糖版本
function* foo2(index) {
   while (index < 20) {
     yield *inner(index);
     index += 5;
   }
}


const iterator = foo1(0);

for (let val of iterator) {
    console.log(val);
}

async 执行流的思考

  • Async 的代码执行流程是下面这棵树的中序遍历

  • Async 函数的代码执行流程如下

    • 先执行绿色部分代码,直到最底层的 promise,由于promise 测试未决定(pending 状态),整个函数暂停退出。
    • promise resolve或reject 后,恢复中序遍历执行淡蓝色部分代码,直到下一个 promise。这里相当于执行了 promise 的 then 回调。
      • Plus. 这里仍然有一次 暂停执行。因为 新的 promise 是 pending 状态。
    • 新的 promise resolve或reject 后,继续恢复执行 。。。。
    • Async 函数的结尾的 return 道理上相当于一个 then 回调
  • Async 函数的代码执行流程非常像 树形 generator

  • 都说 async 函数返回一个 promise,它返回的 promise 到底是什么?
    【js】js 异步机制详解 Generator / Async / Promise,javascript,前端,开发语言

  • Async 函数框架

async function asyncfunc() {
    code1;
    var a1 = await asyncfunc1(); // 这里是一个 async 函数
    code2;
    var a2 = await promise1; // 这里是一个 真正的 Promise
    code3;
    var a3 = await asyncfunc2(); // 这里是一个 async 函数
    codeR;
    return x;
}

asyncfunc();
  • 可以尝试使用如下代码,单步调试来验证
async function wrapFetch(url) {
    console.log("wrapFetch code1");
    const response = await fetch(url);
    console.log("wrapFetch code2");
    return response;
}

// 异步函数示例
async function fetchAsyncData() {
    console.log("fetchAsyncData code1");
    const response = await wrapFetch('https://qqlykm.cn/api/weather/get');
    console.log("fetchAsyncData code2 ok?", response.ok);
    const data = await response.json();
    console.log(data);
}
 
// 调用异步函数
console.log("before async");
fetchAsyncData();
console.log("after async");
  • 问题:能把 async 函数串行化么?答案是不能。只要使用了 promise (叶子节点是真正的 promise),代码的执行就要遵循 promise 的执行规则,而 promise 本身就是异步的,因此无法串行化。

一点点 Promise 的思考

想要理解如何将 async 函数返回的到底是什么 promise?以及如何将 async 函数翻译成一个 promise 的形式,需要深入理解 then 函数。

Then 函数
  • Then 函数返回一个 promise,称其为 p。
  • Then 注册的回调函数中也会返回一个值。那么 返回 一个值 和 返回一个 promise 有什么不同?
  • 如果回调函数返回了 promise,那么这个promise 和 then 返回的 promise p 是 什么关系?官方文档:链式调用。
    • 结论:他俩在行为上是 同一个 promise
    • 知道这一点,就可以轻松的把一个 async 函数改写成 promise 的形式了。
const myPromise = new Promise((resolve, reject) => {
    // 进行异步操作
        const randomNumber = Math.random();
        // 如果操作成功,调用resolve并传递结果
        resolve(randomNumber);
});
 
// 使用Promise对象
myPromise.then(result => {
        // 操作成功时的处理逻辑
        console.log("操作成功,结果为:" + result);
        **return 1; **
        **return new Promise((rs, rj) => rs(2));**
    }).then( val => {
        console.log(val);
    })

将 async 改写成 promise

如何改写?下面用一个示例来展示

注:这里并没有关注异常执行流,而是只关注异步执行流。异常执行流要想完全转换,需要在promise里注册错误回调,并且 async 和 promise 都要捕获异常

// async 写法

async function asyncfunc() {
    code1;
    var a1 = await asyncfunc1();    // 这里是一个 async 函数
    code2;
    var a2 = await promise1;     // 这里是一个 真正的 Promise
    code3;
    var a3 = await asyncfunc2();    // 这里是一个 async 函数
    codeR;
    return x;
}

asyncfunc();
// 等价的promise 写法

function func() {
  return new Promise((resolve, reject) =>{
    code1;
    func1()
      .then( (val) => resolve(val) );
  }).then((a1) => {
      code2;
      return promise1;
  }).then((a2)=> {
      code3;
      // 返回一个Promise
      return func2(); 
  }).then((a3) => {
      codeR;
      return x;
  });
}
func();

结论:async 语法糖有什么好处呢?

  • 代码写起来更简洁、优雅,意味着 减少出错率
  • 词法作用域更广。写 code2 可以用 code1 部分的变量,写 promise 的时候就没办法了。

可验证代码

异步调用一个 网络 api 接口文章来源地址https://www.toymoban.com/news/detail-812926.html

  • async 版本
async function wrapFetch(url) {
    console.log("wrapFetch code1");
    const response = await fetch(url);
    console.log("wrapFetch code2");
    return response;
}

// 异步函数示例
async function fetchAsyncData() {
    console.log("fetchAsyncData code1");
    const response = await wrapFetch('https://qqlykm.cn/api/weather/get');
    console.log("fetchAsyncData code2 ok?", response.ok);
    const data = await response.json();
    console.log(data);
}
 
// 调用异步函数
console.log("before async");
fetchAsyncData();
console.log("after async");
  • 等价 Promise 版本
function wrapFetch(url) {
    return new Promise( function (resolve, reject) {
        console.log("wrapFetch code1");
        fetch(url).then( (response) => {
            resolve(response);
            console.log("wrapFetch code2");
        })
    });
}


function fetchAsyncData() {
    return new Promise(function (resolve, reject) {
        console.log("fetchAsyncData code1");
        wrapFetch('https://qqlykm.cn/api/weather/get')
            .then( val => resolve(val) )
    })
    .then( (response) => {
        console.log("fetchAsyncData code2 ok?", response.ok);
        return response.json()
    })
    .then((data) => {
        console.log(data);
    });
}

// 调用异步函数
console.log("before async");
fetchAsyncData();
console.log("after async");

到了这里,关于【js】js 异步机制详解 Generator / Async / Promise的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Promise, Generator, async/await的渐进理解

         作为前端开发者的伙伴们,肯定对Promise,Generator,async/await非常熟悉不过了。Promise绝对是烂记于心,而async/await却让使大伙们感觉到爽(原来异步可以这么简单)。可回头来梳理他们的关联时,你惊讶的发现,他们是如此的密切相关。       我对他们三者之间的关联

    2024年02月08日
    浏览(29)
  • promise及异步编程async await

    ECMAScript 6 新增了正式的 Promise(期约)引用类型,支持优雅地定义和组织异步逻辑。接下来几个版本增加了使用 async 和 await 定义异步函数的机制 JavaScript 是单线程事件循环模型。异步行为是为了优化因计算量大而时间长的操作,只要你不想为等待某个异步操作而阻塞

    2024年02月04日
    浏览(30)
  • 什么是Promise对象?它的状态有哪些?如何使用Promise处理异步操作?以及 async、await

    前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发者,这里都将为你提供一

    2024年02月11日
    浏览(32)
  • vue async await promise 等待异步接口执行完毕再进行下一步操作

    需求:上传多个文件,每上传一个文件异步请求一下后台接口,并返回一个新文件名,等把所有的异步接口执行成功后,将上传已成功后新文件名数组得到再去更新业务数据 uni-file-picker 文件上传组件的配置 选择文件后,上传到服务器后端,一个一个的传,等异步执行完一下

    2024年02月12日
    浏览(37)
  • Ajax_4(进阶)同步异步+ 宏任务微任务 + Promise链 + async终极解决方案 +事件循环原理 + 综合案例

    01-同步代码和异步代码 什么是同步代码? 同步代码:逐行执行,需要原地等待结果后,才继续向下执行。 什么是异步代码? 调用后耗时,不阻塞代码继续执行,(不必原地等待),在将来完成后 触发一个 回调函数 。 代码阅读 目标:阅读并回答代码执行和打印的顺序 打印

    2024年02月13日
    浏览(34)
  • Promise、Async/Await 详解

            Promise是抽象异步处理对象以及对其进行各种操作的组件。Promise本身是同步的立即执行函数解决异步回调的问题, 当调用 resolve 或 reject 回调函数进行处理的时候, 是异步操作, 会先执行.then/catch等,当主栈完成后,才会去调用执行resolve/reject中存放的方法。      

    2024年02月14日
    浏览(30)
  • defer 和 async:JavaScript异步编程的利器

    🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_ CSDN 博客专家、23年度博客之星前端领域TOP1 🕠 牛客 高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课 签约作者、上架课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你

    2024年03月24日
    浏览(40)
  • [javascript核心-04]彻底弄懂Promise异步编程

    本文github地址:JavaScript_Interview_Everything 大前端知识体系与面试宝典,从前端到后端,全栈工程师,成为六边形战士 1.1. 快速上手 01快手上手.js 02.若传入的是另一个promise对象,则状态由传入的promise对象决定 03.若传入了一个实现了 then 方法的对象,则执行该then方法且由此方法

    2024年02月08日
    浏览(29)
  • JavaScript 异步解决方案 Promise 全解析(转载)

    Promise 是一个 JS 的异步编程解决方案,解决了传统异步编程回调地狱的问题。 从语义上来说: Promise 是一个向外部传达异步编程操作消息的对象。 JS里一个promise可以有以下几种基本状态: nothing happened yet \\\"locked in\\\" to another promise fulfilled rejected 其中{1,2}为 pending ,{3,4}为 settl

    2024年02月08日
    浏览(44)
  • 前端异步技术之Promise

    由于是参(抄)考(袭)前辈的polyfill,自己编码测试时出现了两处错误,ES6 Promise 规范的2.3.1和2.3.4 2.3.1 你们的支持是我最大的动力,熬夜码字不易,如果此文对你有帮助,请不吝star---https://github.com/chenchangyuan/promise 有兴趣加笔者好友的同学请扫描下方二维码(1.本人微信,

    2024年02月08日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包