V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
oott123
V2EX  ›  JavaScript

Promise 里要用到上一个执行过程里的变量怎么办?

  •  
  •   oott123 · 2015-06-14 23:02:43 +08:00 · 3514 次点击
    这是一个创建于 3246 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如,

    Q "Hello world"
    .then (str)->
        "hello 2"
    .then (str2)->
        # str 怎么获取?
    

    备选方案 1:闭包法

    Q "hello world"
    .then (str)->
        Q "hello 2"
        .then (str2)->
            console.log str, str2
    

    缺点:不好看,陷入了 callback hell。

    备选方案 2:外部变量法

    str = null
    Q "hello world"
    .then (s)->
        s = str
        "hello 2"
    .then (str2)->
        console.log str, str2
    

    缺点:用跨越作用域的变量,显得不太干净

    备选方案 3:返回数组法

    Q "hello world"
    .then (str)->
        [str, "hello 2"]
    .then (s)->
        console.log s[0], s[1]
    

    缺点:返回值意义不明朗;要向下传递多层的时候麻烦。

    所以大家遇到这种问题的时候怎么办?

    12 条回复    2015-06-15 14:10:25 +08:00
    br00k
        1
    br00k  
       2015-06-14 23:11:00 +08:00
    我自己用的第一种。。
    xream
        2
    xream  
       2015-06-14 23:19:17 +08:00   ❤️ 2
    我知道用 bluebird 可以 bind 到 this 上

    .bind() also has a useful side purpose - promise handlers don't need to share a function to use shared state:

    somethingAsync().bind({})
    .spread(function (aValue, bValue) {
    this.aValue = aValue;
    this.bValue = bValue;
    return somethingElseAsync(aValue, bValue);
    })
    .then(function (cValue) {
    return this.aValue + this.bValue + cValue;
    });
    lilydjwg
        3
    lilydjwg  
       2015-06-14 23:22:00 +08:00
    理论上方案三最好。如果数组意义不明确,那么就用 object。实践上方案一写起来方便,但是变量太多的话效果与全局变量类似。
    fundon
        4
    fundon  
       2015-06-14 23:26:36 +08:00   ❤️ 1
    `spread` 返回多个值,是最方便的
    joyee
        5
    joyee  
       2015-06-14 23:54:12 +08:00   ❤️ 1
    用方案三,但用object。如果能用 ES6,配合 ES6 的 object literal shorthand

    Promise.resolve("hello world")
    .then(str => ({str1: str, str2: "hello 2"}))
    .then(({str1, str2}) => console.log(str1, str2))
    iwege
        6
    iwege  
       2015-06-15 00:01:00 +08:00
    @fundon 这个是最好的办法。
    MForever78
        7
    MForever78  
       2015-06-15 00:13:15 +08:00   ❤️ 3
    首先比较推荐使用 bluebird,API 比较丰富,性能也比较高,比 io.js 原生实现的都快。

    如果几个执行过程是相互独立的,只是最终的返回的结果需要用到所有过程的结果,那就用 .spread

    Promise.delay(500).then(function() {
    return [fs.readFileAsync("file1.txt"),
    fs.readFileAsync("file2.txt")] ;
    }).spread(function(file1text, file2text) {
    if (file1text !== file2text) {
    console.log("files are equal");
    }
    else {
    console.log("files are not equal");
    }
    });

    如果后面的过程依赖前面过程的结果,就用第三种,传递的时候用 Object。
    Axurez
        8
    Axurez  
       2015-06-15 12:38:52 +08:00
    这是啥语言?
    orzfly
        9
    orzfly  
       2015-06-15 13:06:54 +08:00
    @Axurez CoffeeScript
    oott123
        10
    oott123  
    OP
       2015-06-15 13:11:57 +08:00
    @xream @MForever78 @fundon 谢谢你们,我觉得我心目中最好的方法大概就是 `spread` 这个 api。
    至于 bluebrid 和 Q 嘛……一开始接触到的就是 Q 就一直用了,不过我倒是觉得 Q 的 api 比 bluebird 的好用一些……

    @joyee coffee 里没有这么好用的语法…… coffee 作者似乎对 ES6 比较抵触。

    @Axurez 是 coffeescript。
    oott123
        11
    oott123  
    OP
       2015-06-15 13:13:16 +08:00
    @br00k
    @lilydjwg 第一种太难看了啊……
    本来用 promise 就是为了避免这种一大堆的嵌套回调……
    otakustay
        12
    otakustay  
       2015-06-15 14:10:25 +08:00
    我会选第三种,这种情况下数组其实是一个Tuple,从这个角度理解就是一个非常正常的数据结构了
    其实更多的我会在第三种的基础上返回对象
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2337 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 06:58 · PVG 14:58 · LAX 23:58 · JFK 02:58
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.