上一主题 下一主题
ScriptCat,新一代的脚本管理器脚本站,与全世界分享你的用户脚本油猴脚本开发指南教程目录
12下一页
返回列表 发新帖

[油猴脚本开发指南]包装异步代码为同步代码

[复制链接]
  • TA的每日心情
    开心
    2023-2-28 23:59
  • 签到天数: 191 天

    [LV.7]常住居民III

    633

    主题

    5172

    回帖

    6051

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6051

    荣誉开发者管理员油中2周年生态建设者喜迎中秋

    发表于 2021-8-23 01:29:27 | 显示全部楼层 | 阅读模式

    前言

    这节课我们学习如何将一段异步代码包装成同步代码

    异步代码

    function GetMess(){
            GM_xmlhttpRequest({
            url:"https://bbs.tampermonkey.net.cn/",
            method :"GET",
            headers: {
            },
            onload:function(xhr){
                console.log(xhr.responseText);
            }
        });
    }
    GetMess()

    这是一段十分简单的代码,在函数内使用了一个get获取网页内容,如果我们想在获取内容之后进行一些处理需要写在onload函数内,这种代码就叫做异步代码,当执行完请求后再回调处理的函数,有时候这样非常麻烦,那有没有什么办法改为同步代码呢?解决方案就是使用Promise

        let p=new Promise((resolve, reject) => {
    
        })

    我们首先创建一个Promise,当Promise不调用resolve和reject结束状态,那将一直是pengding状态,只有调用resolve或reject的时候,才可以结束状态并返回resolve或reject函数内的值

    function GetMess(){
        let p=new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                url:"https://bbs.tampermonkey.net.cn/",
                method :"GET",
                headers: {
                },
                onload:function(xhr){
                    resolve(xhr.responseText)
    
                }
            });
        })
    }
    GetMess()

    现在我们要求在onload后使用resolve结束这个Promise状态,并返回xhr.responseText的值

    我们再结合async和await的语法糖就可以了

    await需要一个Promise,所以我们需要将我们构建的这个Promise返回

    function GetMess(){
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                url:"https://bbs.tampermonkey.net.cn/",
                method :"GET",
                headers: {
                },
                onload:function(xhr){
                    resolve(xhr.responseText)
    
                }
            });
        })
    }
    async function GetPromiseAndWait(){
       let text=await GetMess()
    }
    GetPromiseAndWait()

    添加await GetMess()后,GetMess函数会返回一个Promise,Async和Await语法糖会使Promise阻塞直至完成状态后,将resolve内填入的值赋值给text变量上。

    需要注意的是我们不可以在全局作用域内使用await,目前并未实现该特性,只有在async的函数内才可以使用await。

    由于GetPromiseAndWait使用了Async语法糖,所以调用他现在也会返回一个Promise变量,如果我们想要同步获取他返回的值,也需要使用Async与Await

    function GetMess(){
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                url:"https://bbs.tampermonkey.net.cn/",
                method :"GET",
                headers: {
                },
                onload:function(xhr){
                    resolve(xhr.responseText)
    
                }
            });
        })
    }
    async function GetPromiseAndWait(){
       let text=await GetMess()
       return '我处理完了'
    }
    function WantGetFinallyText(){
        let data=GetPromiseAndWait()
        console.log('WantGetFinallyText',data)
    }
    
    WantGetFinallyText()

    图片.png

    我们可以看到console.log输出了一个promise,这个值是pengding,因为我们调用了GetPromiseAndWait,他在没有执行到return的时候是一个执行中的状态。

    如果我们想要获取到GetPromiseAndWait的值,需要让这个函数执行到return,也就是fulfilled状态。这个时候我们需要对调用这个函数返回的Promise再进行一个Async和Await,来让这个Promise形成阻塞

    function GetMess(){
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                url:"https://bbs.tampermonkey.net.cn/",
                method :"GET",
                headers: {
                },
                onload:function(xhr){
                    resolve(xhr.responseText)
    
                }
            });
        })
    }
    async function GetPromiseAndWait(){
       let text=await GetMess()
       return '我处理完了'
    }
    async function WantGetFinallyText(){
        let data=await GetPromiseAndWait()
        console.log('WantGetFinallyText',data)
    }
    
    WantGetFinallyText()

    图片.png

    这个时候await就会阻塞住GetPromiseAndWait一直到履行状态再将其值赋值给data,因为return会使函数变为履行状态,也就是说await会使函数一直阻塞到return返回内容为止。

    注意,还有一个知识点

    就是GetPromiseAndWait如果return一个Promise,那这个函数返回的将是这个Promise,await阻塞的也是这个Promise的值。

    这个概念我们之前也讲过,当async函数return一个值时,会将其包装成一个Promise,当返回一个Promise时,将直接返回这个Promise

    那么到这里,你就学会了Promise以及多层Async函数的同步!

    结语

    撒花~

    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
  • TA的每日心情
    开心
    9 小时前
  • 签到天数: 169 天

    [LV.7]常住居民III

    11

    主题

    198

    回帖

    239

    积分

    高级工程师

    积分
    239

    油中2周年

    发表于 2021-8-23 07:43:34 | 显示全部楼层
    赶上热乎的了 趁机占个楼
    回复

    使用道具 举报

  • TA的每日心情
    开心
    昨天 18:22
  • 签到天数: 703 天

    [LV.9]以坛为家II

    27

    主题

    733

    回帖

    7212

    积分

    荣誉开发者

    精通各种语言的HelloWord!

    积分
    7212

    荣誉开发者油中2周年生态建设者油中3周年挑战者 lv2

    发表于 2021-8-23 08:10:05 | 显示全部楼层
    太好了
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    昨天 08:49
  • 签到天数: 426 天

    [LV.9]以坛为家II

    148

    主题

    423

    回帖

    1141

    积分

    版主

    积分
    1141

    油中2周年生态建设者

    发表于 2021-8-23 10:14:22 | 显示全部楼层
    哥哥最近有点高产啊
    I don't hate programming but the fucking world.
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2023-2-28 23:59
  • 签到天数: 191 天

    [LV.7]常住居民III

    633

    主题

    5172

    回帖

    6051

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6051

    荣誉开发者管理员油中2周年生态建设者喜迎中秋

    发表于 2021-8-23 10:37:45 | 显示全部楼层
    syy 发表于 2021-8-23 07:43
    赶上热乎的了 趁机占个楼

    谢谢哥哥
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2023-2-28 23:59
  • 签到天数: 191 天

    [LV.7]常住居民III

    633

    主题

    5172

    回帖

    6051

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6051

    荣誉开发者管理员油中2周年生态建设者喜迎中秋

    发表于 2021-8-23 10:37:50 | 显示全部楼层

    谢谢哥哥
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2023-2-28 23:59
  • 签到天数: 191 天

    [LV.7]常住居民III

    633

    主题

    5172

    回帖

    6051

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6051

    荣誉开发者管理员油中2周年生态建设者喜迎中秋

    发表于 2021-8-23 10:38:02 | 显示全部楼层
    小陈 发表于 2021-8-23 10:14
    哥哥最近有点高产啊

    闲着没事想先写几篇,哥哥要不要也写点玩玩
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    2024-1-20 09:03
  • 签到天数: 14 天

    [LV.3]偶尔看看II

    1

    主题

    5

    回帖

    12

    积分

    助理工程师

    积分
    12
    发表于 2022-10-19 16:06:14 | 显示全部楼层
    写的很好,受益良多
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2022-11-20 21:52
  • 签到天数: 1 天

    [LV.1]初来乍到

    2

    主题

    4

    回帖

    11

    积分

    助理工程师

    积分
    11
    发表于 2022-11-30 23:53:12 | 显示全部楼层
    本帖最后由 jinyu2 于 2022-12-1 00:13 编辑

    补充一点,如果请求返回404等错误,可以这么写
    1. // GM_http
    2. onload:function(xhr){
    3.                 if (xhr.status == 200) {
    4.                     resolve(xhr.responseText);
    5.                 }else {reject(xhr.status);}
    6.             },
    7. //省略不必要的代码
    8. try {
    9.         var text = await GetMess();
    10.         //这里是返回reslve的值
    11.     } catch (err) {
    12.         //返回reject
    13.       console.log('我发生了错误',err)
    复制代码


    回复

    使用道具 举报

  • TA的每日心情
    开心
    2023-2-28 23:59
  • 签到天数: 191 天

    [LV.7]常住居民III

    633

    主题

    5172

    回帖

    6051

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6051

    荣誉开发者管理员油中2周年生态建设者喜迎中秋

    发表于 2022-12-1 00:03:27 | 显示全部楼层
    jinyu2 发表于 2022-11-30 23:53
    有一个问题,对于失败的请求,我要返回错误码。我的写法是

    但是这样并不能区分resolve和reject。我该如何 ...

    reject触发了异常
    直接在函数里中断了
    应该改成resolve
    本质上promise就是相当于契约
    你应该自己制定契约的同意和错误的规则
    而不是根据网络请求指定的直接往上传
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
    回复

    使用道具 举报

    发表回复

    本版积分规则

    快速回复 返回顶部 返回列表