同步调用异步Javascript函数

同步调用异步Javascript函数

首先,这是一个非常具体的例子,它将错误的方式用于将异步调用改造成一个非常同步的代码库,该代码库有数千行,而且时间目前还没有能力对“执行”进行更改对的。” 它伤害了我生命中的每一根纤维,但现实和理想往往不会啮合。我知道这很糟糕。

好的,那个方法,我怎么做到这样我可以:

function doSomething() {

  var data;

  function callBack(d) {
    data = d;
  }

  myAsynchronousCall(param1, callBack);

  // block here and return data when the callback is finished
  return data;}

示例(或缺少)都使用库和/或编译器,这两者对于该解决方案都不可行。我需要一个如何使其阻塞的具体示例(例如,在调用回调之前不要离开doSomething函数)不要冻结UI。如果在JS中可以做到这样的话。


墨色风雨
浏览 1050回答 3
3回答

慕哥6287543

“不要告诉我应该怎么做”正确的方式“或其他什么”好。但你应该以正确的方式做到......或者其他什么“我需要一个具体的例子来说明如何阻止它......没有冻结UI。如果在JS中可以做到这样的话。”不,在不阻止UI的情况下阻止正在运行的JavaScript是不可能的。由于缺乏信息,很难提供解决方案,但一种选择可能是让调用函数进行一些轮询以检查全局变量,然后将回调设置data为全局变量。function doSomething() {       // callback sets the received data to a global var   function callBack(d) {       window.data = d;   }       // start the async   myAsynchronousCall(param1, callBack);}   // start the functiondoSomething();   // make sure the global is clearwindow.data = null   // start polling at an interval until the data is found at the globalvar intvl = setInterval(function() {     if (window.data) {          clearInterval(intvl);         console.log(data);     }}, 100);所有这些都假定您可以修改doSomething()。我不知道这是不是卡片。如果它可以修改,那么我不知道为什么你不会只是通过回调来doSomething()从另一个回调调用,但我最好在遇到麻烦之前停止。;)哦,到底是什么。您举了一个示例,表明它可以正确完成,所以我将展示该解决方案......function doSomething( func ) {   function callBack(d) {     func( d );   }   myAsynchronousCall(param1, callBack);}doSomething(function(data) {     console.log(data);});因为您的示例包含传递给异步调用的回调,所以正确的方法是将函数传递doSomething()给要从回调调用。当然如果这是回调唯一做的事情,你只需func直接传递......myAsynchronousCall(param1, func);

侃侃无极

异步功能是ES2017中的一项功能,它通过使用promises(特定形式的异步代码)和await关键字使异步代码看起来同步。另请注意下面的代码示例中关键字async前面的function关键字,表示async / await函数。如果await没有使用关键字预先修复的功能,关键字将无法使用async。由于目前没有例外,这意味着没有顶级等待可以工作(顶级等待意味着等待任何功能之外)。虽然有顶级await的提案。ES2017于2017年6月27日被批准(即最终确定)作为JavaScript的标准。异步等待可能已经在您的浏览器中工作,但如果没有,您仍然可以使用像babel或traceur这样的javascript转换器来使用该功能。Chrome 55完全支持异步功能。因此,如果您有更新的浏览器,您可以尝试下面的代码。有关浏览器兼容性,请参阅kangax的es2017兼容性表。这是一个示例async await函数调用doAsync,它占用三秒钟的暂停时间,并在每次暂停后从开始时间打印时间差:function&nbsp;timeoutPromise&nbsp;(time)&nbsp;{ &nbsp;&nbsp;return&nbsp;new&nbsp;Promise(function&nbsp;(resolve)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;setTimeout(function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resolve(Date.now()); &nbsp;&nbsp;&nbsp;&nbsp;},&nbsp;time) &nbsp;&nbsp;})}function&nbsp;doSomethingAsync&nbsp;()&nbsp;{ &nbsp;&nbsp;return&nbsp;timeoutPromise(1000);}async&nbsp;function&nbsp;doAsync&nbsp;()&nbsp;{ &nbsp;&nbsp;var&nbsp;start&nbsp;=&nbsp;Date.now(),&nbsp;time; &nbsp;&nbsp;console.log(0); &nbsp;&nbsp;time&nbsp;=&nbsp;await&nbsp;doSomethingAsync(); &nbsp;&nbsp;console.log(time&nbsp;-&nbsp;start); &nbsp;&nbsp;time&nbsp;=&nbsp;await&nbsp;doSomethingAsync(); &nbsp;&nbsp;console.log(time&nbsp;-&nbsp;start); &nbsp;&nbsp;time&nbsp;=&nbsp;await&nbsp;doSomethingAsync(); &nbsp;&nbsp;console.log(time&nbsp;-&nbsp;start);}doAsync();当await关键字放在promise值之前(在这种情况下,promise值是函数doSomethingAsync返回的值)await关键字将暂停执行函数调用,但它不会暂停任何其他函数,它将继续执行其他代码,直到promise解决。在promise解析之后,它将解包promise的值,你可以想到await和promise表达式现在被替换为unwrapped值。因此,由于等待暂停等待然后在执行行的其余部分之前解开一个值,您可以在for循环和内部函数调用中使用它,如下例所示,它收集数组中等待的时间差并打印出数组。function&nbsp;timeoutPromise&nbsp;(time)&nbsp;{ &nbsp;&nbsp;return&nbsp;new&nbsp;Promise(function&nbsp;(resolve)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;setTimeout(function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resolve(Date.now()); &nbsp;&nbsp;&nbsp;&nbsp;},&nbsp;time) &nbsp;&nbsp;})}function&nbsp;doSomethingAsync&nbsp;()&nbsp;{ &nbsp;&nbsp;return&nbsp;timeoutPromise(1000);}//&nbsp;this&nbsp;calls&nbsp;each&nbsp;promise&nbsp;returning&nbsp;function&nbsp;one&nbsp;after&nbsp;the&nbsp;otherasync&nbsp;function&nbsp;doAsync&nbsp;()&nbsp;{ &nbsp;&nbsp;var&nbsp;response&nbsp;=&nbsp;[]; &nbsp;&nbsp;var&nbsp;start&nbsp;=&nbsp;Date.now(); &nbsp;&nbsp;//&nbsp;each&nbsp;index&nbsp;is&nbsp;a&nbsp;promise&nbsp;returning&nbsp;function &nbsp;&nbsp;var&nbsp;promiseFuncs=&nbsp;[doSomethingAsync,&nbsp;doSomethingAsync,&nbsp;doSomethingAsync]; &nbsp;&nbsp;for(var&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;<&nbsp;promiseFuncs.length;&nbsp;++i)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;promiseFunc&nbsp;=&nbsp;promiseFuncs[i]; &nbsp;&nbsp;&nbsp;&nbsp;response.push(await&nbsp;promiseFunc()&nbsp;-&nbsp;start); &nbsp;&nbsp;&nbsp;&nbsp;console.log(response); &nbsp;&nbsp;} &nbsp;&nbsp;//&nbsp;do&nbsp;something&nbsp;with&nbsp;response&nbsp;which&nbsp;is&nbsp;an&nbsp;array&nbsp;of&nbsp;values&nbsp;that&nbsp;were&nbsp;from&nbsp;resolved&nbsp;promises. &nbsp;&nbsp;return&nbsp;response}doAsync().then(function&nbsp;(response)&nbsp;{ &nbsp;&nbsp;console.log(response)})异步函数本身返回一个promise,因此您可以将其用作链接,就像我在上面或在另一个async await函数中一样。如果你想同时发送请求你可以使用Promise.all,上面的函数会在发送另一个请求之前等待每个响应。//&nbsp;no&nbsp;changefunction&nbsp;timeoutPromise&nbsp;(time)&nbsp;{ &nbsp;&nbsp;return&nbsp;new&nbsp;Promise(function&nbsp;(resolve)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;setTimeout(function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resolve(Date.now()); &nbsp;&nbsp;&nbsp;&nbsp;},&nbsp;time) &nbsp;&nbsp;})}//&nbsp;no&nbsp;changefunction&nbsp;doSomethingAsync&nbsp;()&nbsp;{ &nbsp;&nbsp;return&nbsp;timeoutPromise(1000);}//&nbsp;this&nbsp;function&nbsp;calls&nbsp;the&nbsp;async&nbsp;promise&nbsp;returning&nbsp;functions&nbsp;all&nbsp;at&nbsp;around&nbsp;the&nbsp;same&nbsp;timeasync&nbsp;function&nbsp;doAsync&nbsp;()&nbsp;{ &nbsp;&nbsp;var&nbsp;start&nbsp;=&nbsp;Date.now(); &nbsp;&nbsp;//&nbsp;we&nbsp;are&nbsp;now&nbsp;using&nbsp;promise&nbsp;all&nbsp;to&nbsp;await&nbsp;all&nbsp;promises&nbsp;to&nbsp;settle &nbsp;&nbsp;var&nbsp;responses&nbsp;=&nbsp;await&nbsp;Promise.all([doSomethingAsync(),&nbsp;doSomethingAsync(),&nbsp;doSomethingAsync()]); &nbsp;&nbsp;return&nbsp;responses.map(x=>x-start);}//&nbsp;no&nbsp;changedoAsync().then(function&nbsp;(response)&nbsp;{ &nbsp;&nbsp;console.log(response)})如果promise可能拒绝你可以将它包装在try catch中或跳过try catch并让错误传播到async / await函数catch调用。你应该注意不要留下未处理的promise错误,特别是在Node.js.&nbsp;下面是一些展示错误如何工作的示例。function&nbsp;timeoutReject&nbsp;(time)&nbsp;{ &nbsp;&nbsp;return&nbsp;new&nbsp;Promise(function&nbsp;(resolve,&nbsp;reject)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;setTimeout(function&nbsp;()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;reject(new&nbsp;Error("OOPS&nbsp;well&nbsp;you&nbsp;got&nbsp;an&nbsp;error&nbsp;at&nbsp;TIMESTAMP:&nbsp;"&nbsp;+&nbsp;Date.now())); &nbsp;&nbsp;&nbsp;&nbsp;},&nbsp;time) &nbsp;&nbsp;})}function&nbsp;doErrorAsync&nbsp;()&nbsp;{ &nbsp;&nbsp;return&nbsp;timeoutReject(1000);}var&nbsp;log&nbsp;=&nbsp;(...args)=>console.log(...args);var&nbsp;logErr&nbsp;=&nbsp;(...args)=>console.error(...args);async&nbsp;function&nbsp;unpropogatedError&nbsp;()&nbsp;{ &nbsp;&nbsp;//&nbsp;promise&nbsp;is&nbsp;not&nbsp;awaited&nbsp;or&nbsp;returned&nbsp;so&nbsp;it&nbsp;does&nbsp;not&nbsp;propogate&nbsp;the&nbsp;error &nbsp;&nbsp;doErrorAsync(); &nbsp;&nbsp;return&nbsp;"finished&nbsp;unpropogatedError&nbsp;successfully";}unpropogatedError().then(log).catch(logErr)async&nbsp;function&nbsp;handledError&nbsp;()&nbsp;{ &nbsp;&nbsp;var&nbsp;start&nbsp;=&nbsp;Date.now(); &nbsp;&nbsp;try&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;console.log((await&nbsp;doErrorAsync())&nbsp;-&nbsp;start); &nbsp;&nbsp;&nbsp;&nbsp;console.log("past&nbsp;error"); &nbsp;&nbsp;}&nbsp;catch&nbsp;(e)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;console.log("in&nbsp;catch&nbsp;we&nbsp;handled&nbsp;the&nbsp;error"); &nbsp;&nbsp;} &nbsp;&nbsp; &nbsp;&nbsp;return&nbsp;"finished&nbsp;handledError&nbsp;successfully";}handledError().then(log).catch(logErr)//&nbsp;example&nbsp;of&nbsp;how&nbsp;error&nbsp;propogates&nbsp;to&nbsp;chained&nbsp;catch&nbsp;methodasync&nbsp;function&nbsp;propogatedError&nbsp;()&nbsp;{ &nbsp;&nbsp;var&nbsp;start&nbsp;=&nbsp;Date.now(); &nbsp;&nbsp;var&nbsp;time&nbsp;=&nbsp;await&nbsp;doErrorAsync()&nbsp;-&nbsp;start; &nbsp;&nbsp;console.log(time&nbsp;-&nbsp;start); &nbsp;&nbsp;return&nbsp;"finished&nbsp;propogatedError&nbsp;successfully";}//&nbsp;this&nbsp;is&nbsp;what&nbsp;prints&nbsp;propogatedError's&nbsp;error.propogatedError().then(log).catch(logErr)如果你去这里,你可以看到即将推出的ECMAScript版本的完成提案。可以与ES2015(ES6)一起使用的另一种方法是使用包含发生器功能的特殊功能。生成器函数有一个yield关键字,可用于复制带有周围函数的await关键字。yield关键字和生成器函数更通用,并且可以执行更多的事情,而不仅仅是async await函数所做的事情。如果你想要一台发电机的功能封装,可用于复制异步等待我想看看co.js。顺便说一下co的功能很像async await函数返回一个promise。老实说,虽然此时浏览器兼容性对于生成器函数和异步函数大致相同,因此如果您只想要异步等待功能,则应使用不带co.js的异步函数。对于IE以外的所有当前主流浏览器(Chrome,Safari和Edge),浏览器支持实际上非常适合Async功能。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript