简体   繁体   English

如何在 .then() 链中访问先前的承诺结果?

[英]How do I access previous promise results in a .then() chain?

I have restructured my code to promises , and built a wonderful long flat promise chain , consisting of multiple .then() callbacks.我已经将我的代码重构为promises ,并构建了一个美妙的长扁平 promise 链,由多个.then()回调组成。 In the end I want to return some composite value, and need to access multiple intermediate promise results .最后我想返回一些复合值,并且需要访问多个中间承诺结果 However the resolution values from the middle of the sequence are not in scope in the last callback, how do I access them?然而,序列中间的分辨率值不在最后一个回调的范围内,我如何访问它们?

function getExample() {
    return promiseA(…).then(function(resultA) {
        // Some processing
        return promiseB(…);
    }).then(function(resultB) {
        // More processing
        return // How do I gain access to resultA here?
    });
}

Break the chain打破链条

When you need to access the intermediate values in your chain, you should split your chain apart in those single pieces that you need.当您需要访问链中的中间值时,您应该将链拆分为您需要的单个部分。 Instead of attaching one callback and somehow trying to use its parameter multiple times, attach multiple callbacks to the same promise - wherever you need the result value.与其附加一个回调并以某种方式尝试多次使用其参数,不如将多个回调附加到同一个 Promise - 无论您需要结果值的任何地方。 Don't forget, a promise just represents (proxies) a future value !不要忘记, promise 只是代表(代理)一个未来值 Next to deriving one promise from the other in a linear chain, use the promise combinators that are given to you by your library to build the result value.在从线性链中的另一个 promise 导出一个 promise 之后,使用库提供给您的 promise 组合子来构建结果值。

This will result in a very straightforward control flow, clear composition of functionalities and therefore easy modularisation.这将导致非常简单的控制流程、清晰的功能组合,因此易于模块化。

function getExample() {
    var a = promiseA(…);
    var b = a.then(function(resultA) {
        // some processing
        return promiseB(…);
    });
    return Promise.all([a, b]).then(function([resultA, resultB]) {
        // more processing
        return // something using both resultA and resultB
    });
}

Instead of the parameter destructuring in the callback after Promise.all that only became available with ES6, in ES5 the then call would be replaced by a nifty helper method that was provided by many promise libraries ( Q , Bluebird , when , …): .spread(function(resultA, resultB) { … .Promise.all之后回调中的参数解构(仅在 ES6 中可用)不同,在 ES5 中then调用将被许多 Promise 库( QBluebirdwhen ……)提供的漂亮辅助方法替换: .spread(function(resultA, resultB) { …

Bluebird also features a dedicated join function to replace that Promise.all + spread combination with a simpler (and more efficient) construct: Bluebird 还具有专用的join函数,可以用更简单(更高效)的构造替换Promise.all + spread组合:

…
return Promise.join(a, b, function(resultA, resultB) { … });

ECMAScript Harmony ECMAScript 和谐

Of course, this problem was recognized by the language designers as well.当然,这个问题也得到了语言设计者的认可。 They did a lot of work and the async functions proposal finally made it into他们做了很多工作,异步函数提案最终成为了

ECMAScript 8 ECMAScript 8

You don't need a single then invocation or callback function anymore, as in an asynchronous function (that returns a promise when being called) you can simply wait for promises to resolve directly.您不再需要单个then调用或回调函数,因为在异步函数(在被调用时返回承诺)中,您可以简单地等待承诺直接解析。 It also features arbitrary control structures like conditions, loops and try-catch-clauses, but for the sake of convenience we don't need them here:它还具有任意控制结构,如条件、循环和 try-catch-clause,但为了方便起见,我们在这里不需要它们:

async function getExample() {
    var resultA = await promiseA(…);
    // some processing
    var resultB = await promiseB(…);
    // more processing
    return // something using both resultA and resultB
}

ECMAScript 6 ECMAScript 6

While we were waiting for ES8, we already did use a very similar kind of syntax.在我们等待 ES8 的时候,我们已经使用了一种非常相似的语法。 ES6 came with generator functions , which allow breaking the execution apart in pieces at arbitrarily placed yield keywords. ES6 带有生成器函数,它允许在任意放置的yield关键字处将执行分成几部分。 Those slices can be run after each other, independently, even asynchronously - and that's just what we do when we want to wait for a promise resolution before running the next step.这些切片可以相互独立,甚至异步运行 - 这就是我们想要在运行下一步之前等待承诺解决方案时所做的。

There are dedicated libraries (like co or task.js ), but also many promise libraries have helper functions ( Q , Bluebird , when , …) that do this async step-by-step execution for you when you give them a generator function that yields promises.有专用的库(如cotask.js ),但也有许多Promise库具有辅助函数( QBluebirdwhen ……),当您给它们一个生成器函数时,它们会为您执行异步逐步执行产生承诺。

var getExample = Promise.coroutine(function* () {
//               ^^^^^^^^^^^^^^^^^ Bluebird syntax
    var resultA = yield promiseA(…);
    // some processing
    var resultB = yield promiseB(…);
    // more processing
    return // something using both resultA and resultB
});

This did work in Node.js since version 4.0, also a few browsers (or their dev editions) did support generator syntax relatively early.自 4.0 版以来,这在 Node.js 中确实有效,而且一些浏览器(或其开发版本)确实较早地支持生成器语法。

ECMAScript 5 ECMAScript 5

However, if you want/need to be backward-compatible you cannot use those without a transpiler.但是,如果您想要/需要向后兼容,则不能在没有转译器的情况下使用那些。 Both generator functions and async functions are supported by the current tooling, see for example the documentation of Babel on generators and async functions .当前工具支持生成器函数和异步函数,例如参见 Babel 关于生成器异步函数的文档。

And then, there are also many other compile-to-JS languages that are dedicated to easing asynchronous programming.然后,还有许多其他编译为 JS 的语言专门用于简化异步编程。 They usually use a syntax similar to await , (eg Iced CoffeeScript ), but there are also others that feature a Haskell-like do -notation (eg LatteJs , monadic , PureScript or LispyScript ).他们通常使用类似语法await (例如冰的CoffeeScript ),但也有其他人配备了哈斯克尔样do -notation(如LatteJs一元PureScriptLispyScript )。

Synchronous inspection同步检测

Assigning promises-for-later-needed-values to variables and then getting their value via synchronous inspection.将 promises-for-later-needed-values 分配给变量,然后通过同步检查获取它们的值。 The example uses bluebird's .value() method but many libraries provide similar method.该示例使用 bluebird 的.value()方法,但许多库提供了类似的方法。

function getExample() {
    var a = promiseA(…);

    return a.then(function() {
        // some processing
        return promiseB(…);
    }).then(function(resultB) {
        // a is guaranteed to be fulfilled here so we can just retrieve its
        // value synchronously
        var aValue = a.value();
    });
}

This can be used for as many values as you like:这可以用于任意数量的值:

function getExample() {
    var a = promiseA(…);

    var b = a.then(function() {
        return promiseB(…)
    });

    var c = b.then(function() {
        return promiseC(…);
    });

    var d = c.then(function() {
        return promiseD(…);
    });

    return d.then(function() {
        return a.value() + b.value() + c.value() + d.value();
    });
}

Nesting (and) closures嵌套(和)闭包

Using closures for maintaining the scope of variables (in our case, the success callback function parameters) is the natural JavaScript solution.使用闭包来维护变量的范围(在我们的例子中,成功回调函数参数)是自然的 JavaScript 解决方案。 With promises, we can arbitrarily nest and flatten .then() callbacks - they are semantically equivalent, except for the scope of the inner one.使用 promise,我们可以任意嵌套和扁平化.then()回调——它们在语义上是等效的,除了内部的范围。

function getExample() {
    return promiseA(…).then(function(resultA) {
        // some processing
        return promiseB(…).then(function(resultB) {
            // more processing
            return // something using both resultA and resultB;
        });
    });
}

Of course, this is building an indentation pyramid.当然,这是在构建一个缩进金字塔。 If indentation is getting too large, you still can apply the old tools to counter the pyramid of doom : modularize, use extra named functions, and flatten the promise chain as soon as you don't need a variable any more.如果缩进太大,您仍然可以应用旧工具来对抗厄运金字塔:模块化,使用额外的命名函数,并在不再需要变量时立即展平承诺链。
In theory, you can always avoid more than two levels of nesting (by making all closures explicit), in practise use as many as are reasonable.理论上,您总是可以避免多于两层的嵌套(通过使所有闭包显式),在实践中尽可能多地使用。

function getExample() {
    // preprocessing
    return promiseA(…).then(makeAhandler(…));
}
function makeAhandler(…)
    return function(resultA) {
        // some processing
        return promiseB(…).then(makeBhandler(resultA, …));
    };
}
function makeBhandler(resultA, …) {
    return function(resultB) {
        // more processing
        return // anything that uses the variables in scope
    };
}

You can also use helper functions for this kind of partial application , like _.partial from Underscore / lodash or the native .bind() method , to further decrease indentation:您还可以使用辅助功能对于这种局部的应用,像_.partial下划线/ lodash本地.bind()方法,以进一步降低缩进:

function getExample() {
    // preprocessing
    return promiseA(…).then(handlerA);
}
function handlerA(resultA) {
    // some processing
    return promiseB(…).then(handlerB.bind(null, resultA));
}
function handlerB(resultA, resultB) {
    // more processing
    return // anything that uses resultA and resultB
}

Explicit pass-through显式传递

Similar to nesting the callbacks, this technique relies on closures.与嵌套回调类似,此技术依赖于闭包。 Yet, the chain stays flat - instead of passing only the latest result, some state object is passed for every step.然而,链保持平坦——不是只传递最新的结果,而是每一步都传递一些状态对象。 These state objects accumulate the results of the previous actions, handing down all values that will be needed later again plus the result of the current task.这些状态对象累积先前操作的结果,传递以后再次需要的所有值以及当前任务的结果。

function getExample() {
    return promiseA(…).then(function(resultA) {
        // some processing
        return promiseB(…).then(b => [resultA, b]); // function(b) { return [resultA, b] }
    }).then(function([resultA, resultB]) {
        // more processing
        return // something using both resultA and resultB
    });
}

Here, that little arrow b => [resultA, b] is the function that closes over resultA , and passes an array of both results to the next step.这里,那个小箭头b => [resultA, b]是关闭resultA的函数,并将两个结果的数组传递给下一步。 Which uses parameter destructuring syntax to break it up in single variables again.它使用参数解构语法再次将其分解为单个变量。

Before destructuring became available with ES6, a nifty helper method called .spread() was provided by many promise libraries ( Q , Bluebird , when , …).在 ES6 提供解构之前,许多.spread()库( QBluebirdwhen ……)都提供了一个名为.spread()的漂亮辅助方法。 It takes a function with multiple parameters - one for each array element - to be used as .spread(function(resultA, resultB) { … .它需要一个带有多个参数的函数 - 每个数组元素一个 - 用作.spread(function(resultA, resultB) { …

Of course, that closure needed here can be further simplified by some helper functions, eg当然,这里需要的闭包可以通过一些辅助函数进一步简化,例如

function addTo(x) {
    // imagine complex `arguments` fiddling or anything that helps usability
    // but you get the idea with this simple one:
    return res => [x, res];
}

…
return promiseB(…).then(addTo(resultA));

Alternatively, you can employ Promise.all to produce the promise for the array:或者,您可以使用Promise.all为数组生成承诺:

function getExample() {
    return promiseA(…).then(function(resultA) {
        // some processing
        return Promise.all([resultA, promiseB(…)]); // resultA will implicitly be wrapped
                                                    // as if passed to Promise.resolve()
    }).then(function([resultA, resultB]) {
        // more processing
        return // something using both resultA and resultB
    });
}

And you might not only use arrays, but arbitrarily complex objects.您不仅可以使用数组,还可以使用任意复杂的对象。 For example, with _.extend or Object.assign in a different helper function:例如,在不同的辅助函数中使用_.extendObject.assign

function augment(obj, name) {
    return function (res) { var r = Object.assign({}, obj); r[name] = res; return r; };
}

function getExample() {
    return promiseA(…).then(function(resultA) {
        // some processing
        return promiseB(…).then(augment({resultA}, "resultB"));
    }).then(function(obj) {
        // more processing
        return // something using both obj.resultA and obj.resultB
    });
}

While this pattern guarantees a flat chain and explicit state objects can improve clarity, it will become tedious for a long chain.虽然这种模式保证了一个扁平的链并且明确的状态对象可以提高清晰度,但对于长链来说它会变得乏味。 Especially when you need the state only sporadically, you still have to pass it through every step.特别是当您只是偶尔需要状态时,您仍然需要通过每一步。 With this fixed interface, the single callbacks in the chain are rather tightly coupled and inflexible to change.有了这个固定的接口,链中的单个回调就非常紧密地耦合在一起,并且难以改变。 It makes factoring out single steps harder, and callbacks cannot be supplied directly from other modules - they always need to be wrapped in boilerplate code that cares about the state.它使分解单个步骤变得更加困难,并且不能直接从其他模块提供回调——它们总是需要包装在关心状态的样板代码中。 Abstract helper functions like the above can ease the pain a bit, but it will always be present.像上面这样的抽象辅助函数可以稍微缓解一些痛苦,但它会一直存在。

Mutable contextual state可变上下文状态

The trivial (but inelegant and rather errorprone) solution is to just use higher-scope variables (to which all callbacks in the chain have access) and write result values to them when you get them:微不足道(但不优雅且相当容易出错)的解决方案是只使用更高范围的变量(链中的所有回调都可以访问)并在获得结果值时将结果值写入它们:

function getExample() {
    var resultA;
    return promiseA(…).then(function(_resultA) {
        resultA = _resultA;
        // some processing
        return promiseB(…);
    }).then(function(resultB) {
        // more processing
        return // something using both resultA and resultB
    });
}

Instead of many variables one might also use an (initially empty) object, on which the results are stored as dynamically created properties.除了许多变量之外,还可以使用(最初为空的)对象,在该对象上将结果存储为动态创建的属性。

This solution has several drawbacks:该解决方案有几个缺点:

  • Mutable state is ugly , and global variables are evil .可变状态是丑陋的全局变量是邪恶的
  • This pattern doesn't work across function boundaries, modularising the functions is harder as their declarations must not leave the shared scope这种模式不能跨函数边界工作,模块化函数更难,因为它们的声明不能离开共享范围
  • The scope of the variables does not prevent to access them before they are initialized.变量的范围不会阻止在初始化之前访问它们。 This is especially likely for complex promise constructions (loops, branching, excptions) where race conditions might happen.这对于可能发生竞争条件的复杂承诺结构(循环、分支、异常)尤其有可能。 Passing state explicitly, a declarative design that promises encourage, forces a cleaner coding style which can prevent this.显式传递状态,一种承诺鼓励的声明式设计,强制采用更简洁的编码风格,可以防止这种情况发生。
  • One must choose the scope for those shared variables correctly.必须正确选择这些共享变量的范围。 It needs to be local to the executed function to prevent race conditions between multiple parallel invocations, as would be the case if, for example, state was stored on an instance.它需要位于执行的函数的本地,以防止多个并行调用之间的竞争条件,例如,如果状态存储在实例上,就会出现这种情况。

The Bluebird library encourages the use of an object that is passed along, using their bind() method to assign a context object to a promise chain. Bluebird 库鼓励使用传递的对象,使用bind()方法将上下文对象分配给承诺链。 It will be accessible from each callback function via the otherwise unusable this keyword .每个回调函数都可以通过否则无法使用的this关键字访问它。 While object properties are more prone to undetected typos than variables, the pattern is quite clever:虽然对象属性比变量更容易出现未检测到的拼写错误,但该模式非常聪明:

function getExample() {
    return promiseA(…)
    .bind({}) // Bluebird only!
    .then(function(resultA) {
        this.resultA = resultA;
        // some processing
        return promiseB(…);
    }).then(function(resultB) {
        // more processing
        return // something using both this.resultA and resultB
    }).bind(); // don't forget to unbind the object if you don't want the
               // caller to access it
}

This approach can be easily simulated in promise libraries that do not support .bind (although in a somewhat more verbose way and cannot be used in an expression):这种方法可以在不支持 .bind 的 Promise 库中轻松模拟(尽管以更冗长的方式并且不能在表达式中使用):

function getExample() {
    var ctx = {};
    return promiseA(…)
    .then(function(resultA) {
        this.resultA = resultA;
        // some processing
        return promiseB(…);
    }.bind(ctx)).then(function(resultB) {
        // more processing
        return // something using both this.resultA and resultB
    }.bind(ctx));
}

A less harsh spin on "Mutable contextual state"不那么苛刻的“可变上下文状态”

Using a locally scoped object to collect the intermediate results in a promise chain is a reasonable approach to the question you posed.使用本地范围的对象来收集承诺链中的中间结果是解决您提出的问题的合理方法。 Consider the following snippet:考虑以下片段:

function getExample(){
    //locally scoped
    const results = {};
    return promiseA(paramsA).then(function(resultA){
        results.a = resultA;
        return promiseB(paramsB);
    }).then(function(resultB){
        results.b = resultB;
        return promiseC(paramsC);
    }).then(function(resultC){
        //Resolve with composite of all promises
        return Promise.resolve(results.a + results.b + resultC);
    }).catch(function(error){
        return Promise.reject(error);
    });
}
  • Global variables are bad, so this solution uses a locally scoped variable which causes no harm.全局变量很糟糕,所以这个解决方案使用了一个不会造成伤害的局部范围变量。 It is only accessible within the function.它只能在函数内访问。
  • Mutable state is ugly, but this does not mutate state in an ugly manner.可变状态是丑陋的,但这不会以丑陋的方式改变状态。 The ugly mutable state traditionally refers to modifying the state of function arguments or global variables, but this approach simply modifies the state of a locally scoped variable that exists for the sole purpose of aggregating promise results...a variable that will die a simple death once the promise resolves.丑陋的可变状态传统上是指修改函数参数或全局变量的状态,但这种方法只是修改了局部作用域变量的状态,该变量存在的唯一目的是聚合承诺结果......一个将简单死亡的变量一旦承诺解决。
  • Intermediate promises are not prevented from accessing the state of the results object, but this does not introduce some scary scenario where one of the promises in the chain will go rogue and sabotage your results.不会阻止中间承诺访问结果对象的状态,但这不会引入一些可怕的场景,其中链中的一个承诺会流氓并破坏您的结果。 The responsibility of setting the values in each step of the promise is confined to this function and the overall result will either be correct or incorrect...it will not be some bug that will crop up years later in production (unless you intend it to!)在 promise 的每一步中设置值的责任仅限于这个函数,整体结果要么正确要么不正确......它不会是几年后在生产中突然出现的错误(除非你打算这样做!)
  • This does not introduce a race condition scenario that would arise from parallel invocation because a new instance of the results variable is created for every invocation of the getExample function.这不会引入由并行调用引起的竞争条件场景,因为每次调用 getExample 函数都会创建一个新的结果变量实例。

Example is available on jsfiddle示例在jsfiddle可用

Node 7.4 now supports async/await calls with the harmony flag. Node 7.4 现在支持带有和声标志的 async/await 调用。

Try this:尝试这个:

async function getExample(){

  let response = await returnPromise();

  let response2 = await returnPromise2();

  console.log(response, response2)

}

getExample()

and run the file with:并使用以下命令运行文件:

node --harmony-async-await getExample.js

Simple as can be!尽可能简单!

Another answer, using babel-node version <6另一个答案,使用babel-node版本 <6

Using async - await使用async - await

npm install -g babel@5.6.14

example.js:

async function getExample(){

  let response = await returnPromise();

  let response2 = await returnPromise2();

  console.log(response, response2)

}

getExample()

Then, run babel-node example.js and voila!然后,运行babel-node example.js ,瞧!

This days, I also hava meet some questions like you.这几天,我也遇到了一些像你一样的问题。 At last, I find a good solution with the quesition, it's simple and good to read.最后,我找到了一个很好的解决方案,简单易读。 I hope this can help you.我希望这可以帮助你。

According to how-to-chain-javascript-promises根据how-to-chain-javascript-promises

ok, let's look at the code:好的,让我们看一下代码:

const firstPromise = () => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('first promise is completed');
            resolve({data: '123'});
        }, 2000);
    });
};

const secondPromise = (someStuff) => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('second promise is completed');
            resolve({newData: `${someStuff.data} some more data`});
        }, 2000);
    });
};

