【问题标题】:Javascript promise conversionJavascript 承诺转换
【发布时间】:2014-05-23 14:19:04
【问题描述】:

我很难理解 Promise 是如何工作的。我看过一些例子,其中一些是有道理的。但是,当我尝试实际使用它时,我被卡住了。我有以下示例: (我正在使用 q 和 nodejs。getItem() 返回一个承诺,但我的函数不会等待它。)

function calculate(id, item) {
   var calcId = id ? id : getItem(item);
   if (!id && calcId) { calcId = calcId.Id; }

   if (calcId) {
      update(calcId);
   } else {
      insert(item);
   }
}

根据示例,如果不重复代码,我不明白如何做到这一点。

【问题讨论】:

  • “不等待”是什么意思?否则它将如何访问其.Id?还是那是承诺的属性?

标签: javascript node.js promise q


【解决方案1】:

Promise 是异步解决的,因此您不能像示例中那样将它们视为同步的。如果需要,您想要做的是强制该值是 Q 承诺,然后从那里继续,这样您就具有确定性的行为并且没有代码重复。

我在这里对 updateinsert 返回承诺并在需要时返回它们做出一些假设,以便计算本身返回承诺。

function calculate( id, item ) {
    return Q( id || getItem(item) ).then(function( calcId ) {

        // Code seems weird to be, but it's based on the original example.
        // Might want to review this.
        if ( !id && calcId ) {
            calcId = calcId.Id;
        }

        return calcId ?
            update( calcId ) :
            insert( item );
    });
}

【讨论】:

    【解决方案2】:

    不要重复您的 id 检查:

    function calculate(id, item) {
        var calcId;
    
        if (id) {
            calcId = id;
        } else {
            calcId = getItem(item).Id;
        }
    
        if (calcId) {
            update(calcId);
        } else {
            insert(item);
        }
    }
    

    现在让calcId 始终是一个持有Id 的承诺:

    function calculate(id, item) {
        var p;
    
        if (id) {
            p = Promise.resolve({ Id: id });
        } else {
            p = getItem(item);
        }
    
        return p.then(function (calcId) {
            if (calcId.Id) {
                return update(calcId.Id);
            } else {
                return insert(item);
            }
        });
    }
    

    在 Q 的情况下,Promise.resolveQ.resolve,或者只是 Q

    奖励:作为生成器!

    function calculate(id, item) {
       var calcId = id ? id : yield getItem(item);
       if (!id && calcId) { calcId = calcId.Id; }
    
       if (calcId) {
          update(calcId);
       } else {
          insert(item);
       }
    }
    

    【讨论】:

    • 由于 id 未定义,我需要检索项目 (getItem()) q.resolve 到底有什么帮助?永远无法达到该代码。 getItem() 是我必须等待的...
    • @user3582665:对不起,我完全忘记了then
    【解决方案3】:

    几点:

    • 需要使用指定为 promise 方法参数的函数来处理 Promise 包装的结果(例如 .then(fn)
    • Q(x) 可用于确保 x 是 Promise 包装的。如果x 已经是一个承诺,则该操作是透明的 - 它不会被双重包装
    • 您需要安全,以防iditem 都为空或丢失
    • 如果calcId 是假的并且没有提供item,您需要进一步的安全
    • idcalcId.Id 可以更优雅地迎合。
    function calculate(id, item) {
        if(!id && !item) {
            throw new Error("'calculate(): parameters empty or missing'");
        }
        return Q(id ? {Id:id} : getItem(item)).then(function(resultObj) {
            var calcId = resultObj.Id;
            if(calcId) {
                update(calcId);
            } else {
                if(item) {
                    insert(item);
                } else {
                    throw new Error("'calculate(): `calcId` is falsy and `item` is empty of missing'");
                }
            }
            return calcId; //in case you need to chain calculate(...).then(...)
            //(Alternatively, if update() and insert() return promises, then return them instead as per dherman's answer)
        });
    }
    

    调用如下:

    calculate(myId, myItem).then(function(calcId) {
        //(optional) anything else you wish to do with `calcId`
    }).catch(function(e) {
        console.error(e);
    });
    

    【讨论】:

      猜你喜欢
      • 2018-08-08
      • 2015-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-27
      • 2018-05-04
      • 2018-01-10
      相关资源
      最近更新 更多