为了账号安全,请及时绑定邮箱和手机立即绑定

同步调用异步Javascript函数

同步调用异步Javascript函数

墨色风雨 2019-07-26 14:39:40
同步调用异步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中可以做到这样的话。
查看完整描述

3 回答

?
慕哥6287543

TA贡献1831条经验 获得超10个赞

“不要告诉我应该怎么做”正确的方式“或其他什么”

好。但你应该以正确的方式做到......或者其他什么

“我需要一个具体的例子来说明如何阻止它......没有冻结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);


查看完整回答
反对 回复 2019-07-26
?
侃侃无极

TA贡献2051条经验 获得超10个赞

异步功能ES2017中的一项功能,它通过使用promises(特定形式的异步代码)和await关键字使异步代码看起来同步。另请注意下面的代码示例中关键字async前面的function关键字,表示async / await函数。如果await没有使用关键字预先修复的功能,关键字将无法使用async。由于目前没有例外,这意味着没有顶级等待可以工作(顶级等待意味着等待任何功能之外)。虽然有顶级await提案

ES2017于2017年6月27日被批准(即最终确定)作为JavaScript的标准。异步等待可能已经在您的浏览器中工作,但如果没有,您仍然可以使用像babeltraceur这样的javascript转换器来使用该功能。Chrome 55完全支持异步功能。因此,如果您有更新的浏览器,您可以尝试下面的代码。

有关浏览器兼容性,请参阅kangax的es2017兼容性表

这是一个示例async await函数调用doAsync,它占用三秒钟的暂停时间,并在每次暂停后从开始时间打印时间差:

function timeoutPromise (time) {
  return new Promise(function (resolve) {
    setTimeout(function () {
      resolve(Date.now());
    }, time)
  })}function doSomethingAsync () {
  return timeoutPromise(1000);}async function doAsync () {
  var start = Date.now(), time;
  console.log(0);
  time = await doSomethingAsync();
  console.log(time - start);
  time = await doSomethingAsync();
  console.log(time - start);
  time = await doSomethingAsync();
  console.log(time - start);}doAsync();

当await关键字放在promise值之前(在这种情况下,promise值是函数doSomethingAsync返回的值)await关键字将暂停执行函数调用,但它不会暂停任何其他函数,它将继续执行其他代码,直到promise解决。在promise解析之后,它将解包promise的值,你可以想到await和promise表达式现在被替换为unwrapped值。

因此,由于等待暂停等待然后在执行行的其余部分之前解开一个值,您可以在for循环和内部函数调用中使用它,如下例所示,它收集数组中等待的时间差并打印出数组。

function timeoutPromise (time) {
  return new Promise(function (resolve) {
    setTimeout(function () {
      resolve(Date.now());
    }, time)
  })}function doSomethingAsync () {
  return timeoutPromise(1000);}// this calls each promise returning function one after the otherasync function doAsync () {
  var response = [];
  var start = Date.now();
  // each index is a promise returning function
  var promiseFuncs= [doSomethingAsync, doSomethingAsync, doSomethingAsync];
  for(var i = 0; i < promiseFuncs.length; ++i) {
    var promiseFunc = promiseFuncs[i];
    response.push(await promiseFunc() - start);
    console.log(response);
  }
  // do something with response which is an array of values that were from resolved promises.
  return response}doAsync().then(function (response) {
  console.log(response)})

异步函数本身返回一个promise,因此您可以将其用作链接,就像我在上面或在另一个async await函数中一样。

如果你想同时发送请求你可以使用Promise.all,上面的函数会在发送另一个请求之前等待每个响应。

// no changefunction timeoutPromise (time) {
  return new Promise(function (resolve) {
    setTimeout(function () {
      resolve(Date.now());
    }, time)
  })}// no changefunction doSomethingAsync () {
  return timeoutPromise(1000);}// this function calls the async promise returning functions all at around the same timeasync function doAsync () {
  var start = Date.now();
  // we are now using promise all to await all promises to settle
  var responses = await Promise.all([doSomethingAsync(), doSomethingAsync(), doSomethingAsync()]);
  return responses.map(x=>x-start);}// no changedoAsync().then(function (response) {
  console.log(response)})

如果promise可能拒绝你可以将它包装在try catch中或跳过try catch并让错误传播到async / await函数catch调用。你应该注意不要留下未处理的promise错误,特别是在Node.js. 下面是一些展示错误如何工作的示例。

function timeoutReject (time) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      reject(new Error("OOPS well you got an error at TIMESTAMP: " + Date.now()));
    }, time)
  })}function doErrorAsync () {
  return timeoutReject(1000);}var log = (...args)=>console.log(...args);var logErr = (...args)=>console.error(...args);async function unpropogatedError () {
  // promise is not awaited or returned so it does not propogate the error
  doErrorAsync();
  return "finished unpropogatedError successfully";}unpropogatedError().then(log).catch(logErr)async function handledError () {
  var start = Date.now();
  try {
    console.log((await doErrorAsync()) - start);
    console.log("past error");
  } catch (e) {
    console.log("in catch we handled the error");
  }
  
  return "finished handledError successfully";}handledError().then(log).catch(logErr)// example of how error propogates to chained catch methodasync function propogatedError () {
  var start = Date.now();
  var time = await doErrorAsync() - start;
  console.log(time - start);
  return "finished propogatedError successfully";}// this is what prints propogatedError's 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功能。


查看完整回答
反对 回复 2019-07-26
  • 3 回答
  • 0 关注
  • 1049 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信