3 回答
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);
TA贡献2051条经验 获得超10个赞
异步功能是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 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功能。
添加回答
举报