const thirdPromise = (someStuff) => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('third promise is completed');
            resolve({result: someStuff});
        }, 2000);
    });
};

firstPromise()
    .then(secondPromise)
    .then(thirdPromise)
    .then(data => {
        console.log(data);
    });

I am not going to use this pattern in my own code since I'm not a big fan of using global variables.我不会在我自己的代码中使用这种模式,因为我不是使用全局变量的忠实粉丝。 However, in a pinch it will work.但是,在紧要关头它会起作用。

User is a promisified Mongoose model.用户是一个承诺的猫鼬模型。

var globalVar = '';

User.findAsync({}).then(function(users){
  globalVar = users;
}).then(function(){
  console.log(globalVar);
});

Another answer, using sequential executor nsynjs :另一个答案,使用顺序执行程序nsynjs

function getExample(){

  var response1 = returnPromise1().data;

  // promise1 is resolved at this point, '.data' has the result from resolve(result)

  var response2 = returnPromise2().data;

  // promise2 is resolved at this point, '.data' has the result from resolve(result)

  console.log(response, response2);

}

nynjs.run(getExample,{},function(){
    console.log('all done');
})

Update: added working example更新:添加了工作示例

 function synchronousCode() { var urls=[ "https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js", "https://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js", "https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js" ]; for(var i=0; i<urls.length; i++) { var len=window.fetch(urls[i]).data.text().data.length; // ^ ^ // | +- 2-nd promise result // | assigned to 'data' // | // +-- 1-st promise result assigned to 'data' // console.log('URL #'+i+' : '+urls[i]+", length: "+len); } } nsynjs.run(synchronousCode,{},function(){ console.log('all done'); })
 <script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>

When using bluebird, you can use .bind method to share variables in promise chain:使用 bluebird 时,您可以使用.bind方法在承诺链中共享变量:

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;
});

