DA.*_*DA. 144 javascript jquery delay pausing-execution
我有两个JS函数.一个叫另一个.在调用函数中,我想调用另一个,等待该函数完成,然后继续.所以,例如/伪代码:
function firstFunction(){
for(i=0;i<x;i++){
// do something
}
};
function secondFunction(){
firstFunction()
// now wait for firstFunction to finish...
// do something else
};
Run Code Online (Sandbox Code Playgroud)
我提出了这个解决方案,但不知道这是否是一个聪明的方法.
var isPaused = false;
function firstFunction(){
isPaused = true;
for(i=0;i<x;i++){
// do something
}
isPaused = false;
};
function secondFunction(){
firstFunction()
function waitForIt(){
if (isPaused) {
setTimeout(function(){waitForIt()},100);
} else {
// go do that thing
};
}
};
Run Code Online (Sandbox Code Playgroud)
这是合法的吗?是否有更优雅的方式来处理它?也许用jQuery?
Mat*_*Way 118
处理这种异步工作的一种方法是使用回调函数,例如:
function firstFunction(_callback){
// do some asynchronous work
// and when the asynchronous stuff is complete
_callback();
}
function secondFunction(){
// call first function and pass in a callback function which
// first function runs when it has completed
firstFunction(function() {
console.log('huzzah, I\'m done!');
});
}
Run Code Online (Sandbox Code Playgroud)
根据@Janaka Pushpakumara的建议,您现在可以使用箭头功能来实现相同的功能.例如:
firstFunction(() => console.log('huzzah, I\'m done!'))
nos*_*tio 47
看来你在这里忽略了一个重点:JavaScript是一个单线程执行环境.让我们再看一下你的代码,注意我已添加alert("Here"):
var isPaused = false;
function firstFunction(){
isPaused = true;
for(i=0;i<x;i++){
// do something
}
isPaused = false;
};
function secondFunction(){
firstFunction()
alert("Here");
function waitForIt(){
if (isPaused) {
setTimeout(function(){waitForIt()},100);
} else {
// go do that thing
};
}
};
Run Code Online (Sandbox Code Playgroud)
你不必等待isPaused.当您看到"此处"警报时,isPaused将会false已经firstFunction返回.那是因为你不能从for循环(// do something)内部"屈服" ,循环可能不会被中断并且必须首先完全完成(更多细节:Javascript线程处理和竞争条件).
也就是说,您仍然可以使内部的代码流firstFunction为异步,并使用回调或promise来通知调用者.你必须放弃for循环并用它if来模拟它(JSFiddle):
function firstFunction()
{
var deferred = $.Deferred();
var i = 0;
var nextStep = function() {
if (i<10) {
// Do something
printOutput("Step: " + i);
i++;
setTimeout(nextStep, 500);
}
else {
deferred.resolve(i);
}
}
nextStep();
return deferred.promise();
}
function secondFunction()
{
var promise = firstFunction();
promise.then(function(result) {
printOutput("Result: " + result);
});
}
Run Code Online (Sandbox Code Playgroud)
另外,JavaScript 1.7引入了yield关键字作为生成器的一部分.这将允许在其他同步JavaScript代码流中"打击"异步漏洞(更多细节和示例).但是,浏览器对生成器的支持目前仅限于Firefox和Chrome,AFAIK.
Faw*_*waz 38
使用async/await:
async function firstFunction(){
for(i=0;i<x;i++){
// do something
}
return;
};
Run Code Online (Sandbox Code Playgroud)
然后在你的其他函数中使用await来等待它返回:
async function secondFunction(){
await firstFunction();
// now wait for firstFunction to finish...
// do something else
};
Run Code Online (Sandbox Code Playgroud)
dav*_*rad 13
我想知道为什么没有人提到这个简单的模式?:
(function(next) {
//do something
next()
}(function() {
//do some more
}))
Run Code Online (Sandbox Code Playgroud)
仅仅为了盲目等待而使用超时是不好的做法;并涉及承诺只会增加代码的复杂性。在 OP 的情况下:
(function(next) {
for(i=0;i<x;i++){
// do something
if (i==x-1) next()
}
}(function() {
// now wait for firstFunction to finish...
// do something else
}))
Run Code Online (Sandbox Code Playgroud)
一个小演示 -> http://jsfiddle.net/5jdeb93r/
等待一个功能首先完成的一种优雅方法是将Promises与async / await函数一起使用。
快速示例:
let firstFunction = new Promise(function(resolve, reject) {
let x = 10
let y = 0
setTimeout(function(){
for(i=0;i<x;i++){
y++
}
console.log('loop completed')
resolve(y)
}, 2000)
})
Run Code Online (Sandbox Code Playgroud)
首先,创建一个Promise。上面的功能将在2秒钟后完成。我用来setTimeout演示指令需要花费一些时间的情况(根据您的示例)。
async function secondFunction(){
let result = await firstFunction
console.log(result)
console.log('next step')
};
secondFunction()
Run Code Online (Sandbox Code Playgroud)
对于第二个功能,您可以使用异步/等待功能,在继续执行说明之前,您将等待第一个功能完成。
注意:您可以简单地解决Promise,而无需像so这样的任何值resolve()。在我的示例中,我解决了Promise的值,y然后可以在第二个函数中使用该值。
希望它对仍然访问此线程的人有所帮助。
可以使用Promise
Promise 是一种 JavaScript 构造,代表未来的未知值。它可能是 API 调用的结果,也可能是失败的网络请求的错误对象。你一定会得到一些东西。
const promise = new Promise((resolve, reject) => {
// Make a network request
if (yourcondition=="value") {
} else {
reject(error);
}
})
promise.then(res => {
//if not rejected, code
}).catch(err => {
//return false;
})
Run Code Online (Sandbox Code Playgroud)
一个承诺可以有
已完成 - 操作成功完成
被拒绝 - 操作失败
待处理 - 两项操作均尚未完成
已解决 - 已履行或拒绝
承诺的唯一问题是IE不支持它们。Edge确实有,但是有很多IE 10和11:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise(底部兼容)
因此,JavaScript是单线程的。如果您不进行异步调用,它将可以预期地运行。JavaScript主线程将按执行顺序在代码中出现的顺序完全执行一个功能。保证同步功能的顺序很简单-每个功能将完全按照其调用的顺序执行。
将同步功能视为工作的原子单元。JavaScript主线程将按照语句在代码中出现的顺序完全执行它。
但是,引发异步调用,如下所示:
showLoadingDiv(); // function 1
makeAjaxCall(); // function 2 - contains async ajax call
hideLoadingDiv(); // function 3
Run Code Online (Sandbox Code Playgroud)
这并不能满足您的要求。它立即执行功能1,功能2和功能3。尽管ajax调用makeAjaxCall()返回了,但它几乎没有完成,而加载div闪烁并消失了。复杂之处在于,makeAjaxCall()将其工作分解为多个块,每个主要JavaScript线程的每次旋转都会逐步推进这些块 -它的行为是不同步的。但是,同一主线程在一次旋转/运行期间可以快速且可预测地执行同步部分。
因此,我的处理方式:就像我说的那样,函数是工作的原子单元。我将函数1和2的代码合并在一起-在异步调用之前,将函数1的代码放入函数2中。我摆脱了函数1。直到异步调用为止的所有工作都可以按顺序执行。
然后,在异步调用完成后,在主JavaScript线程旋转几次之后,让其调用函数3。这样可以保证顺序。例如,对于ajax,onreadystatechange事件处理程序被多次调用。报告完成后,请调用所需的最终函数。
我同意这比较麻烦。我喜欢让代码对称,我喜欢让函数做一件事情(或接近它),而且我不喜欢让ajax调用以任何方式负责显示(对调用者产生依赖性)。但是,将异步调用嵌入到同步函数中,因此必须做出折衷以保证执行顺序。而且我必须为IE 10编写代码,所以没有任何希望。
摘要:对于同步呼叫,保证顺序很简单。每个函数均按其调用顺序完全执行。对于具有异步调用的函数,保证顺序的唯一方法是监视异步调用何时完成,并在检测到该状态时调用第三个函数。
有关JavaScript线程的讨论,请参见:https : //medium.com/@francesco_rizzi/javascript-main-thread-dissected-43c85fce7e23和https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/事件循环
另外,与此主题相关的另一个类似的,评分很高的问题:我应该如何调用3个函数才能一个接一个地执行它们?