一直有个疑问,用 nodejs 时有什么优雅的办法能让代码在流程上回避掉回调吗? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
tomoya92
V2EX    Node.js

一直有个疑问,用 nodejs 时有什么优雅的办法能让代码在流程上回避掉回调吗?

  •  3
     
  •   tomoya92 2019-01-15 22:41:36 +08:00 8860 次点击
    这是一个创建于 2460 天前的主题,其中的信息可能已经有所发展或是发生改变。

    虽然现在 ES 标准里加上了 async await 来实现同步操作,还有 Promise,但业务复杂了,代码还是会被各种回调弄的执行流程出问题

    举个例子

    写 js 的时候用的最多的应该就是回调了,回调里可以传很多个参数,简单的操作,这样写很方便,但业务复杂了,就不方便了,回调地狱也就是这样来的

    这时候你可能会说不是有 Promise 吗,但用这货我觉得也就是把代码变的好看些,拿结果还是要靠 then 方法回调拿

    到这你可能还会说,不是还有 async await 吗,这货确实不用从 then 函数的回调里拿数据了,但用 nodejs 多了就会发现,很多函数的调用的写法还是会用到回调,而且这时候还会在回调函数的前面加上个 async,我也是无语了,这不是又回到起点了吗,如下

    it ('waitBody', async function() { await driver.sleep(500).wait('body', 30000).html().then(function(code) { isPageError(code).should.be.false; }) }) 

    当然也有用起来舒服的地方,比如 mongoose 的查询

    const results = await UserModel.find({}); 

    综上,难道就没有一个优雅的方法能让代码一行一行的执行吗,前一个结果执行完了,拿到结果再参与下一行代码的执行?

    有人会说了,你上面不是说了 async await 了吗,它不就是这样用的吗?那为啥还要在回调的方法上用 async await 呢?总觉得有点换汤不换药,折腾来折腾去,还是离不了回调,但回调又会涉及到代码结构和流程控制上的问题

    还请原谅我这小白的问题,相信很多学习 nodejs 的朋友都有过这样的疑惑

    80 条回复    2019-12-28 23:03:12 +08:00
    oott123
        1
    oott123  
       2019-01-15 22:46:54 +08:00 via Android   1
    没有,这就叫异步,你可以改用 Python。
    sagaxu
        2
    sagaxu  
       2019-01-15 22:48:41 +08:00 via Android
    promise 不能 await?
    lekai63
        3
    lekai63  
       2019-01-15 22:51:14 +08:00 via iPhone
    async 都不能忍受的话 要不考虑学个正经的偏后端语言?
    misaka19000
        4
    misaka19000  
       2019-01-15 22:51:15 +08:00
    最好的办法就是不写 JS (滑鸡)
    EPr2hh6LADQWqRVH
        5
    EPr2hh6LADQWqRVH  
       2019-01-15 22:52:25 +08:00 via Android
    promisify
    tcdw
        6
    tcdw  
       2019-01-15 22:56:45 +08:00 via Android
    > 很多函数的调用的写法还是会用到回调

    https://nodejs.org/api/util.html#util_util_promisify_original
    Hanggi
        7
    Hanggi  
       2019-01-15 22:57:40 +08:00
    你这个写的感觉有问题。你再好好看看。
    tomoya92
        8
    tomoya92  
    OP
       2019-01-15 23:07:07 +08:00
    @tcdw #6 感谢大佬指点,原来 nodejs 内置已经实现了一个 promise,并且有一定的规则,谢谢
    wly19960911
        9
    wly19960911  
       2019-01-15 23:07:43 +08:00
    这个和 nodejs 有什么关系呢,那异步你怎么解决异步回调的问题? async 已经很接近同步的写法了。

    不是 nodejs 想这么做,而是逻辑上只有这样的处理啊,不断的回调,我知道你什么时候运行什么方法嘛?我只能等你运行完成之后调用我才知道,你可以选择同步,但是问题是同步又阻塞线程你满意嘛。。

    另外你用 await 就用错了,是我我会这么用,虽然我接触 await 是在 flutter 里面。

    it ('waitBody', async function() {
    var a = await driver.sleep(500);
    var b =await a.wait('body', 30000);
    await html();
    (function(code) {
    isPageError(code).should.be.false;
    })();
    })
    tomoya92
        10
    tomoya92  
    OP
       2019-01-15 23:08:22 +08:00
    @Hanggi #7 前端萌新,一直都是迷迷糊糊的用 nodejs,最近觉得非常有必要把这个弄清楚,所以才发帖求助的,还请见谅 :joy
    tomoya92
        11
    tomoya92  
    OP
       2019-01-15 23:10:09 +08:00
    @wly19960911 #9 感谢指点,上面那段代码不是我写出来的,是 uirecorder 录制完成后自动生成的测试用例里的代码,我也觉得在回调上还用 async await 总觉得别扭 :joy
    wly19960911
        12
    wly19960911  
       2019-01-15 23:10:44 +08:00
    async 和 await 是把一切耗时的操作打上一个 await,然后整体下来看起来就像同步,而不是像你那样 promise 和 async 混搭
    Pastsong
        13
    Pastsong  
       2019-01-15 23:13:44 +08:00 via Android
    js 语言特色就是单线程异步,你要先理解 async 解决了什么问题
    tomoya92
        14
    tomoya92  
    OP
       2019-01-15 23:14:56 +08:00
    @wly19960911 #12 await 不是等待的意思吗?加上这个关键字后,后面的代码要等待这行代码执行完才往下继续执行,不应该是这个意思吗?
    wly19960911
        15
    wly19960911  
       2019-01-15 23:18:55 +08:00   1
    @tomoya92 #14 是的,然后你就没必要去不断的 写个 promise.then()去处理回调了,把 promise.then()的东西丢到一个方法里面,一个个 await 调用,实际上会比 promise.then()好看,而且逻辑上清晰。async 没有解决什么根本上的问题,只是一种新的写法让异步回调看起来像同步,把箭头函数里面的东西丢到一个封装方法里面,最后到达一个更直观的代码.
    Sparetire
        16
    Sparetire  
       2019-01-16 01:55:05 +08:00 via Android
    没看懂都 await 了,为什么还要 then。。讲道理是不会出现一个 then 的
    autoxbc
        17
    autoxbc  
       2019-01-16 04:42:41 +08:00   1
    这个例子本身写的不好,看面条代码脑子绕圈是正常反应,要先坚实自己,就不会被带偏

    可以看 Promise 迷你书
    omnip
        18
    omnip  
       2019-01-16 04:51:51 +08:00
    试试这样
    const code = await driver.sleep(500).wait('body', 3000).html();
    isPageError(code).should.be.false;
    edward8628
        19
    edward8628  
       2019-01-16 05:31:48 +08:00
    async 和 await 是目前最优雅的了
    tomoya92
        20
    tomoya92  
    OP
       2019-01-16 08:01:07 +08:00 via iPhone
    @Sparetire 跟着网上的教程学呀,发现用上 await 就能同步了,就用上了
    motai
        21
    motai  
       2019-01-16 08:08:30 +08:00 via iPhone
    回调是 js 的精髓吧
    lzvezr
        22
    lzvezr  
       2019-01-16 08:24:24 +08:00 via Android
    回调是不可能避免的,只是封装成 promise,让.then 或者 await 调用而已
    .then 和 await 只是为了让代码变得好看
    比如
    await cb1()
    await cb2()
    await cb3()
    要比
    f()
    .then(cb1())
    .then(cb2())
    .then(cb3())
    或者
    f(cb3(cb2(cb1)))
    好看一些
    tomoya92
        23
    tomoya92  
    OP
       2019-01-16 08:58:16 +08:00
    @lzvezr #22 我也是觉得 async await 这种就是让代码好看的,还是没有解决回调问题
    des
        24
    des  
       2019-01-16 09:04:33 +08:00 via Android
    那么,你可以去看看 fibjs
    另外你可以用 promise 包装回调,然后 await
    然而我觉得是你没明白 promise 和 async 是做了什么
    shintendo
        25
    shintendo  
       2019-01-16 09:06:03 +08:00   1
    @tomoya92
    我也是觉得 async await 这种就是让代码好看的,还是没有解决回调问题
    ----------------------
    因为回调本来就不是问题啊,nodejs 的精髓你要把它“解决”掉,那为什么要用 nodejs 呢
    lhx2008
        26
    lhx2008  
       2019-01-16 09:08:36 +08:00 via Android
    还有一种方法是响应式编程,rxjs 或者 reactorjs,不过也只是看起来比较美好,await 那种还是好用一点
    tomoya92
        27
    tomoya92  
    OP
       2019-01-16 09:09:07 +08:00
    @des #24 我确实是糊里糊涂的
    tomoya92
        28
    tomoya92  
    OP
       2019-01-16 09:10:20 +08:00
    @lhx2008 #26 嗯,谢谢,我觉得我还是像楼上说的那样,先把 promise async await 它们都是做什么的弄清楚比较好
    woodensail
        29
    woodensail  
       2019-01-16 09:14:02 +08:00   1
    ps:async await 可不只是好看一点这么简单。
    async 给了你统一的错误流,以及可精确控制范围的 try catch。
    没有 async 前,写复杂异步链的异常处理非常之痛苦……
    learnshare
        30
    learnshare  
       2019-01-16 09:43:53 +08:00
    Promise + async/await 已经比较优雅了
    qiushijie
        31
    qiushijie  
       2019-01-16 09:47:54 +08:00 via Android
    异步适用一次回调,回调使用多次调用
    shakaraka
        32
    shakaraka  
    PRO
       2019-01-16 10:00:28 +08:00
    用了 await 还用 then ??
    tomoya92
        33
    tomoya92  
    OP
       2019-01-16 10:02:28 +08:00
    @tcdw #6 大佬,再打扰一下,看你给的链接里的介绍,`fs.stat` 方法传进 `util.promisify(fs.stat) ` 里当参数后,下面就可以直接使用 async/await 来同步执行拿返回值数据了,当然它们有规则,就是 fs.stat 方法的回调第一个参数要是异常

    这样看来我是不是就可以理解为,任何一个被包装成了 Promise 的函数都可以使用 async/await 来同步执行拿返回值的数据?

    另外 `util.promisify()` 方法跟自定义的 Promise 封装是不是效果一样的呢?比如下面这两种用法是等效的吗?

    ```js
    function timeout(ms) {
    return new Promise((resolve, reject) => {
    setTimeout(resolve, ms, 'done');
    });
    }

    timeout(100).then((value) => {
    console.log(value);
    });
    ```

    ```js
    const timeout = util.promisify(setTimeout);
    timeout(100).then((value) => {
    console.log(value);
    });
    ```

    谢谢!
    cuberlzy
        34
    cuberlzy  
       2019-01-16 10:21:59 +08:00
    ``` js

    function timeout(ms) {
    return new Promise((resolve, reject) => {
    setTimeout(resolve, ms);
    });
    }

    await timeout(1000);

    ```
    roscoecheung1993
        35
    roscoecheung1993  
       2019-01-16 10:31:59 +08:00
    这就是 nodejs 的特点...如果没有异步,单线程模型就无法支持多用户访问了。
    某些模块的 api 还是支持同步调用的,比如 fs.readFileSync...写起来方便但是就阻塞了
    momocraft
        36
    momocraft  
       2019-01-16 10:36:01 +08:00
    代码清楚就行了,async/await 只是语法糖,不用太敏感

    await 之后的代码逻辑上已经是被 await 的 promise 的 then 的 callback,只是看起来代码是“连续”的
    yamedie
        37
    yamedie  
       2019-01-16 10:36:02 +08:00
    @tomoya92 "任何一个被包装成了 Promise 的函数都可以使用 async/await 来同步执行拿返回值的数据?"
    await 期待的就是一个 promise
    (如果 await 后面跟的是一个普通的 function, 也不会报错, 只是 await 变得毫无意义了)
    tomoya92
        38
    tomoya92  
    OP
       2019-01-16 10:39:14 +08:00
    @yamedie #37 哦哦,明白了,那我理解的就是对的了,谢谢!
    momocraft
        39
    momocraft  
       2019-01-16 10:41:24 +08:00
    顶楼的代码是不是也可以写成

    ```
    const code = await driver.sleep(500).wait('body', 30000).html();
    isPageError(code).should.be.false;
    ```

    ? 这样会清楚点吗?
    sagaxu
        40
    sagaxu  
       2019-01-16 10:48:34 +08:00 via Android
    @lzvezr 这段代码用回调写写看,就知道 await 是不是好看了

    for (let i = 0; i < 10; i++) {
    const ret = await $.getData(i);
    if (ret.code !== 0) {
    continue;
    }

    if (await check(ret.data) === true) {
    return ret.data;
    }
    }
    momocraft
        41
    momocraft  
       2019-01-16 10:52:18 +08:00   2
    await 一个不 thenable 的表达式也是有作用的,await 后的代码一定在栈清空后才被执行 (和 promise 的 then 同样保证)

    考虑:

    ```
    async function foo() {
    console.log(1);
    await 0;
    console.log(3);
    }

    foo();
    console.log(2);
    ```

    是不是有"意义"这个自己判断吧
    janxin
        42
    janxin  
       2019-01-16 10:53:20 +08:00
    @tomoya92 回调最大的问题难道不是很难看么
    momocraft
        43
    momocraft  
       2019-01-16 11:00:32 +08:00   1
    回调的另一个问题是这个语法不自带 "可组合性",表现为层数多起来就很难连异常处理一起写对

    而 await 时 promise fulfill 天然映射到表达式求值,promise reject 天然映射到求值中 throw,没被 catch 的 reject 会自动向上传递到一个无法忽略的地方
    tomoya92
        44
    tomoya92  
    OP
       2019-01-16 11:04:03 +08:00
    @janxin #42 还真不是,如果业务复杂,回调多了,会很乱的
    lzvezr
        45
    lzvezr  
       2019-01-16 12:48:06 +08:00 via Android
    @sagaxu 回调函数的循环控制嘛,这个在没有 await 的时候又不是没有

    实际上 await 后面是一个 promise 对象,而 promise 对象要返回值给上层需要一个 resolve()作为回调函数,最终还是回调函数

    这段程序要是没理解错的话,是需要依次获取数据直到得到正确结果
    可以构造一个对象,包含当前执行到的位置(i),最多可以达到的位置(10),函数 f(this.i),每次 f 执行之后 this.i++或者 cb(ret.data)
    Sparetire
        46
    Sparetire  
       2019-01-16 13:14:02 +08:00 via Android
    @tomoya92 不要把 async/await 当成同步。。它们只是看起来同步,实际上还是异步,异步逻辑不会消失,只会看起来变得优雅。把 async/await 当成同步那会给自己挖坑的。。
    sagaxu
        47
    sagaxu  
       2019-01-16 13:16:37 +08:00 via Android   1
    @lzvezr 手动维护一个 context 心智负担太重,这只是一个简单的例子,循环可以有多层,调用链路可以有十几层,实际逻辑可能复杂的多,相当于人肉维护一个状态机。同步写法,思路顺畅许多,也更不容易出错。

    不仅是 js,各种语言都在往弃回调,引入同步写法。
    tomoya92
        48
    tomoya92  
    OP
       2019-01-16 13:22:00 +08:00
    @Sparetire #46 也就是说用了 async/await 代码会在 await 那地方等着执行完对吧,至于被调用方法执行是同步执行还是异步执行的,不是 async/await 管的了,是这个意思不?
    lamada
        49
    lamada  
       2019-01-16 13:25:52 +08:00
    rxjs?
    lzvezr
        50
    lzvezr  
       2019-01-16 13:48:31 +08:00 via Android
    @sagaxu 嗯哼,好像理念并不冲突啊,谁不喜欢用同步写法去调用异步函数呢

    楼主的问题是觉得已经有 async 了,结果使用第三方库只是回调函数从 function 变成了 async function,并没有解决回调

    当其他库没法直接用,或者为了兼容性还在使用回调的时候,自己封装一下就显得很必要
    reus
        51
    reus  
       2019-01-16 13:57:51 +08:00
    不要用 js 不就行了,找个对并发支持更好的不就行了
    Sparetire
        52
    Sparetire  
       2019-01-16 14:03:31 +08:00 via Android   1
    @tomoya92 只是当前函数的上下文中会等待在这里,但是每个等待的时候,都有可能存在其他函数在执行,和回调一样是异步的,这和同步是有区别的
    est
        53
    est  
       2019-01-16 14:04:25 +08:00
    优雅和 优雅 是互斥的。
    est
        54
    est  
       2019-01-16 14:04:31 +08:00
    优雅和 nodejs 是互斥的。
    pkoukk
        55
    pkoukk  
       2019-01-16 14:09:33 +08:00
    主要是很多第三方库是照着 promise 和回调设计的,所以有些地方没办法用 async/await 解决。
    比如 sequelize 的 transcation
    wly19960911
        56
    wly19960911  
       2019-01-16 14:22:08 +08:00
    @reus #51 并发和 js 有什么关系嘛。并发是一个实现,js 只是工具,实际上异步实现并发性能还更好。如果是多线程的并发,还得玩多线程,相比异步反而麻烦了。
    janxin
        57
    janxin  
       2019-01-16 14:30:58 +08:00
    @tomoya92 乱不就是难看么...
    oyjw443523
        58
    oyjw443523  
       2019-01-16 14:38:12 +08:00
    想不用回调就去试下 go,得用协程
    yoshiyuki
        59
    yoshiyuki  
       2019-01-16 14:50:17 +08:00
    异步回调是为了实现更好的 IO 性能,如果不需要 IO 性能可以考虑改用 PHP、Python 等
    tomoya92
        60
    tomoya92  
    OP
       2019-01-16 14:56:46 +08:00
    @oyjw443523 #58 go 用过,写着很舒服,不过还是没有 nodejs 用的广,而且公司要用啥也不是我说的算的 :joy
    tomoya92
        61
    tomoya92  
    OP
       2019-01-16 14:57:36 +08:00
    @yoshiyuki #59 其实用 nodejs 还有一个好处,就是快,开发效率要比 java 不知道高多少 :joy
    yoshiyuki
        62
    yoshiyuki  
       2019-01-16 15:23:38 +08:00
    @tomoya92 PHP 开发更快
    TomVista
        63
    TomVista  
       2019-01-16 15:36:42 +08:00
    ```
    function some (callback){
    }

    function callback(callback2){
    }

    function callback2(callback3){
    }
    ...


    ```
    Ritr
        64
    Ritr  
       2019-01-16 16:44:50 +08:00
    js 本身就是异步的呀,所以我打算学个其他语言
    reus
        65
    reus  
       2019-01-16 17:19:33 +08:00
    @wly19960911 我用多线程从来就不用考虑这个帖子提出的问题
    justin2018
        66
    justin2018  
       2019-01-16 22:31:15 +08:00
    长时间不写 我总是会忘记~ 不知道为啥~~~
    tomoya92
        67
    tomoya92  
    OP
       2019-01-16 23:11:01 +08:00 via iPhone
    @justin2018 我经常用,都分不清,更别说长时间不用了
    libook
        68
    libook  
       2019-01-16 23:42:52 +08:00
    如果执意使用回调函数的思想来设计程序的话,用什么语言都会有这个问题。

    JS 是以完全不用回调函数来设计数据流的,你都用 async await 了,为什么还要用回调函数来传递数据?可以拿出几个例子来,一定有更好的代码的组织方案的。
    libook
        69
    libook  
       2019-01-16 23:49:01 +08:00
    it ('waitBody', async function() {
    const code = await driver.sleep(500).wait('body', 30000).html();
    isPageError(code).should.be.false;
    })

    这块没必要再用 then 了,你都用 await 了,那就一定是等着这段代码执行完再执行下一句。
    lhx2008
        70
    lhx2008  
       2019-01-17 00:02:14 +08:00 via Android
    @tomoya92 说 python 快我还信了,普通 js 真的不行,npm 装个包都不知道要多久,一升级就各种瞎改,异步也不好写,异常链+正常链+多线程都难搞死了,维护别人代码都想砍人
    sagaxu
        71
    sagaxu  
       2019-01-17 00:10:28 +08:00 via Android
    @tomoya92 那是你不熟悉现代 Java
    busfool
        72
    busfool  
       2019-01-17 06:47:36 +08:00 via Android
    没有,js 异步无法优雅处理
    tomoya92
        73
    tomoya92  
    OP
       2019-01-17 09:20:00 +08:00
    @sagaxu #71 我使用 java 还停留在 8 的版本上
    zy445566
        74
    zy445566  
       2019-01-17 10:05:27 +08:00
    把所有的回调都封装成 Promise,然后返回给上面 await 就好了
    KuroNekoFan
        75
    KuroNekoFan  
       2019-01-17 10:31:20 +08:00
    关于 promiseFunc.then(some_stuff)的观感问题,你可以
    Promise.resolve()
    .then(stuff_1)
    .then(stuff_2)
    //...
    salamanderMH
        76
    salamanderMH  
       2019-01-17 10:47:10 +08:00
    promisify
    no1xsyzy
        77
    no1xsyzy  
       2019-01-17 11:31:52 +08:00
    @oyjw443523 #58 协程不就是 async/await 吗
    其实 NodeJS ( Python 的也是)的 async/await 就是把异步变成协程写法。

    @lhx2008 #70 yarn,请

    其实异步除了回调、Promise/Future、async/await (包括协程)还有一种就是信号式。
    信号式其实多线程下也能很好用,调用链清晰,程序本身就是个系统设计图。
    缺点就是状态不能自然保留和共享(必然手动维护 context ),并且对一本道的代码没特别大的影响。
    exonuclease
        78
    exonuclease  
       2019-01-17 14:36:11 +08:00   1
    我搞了个 node 的 c++扩展 可以强制把异步调用同步执行 不过代价是性能
    hoyixi
        79
    hoyixi  
       2019-01-20 13:51:40 +08:00
    就你给的代码,你不想写 then 回调,
    直接:
    code = await。。。。
    if (判断 code )。。。

    这不就是同步写法吗,await 的优势就是能让你这么写啊,你又不用
    angsheng
        80
    angsheng  
       2019-12-28 23:03:12 +08:00   1
    我个人就很喜欢写回调套回调,当发现回调卡死了写不下去时候比如 fs.statu 与 fs.read 的配套操作的时候,问题出在了整个处理流程的设计,反过头重新设计就是了。
    当然我理解“回调地狱”,,,但我对 Promise、async/await 就感到特别头疼,总是想不起来这个对象怎么用,真希望能尊重下像我这种习惯写回调而不习惯新语法的。
    nodejs 就是 IO 类 API 是与主线程分开的另一个线程(其本身是不是队列结构实在是忘了),所以这里姑且认为至少有两个线程,代码顺序的主线程和 IO 类 API 所在那个线程。Promise 之类折腾来去无非是换了个写法而已(从程序员的层面来看)。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5529 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSIO: 3.9.8.5 34ms UTC 08:59 PVG 16:59 LAX 01:59 JFK 04:59
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86