please check this link for further information:请查看此链接以获取更多信息:

http://bluebirdjs.com/docs/api/promise.bind.html http://bluebirdjs.com/docs/api/promise.bind.html

function getExample() {
    var retA, retB;
    return promiseA(…).then(function(resultA) {
        retA = resultA;
        // Some processing
        return promiseB(…);
    }).then(function(resultB) {
        // More processing
        //retA is value of promiseA
        return // How do I gain access to resultA here?
    });
}

easy way :D简单的方法:D

I think you can use hash of RSVP.我认为您可以使用 RSVP 的哈希值。

Something like as below :如下所示:

    const mainPromise = () => {
        const promise1 = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log('first promise is completed');
                resolve({data: '123'});
            }, 2000);
        });

        const promise2 = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log('second promise is completed');
                resolve({data: '456'});
            }, 2000);
        });

        return new RSVP.hash({
              prom1: promise1,
              prom2: promise2
          });

    };


   mainPromise()
    .then(data => {
        console.log(data.prom1);
        console.log(data.prom2);
    });

Solution:解决方案:

You can put intermediate values in scope in any later 'then' function explicitly, by using 'bind'.您可以使用“bind”显式地将中间值放入任何以后的“then”函数的范围内。 It is a nice solution that doesn't require changing how Promises work, and only requires a line or two of code to propagate the values just like errors are already propagated.这是一个很好的解决方案,不需要改变 Promise 的工作方式,只需要一两行代码来传播值,就像错误已经传播一样。

