链式JavaScript本机承诺:执行顺序不可预测

时间:2018-05-07 23:13:07

标签: javascript es6-promise

我有一个流程,我需要非常可控地执行代码的异步部分。具体来说,我有一个node个项目的链接列表,每个项目都必须按照它们在链接列表中出现的顺序进行评估。但是,某些类型的节点需要评估异步调用。所以,我这样做:

    function getTheValueOfOneNodeThatMayNeedAnSyncCall (oneNode) {
        return new Promise (function (resolve, reject) {
    	if (isSpecialTypeThatNeedsAsyncCall (oneNode)) { // Function TBD
	        oneAsyncCallDefinedInAModule (oneNode) // Function TBD, 
   returns promise
	    	.then (function (result) {
		        resolve (result);
      		})
	    	.catch (function (error) {
		    reject (new Error ("The async call could not be evaluated"));
		});
	} else {
	    resolve (oneNode);
	}
    });
};

function evaluateAStackInOrder (pSimpleExpression) {
    // pSimpleExpression E.g.: node1->node2->node3->node4->node5->null (a linked list)
    var computedAsyncsInOrder = [];
    var result = false;
    let oneNodeProcessedPromise = Promise.resolve ();
    pSimpleExpression.traverse (function (oneNode) {
	oneNodeProcessedPromise = oneNodeProcessedPromise.
	    then (function () {
		getTheValueOfOneNodeThatMayNeedAnSyncCall (oneNode)
		    .then (function (nodeVal) {
			computedAsyncsInOrder.push (nodeVal);
			console.log ("Pushed " + nodeVal + " and stack is now " + computedAsyncsInOrder);
			return;
		    })
		    .catch (function (error) {
			console.log ("Error:\n" + error.message);
			return;
		    });
	    })
	    .catch (function (error) {
		console.log ("Error processing this oneNode");
		return;
	    });
    }); // End of pSimpleExpression.traverse ();
    
    // Compute the final result
    oneNodeProcessedPromise.
	then (function () {
	    result = 
		computeTheFinalResultFromOrderedAsyncs (computedAsyncsInOrder);
	    return;
	})
	.catch (function (error) {
	    console.log ("Error processing final result of Simple expression");
	});

    return result;
};

我遇到的问题是调用没有按顺序执行。具体来说,无需等待异步调用完成(它们通过REST调用调用request来评估节点值),程序将运行完成,从而导致错误结果。

有关正在发生的事情的指示?我的承诺构建链接执行顺序是否正确?

1 个答案:

答案 0 :(得分:3)

使用ES7的AsyncAwait以及递归,此操作会更清晰。

文档:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

假设您不需要返回任何内容,您可以执行以下操作:

async function executeInOrder(myLinkedList) {
    // if head is null (falsey)
    if (!myLinkedList.head)
      return;

    // Halt execution until this operation is done
    await myLinkedList.head.possibleAsyncFunction();

    // Set the new head
    myLinkedList.head = mylinkedList.head.next;

    // Again...
    return executeInOrder(myLinkedList);
}

然后你可以使用它:

executeInOrder(myLinkedList)
  .then(() => doSomethingAfterwards())
  .catch((err) => handleError(err));

或者,如果您只有一个需要循环的节点列表,您可以这样做:

async function executeInOrder(list) {    
  await Promise.all(list.map(async (node) => {
    await node.possibleAsyncFunction();
  }));
}