Rob*_*rth 198 javascript asynchronous
首先,这是一个非常具体的例子,它将错误的方式用于将异步调用改造成一个非常同步的代码库,该代码库有数千行,而且时间目前还没有能力对"执行"进行更改对的." 它伤害了我生命中的每一根纤维,但现实和理想往往不会啮合.我知道这很糟糕.
好的,那个方法,我怎么做到这样我可以:
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中可以做到这样的话.
小智 128
"不要告诉我应该怎么做"正确的方式"或其他什么"
好.但你应该以正确的方式做到......或者其他什么
"我需要一个具体的例子来说明如何阻止它......没有冻结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 function
doSomething();
  // make sure the global is clear
window.data = null
  // start polling at an interval until the data is found at the global
var 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);
Joh*_*ohn 51
异步功能是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 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 other
async 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 change
function timeoutPromise (time) {
  return new Promise(function (resolve) {
    setTimeout(function () {
      resolve(Date.now());
    }, time)
  })
}
// no change
function doSomethingAsync () {
  return timeoutPromise(1000);
}
// this function calls the async promise returning functions all at around the same time
async 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 change
doAsync().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 method
async 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功能(截至2017年).
Mat*_*lor 47
看看JQuery Promises:
http://api.jquery.com/promise/
http://api.jquery.com/jQuery.when/
http://api.jquery.com/deferred.promise/
重构代码:
    var dfd = new jQuery.Deferred();
    function callBack(data) {
       dfd.notify(data);
    }
    // do the async call.
    myAsynchronousCall(param1, callBack);
    function doSomething(data) {
     // do stuff with data...
    }
    $.when(dfd).then(doSomething);
        http://taskjs.org/有一个很好的解决方法
它使用了javascript新手的生成器.因此目前大多数浏览器都没有实现它.我在firefox中测试过,对我来说这是包装异步函数的好方法.
这是项目GitHub的示例代码
var { Deferred } = task;
spawn(function() {
    out.innerHTML = "reading...\n";
    try {
        var d = yield read("read.html");
        alert(d.responseText.length);
    } catch (e) {
        e.stack.split(/\n/).forEach(function(line) { console.log(line) });
        console.log("");
        out.innerHTML = "error: " + e;
    }
});
function read(url, method) {
    method = method || "GET";
    var xhr = new XMLHttpRequest();
    var deferred = new Deferred();
    xhr.onreadystatechange = function() {
        if (xhr.readyState === 4) {
            if (xhr.status >= 400) {
                var e = new Error(xhr.statusText);
                e.status = xhr.status;
                deferred.reject(e);
            } else {
                deferred.resolve({
                    responseText: xhr.responseText
                });
            }
        }
    };
    xhr.open(method, url, true);
    xhr.send();
    return deferred.promise;
}
您可以强制 NodeJS 中的异步 JavaScript 与sync-rpc 同步。
不过,它肯定会冻结您的用户界面,所以当谈到是否可以采取您需要采取的快捷方式时,我仍然持反对意见。在 JavaScript 中挂起唯一线程是不可能的,即使 NodeJS 有时允许您阻止它。在您的承诺解决之前,任何回调,事件,任何异步都无法处理。因此,除非你的读者有像 OP 这样不可避免的情况(或者,在我的例子中,正在编写一个没有回调、事件等的美化 shell 脚本),不要这样做!
但您可以这样做:
./calling-file.js
var createClient = require('sync-rpc');
var mySynchronousCall = createClient(require.resolve('./my-asynchronous-call'), 'init data');
var param1 = 'test data'
var data = mySynchronousCall(param1);
console.log(data); // prints: received "test data" after "init data"
./my-asynchronous-call.js
function init(initData) {
  return function(param1) {
    // Return a promise here and the resulting rpc client will be synchronous
    return Promise.resolve('received "' + param1 + '" after "' + initData + '"');
  };
}
module.exports = init;
限制:
这些都是sync-rpc实现方式的结果,这是通过滥用require('child_process').spawnSync:
JSON.stringify,因此函数和不可枚举的属性(如原型链)将丢失。你想要的现在实际上是可能的。如果您可以在 Service Worker 中运行异步代码,并在 Web Worker 中运行同步代码,那么您可以让 Web Worker 向 Service Worker 发送同步 XHR,当 Service Worker 执行异步操作时,Web Worker 的线程将等待。这不是一个很好的方法,但它可以工作。
let result;
async_function().then(r => result = r);
while (result === undefined) // Wait result from async_function
    require('deasync').sleep(100);
| 归档时间: | 
 | 
| 查看次数: | 232943 次 | 
| 最近记录: |