Here is a complete example:这是一个完整的例子:

// Get info asynchronously from a server
function pGetServerInfo()
    {
    // then value: "server info"
    } // pGetServerInfo

// Write into a file asynchronously
function pWriteFile(path,string)
    {
    // no then value
    } // pWriteFile

// The heart of the solution: Write formatted info into a log file asynchronously,
// using the pGetServerInfo and pWriteFile operations
function pLogInfo(localInfo)
    {
    var scope={localInfo:localInfo}; // Create an explicit scope object
    var thenFunc=p2.bind(scope); // Create a temporary function with this scope
    return (pGetServerInfo().then(thenFunc)); // Do the next 'then' in the chain
    } // pLogInfo

// Scope of this 'then' function is {localInfo:localInfo}
function p2(serverInfo)
    {
    // Do the final 'then' in the chain: Writes "local info, server info"
    return pWriteFile('log',this.localInfo+','+serverInfo);
    } // p2

This solution can be invoked as follows:可以按如下方式调用此解决方案:

pLogInfo("local info").then().catch(err);

(Note: a more complex and complete version of this solution has been tested, but not this example version, so it could have a bug.) (注意:这个解决方案的一个更复杂和完整的版本已经过测试,但不是这个示例版本,所以它可能有一个错误。)

What I learn about promises is to use it only as return values avoid referencing them if possible.我对 Promise 的了解是仅将其用作返回值如果可能,避免引用它们 async/await syntax is particularly practical for that. async/await 语法对此特别实用。 Today all latest browsers and node support it: https://caniuse.com/#feat=async-functions , is a simple behavior and the code is like reading synchronous code, forget about callbacks...今天所有最新的浏览器和节点都支持它: https://caniuse.com/#feat=async-functions ,是一个简单的行为,代码就像阅读同步代码,忘记回调......

In cases I do need to reference a promises is when creation and resolution happen at independent/not-related places.在我确实需要引用承诺的情况下,创建和解析发生在独立/不相关的地方。 So instead an artificial association and probably an event listener just to resolve the "distant" promise, I prefer to expose the promise as a Deferred, which the following code implements it in valid es5因此,取而代之的是人工关联和事件侦听器只是为了解决“遥远”的承诺,我更喜欢将承诺公开为延迟,以下代码在有效的 es5 中实现它

/**
 * Promise like object that allows to resolve it promise from outside code. Example:
 *
```
class Api {
  fooReady = new Deferred<Data>()
  private knower() {
    inOtherMoment(data=>{
      this.fooReady.resolve(data)
    })
  }
}
```
 */
var Deferred = /** @class */ (function () {
  function Deferred(callback) {
    var instance = this;
    this.resolve = null;
    this.reject = null;
    this.status = 'pending';
    this.promise = new Promise(function (resolve, reject) {
      instance.resolve = function () { this.status = 'resolved'; resolve.apply(this, arguments); };
      instance.reject = function () { this.status = 'rejected'; reject.apply(this, arguments); };
    });
    if (typeof callback === 'function') {
      callback.call(this, this.resolve, this.reject);
    }
  }
  Deferred.prototype.then = function (resolve) {
    return this.promise.then(resolve);
  };
  Deferred.prototype.catch = function (r) {
    return this.promise.catch(r);
  };
  return Deferred;
}());

transpiled form a typescript project of mine:从我的打字稿项目转译:

https://github.com/cancerberoSgx/misc-utils-of-mine/blob/2927c2477839f7b36247d054e7e50abe8a41358b/misc-utils-of-mine-generic/src/promise.ts#L31 https://github.com/cancerberoSgx/misc-utils-of-mine/blob/2927c2477839f7b36247d054e7e50abe8a41358b/misc-utils-of-mine-generic/src/promise.ts#L31

For more complex cases I often use these guy small promise utilities without dependencies tested and typed.对于更复杂的情况,我经常使用这些没有测试和输入依赖项的小型承诺实用程序。 p-map has been useful several times. p-map 已经有用了好几次了。 I think he covered most use cases:我认为他涵盖了大多数用例:

https://github.com/sindresorhus?utf8=%E2%9C%93&tab=repositories&q=promise&type=source&language= https://github.com/sindresorhus?utf8=%E2%9C%93&tab=repositories&q=promise&type=source&language=

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM