Eu tenho algum código JavaScript que se parece com:
function statechangedPostQuestion()
{
//alert("statechangedPostQuestion");
if (xmlhttp.readyState==4)
{
var topicId = xmlhttp.responseText;
setTimeout("postinsql(topicId)",4000);
}
}
function postinsql(topicId)
{
//alert(topicId);
}
Eu recebo um erro que topicId
não está definido. Tudo estava funcionando antes de usar a setTimeout()
função.
Quero que minha postinsql(topicId)
função seja chamada depois de algum tempo. O que devo fazer?
javascript
parameters
callback
settimeout
Zeeshan Rang
fonte
fonte
Respostas:
Você precisa alimentar uma função anônima como parâmetro, em vez de uma string, o último método nem deve funcionar de acordo com a especificação ECMAScript, mas os navegadores são branda. Esta é a solução adequada, nunca dependa de passar uma string como uma 'função' ao usar
setTimeout()
ousetInterval()
, é mais lenta porque precisa ser avaliada e simplesmente não está certa.ATUALIZAR:
Como Hobblin disse em seus comentários à pergunta, agora você pode passar argumentos para a função dentro de setTimeout usando
Function.prototype.bind()
.Exemplo:
fonte
window.setTimeout
é um método DOM e, como tal, não é definido pela especificação ECMAScript. Passar uma string sempre funcionou nos navegadores e é um padrão de fato - na verdade, a capacidade de passar um objeto de função foi adicionada posteriormente, com JavaScript 1.2 - faz parte explicitamente da especificação de rascunho do HTML5 ( whatwg.org/specs/web -apps / trabalho atual / várias páginas /… ). No entanto, o uso de uma string em vez de um objeto de função geralmente é considerado um estilo ruim, porque é essencialmente uma forma de atrasoeval()
.Nos navegadores modernos, o "setTimeout" recebe um terceiro parâmetro que é enviado como parâmetro para a função interna no final do timer.
Exemplo:
Mais detalhes:
fonte
Depois de fazer algumas pesquisas e testes, a única implementação correta é:
setTimeout passará todos os parâmetros extras para sua função, para que possam ser processados lá.
A função anônima pode funcionar para coisas muito básicas, mas na instância de um objeto em que você precisa usar "this", não há como fazê-lo funcionar. Qualquer função anônima mudará "this" para apontar para a janela, assim você perderá a referência do objeto.
fonte
var that = this; setTimeout( function() { that.foo(); }, 1000);
Esta é uma pergunta muito antiga, com uma resposta já "correta", mas pensei em mencionar outra abordagem que ninguém mencionou aqui. Isso é copiado e colado da excelente biblioteca de sublinhados :
Você pode passar quantos argumentos quiser para a função chamada por setTimeout e, como um bônus adicional (normalmente, um bônus), o valor dos argumentos passados para sua função é congelado quando você chama setTimeout, portanto, se eles mudarem de valor em algum momento entre quando setTimeout () é chamado e quando atinge o tempo limite, bem ... isso não é mais tão terrivelmente frustrante :)
Aqui está um violino onde você pode ver o que quero dizer.
fonte
Recentemente, deparei-me com a situação única de precisar usar
setTimeout
um loop . Compreender isso pode ajudá-lo a entender como passar parâmetros parasetTimeout
.Método 1
Use
forEach
eObject.keys
, de acordo com a sugestão de Sukima :Eu recomendo este método.
Método 2
Use
bind
:JSFiddle: http://jsfiddle.net/MsBkW/
Método 3
Ou se você não pode usar
forEach
oubind
, use um IIFE :Método 4
Mas se você não se importa com o IE <10, pode usar a sugestão de Fabio :
Método 5 (ES6)
Use uma variável com escopo de bloco:
Embora eu ainda recomendo usar
Object.keys
comforEach
em ES6.fonte
.bind
não funcionará para o IE8 e abaixo [ref: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… ]. Acabei usando a solução de Schien: stackoverflow.com/a/21213723/1876899bind
, também está em um ambiente que ofereceObject.keys
eforEach
. Você pode perder o loop for e obter um escopo de função "livre" (como em dois pássaros com uma pedra livre e não livre de recursos) no processo.async
biblioteca ( github.com/caolan/async ). Nós o usamos extensivamente no Sails e tivemos ótimos resultados nos últimos 2 anos. Ele fornece métodos em ambos paralelo e em série para assíncronoforEach
,map
,reduce
, etcHobblin já comentou isso sobre a questão, mas deveria ser uma resposta mesmo!
Usar
Function.prototype.bind()
é a maneira mais limpa e flexível de fazer isso (com o bônus adicional de poder definir othis
contexto):Para obter mais informações, consulte estes links MDN:
https://developer.mozilla.org/en/docs/DOM/window.setTimeout#highlighter_547041 https://developer.mozilla.org/en/docs/JavaScript/Reference/Global_Objects/Function / bind # With_setTimeout
fonte
setTimeout(postinsql.bind(this, topicId), 4000);
bind
. É realmente um código legível.Algumas respostas estão corretas, mas complicadas.
Estou respondendo de novo, quatro anos depois, porque ainda encontro código muito complexo para resolver exatamente essa questão. Existe uma solução elegante.
Antes de tudo, não passe uma string como o primeiro parâmetro ao chamar setTimeout, porque efetivamente chama uma chamada para a lenta função "eval".
Então, como passamos um parâmetro para uma função de tempo limite? Usando o fechamento:
Alguns sugeriram o uso de função anônima ao chamar a função de tempo limite:
A sintaxe funciona. Mas quando settopic é chamado, ou seja, 4 segundos depois, o objeto XHR pode não ser o mesmo. Portanto, é importante pré-vincular as variáveis .
fonte
Minha resposta:
Explicação:
OU
Isso basicamente se converte em:
EDIT: Eu vi a mesma resposta, então olhe para a dele. Mas não roubei a resposta dele! Eu apenas esqueci de olhar. Leia a explicação e veja se isso ajuda a entender o código.
fonte
topicId
são alterados, o valor no tempo limite também muda. Um clone corrigiuSubstituir
com
ou melhor ainda, substitua a expressão da string por uma função anônima
EDITAR:
O comentário de Brownstone está incorreto, isso funcionará como pretendido, conforme demonstrado ao executá-lo no console do Firebug
Observe que estou de acordo com outras pessoas com as quais você deve evitar passar uma string,
setTimeout
pois isso chamaráeval()
a string e passará uma função.fonte
Você pode passar o parâmetro para a função de retorno de chamada setTimeout como:
setTimeout (função, milissegundos, param1, param2, ...)
por exemplo.
fonte
setTimeout( (p) => { console.log(p); }, 1000, "hi" );
A solução mais fácil entre navegadores para suportar parâmetros no setTimeout:
Se você não se importa em não dar suporte ao IE 9 e inferior:
https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout
fonte
Eu sei que faz dez anos desde que essa pergunta foi feita, mas ainda assim, se você rolou até aqui, presumo que você ainda esteja enfrentando algum problema. A solução da Meder Omuraliev é a mais simples e pode ajudar a maioria de nós, mas para aqueles que não querem ter nenhum vínculo, aqui está:
fonte
Eu sei que é velho, mas eu queria adicionar meu sabor (preferido) a isso.
Eu acho que uma maneira bem legível de conseguir isso é passar a
topicId
para uma função, que por sua vez usa o argumento para referenciar o ID do tópico internamente. Este valor não será alterado, mesmo quetopicId
o exterior seja alterado logo após.ou curto:
fonte
A resposta de David Meister parece cuidar dos parâmetros que podem mudar imediatamente após a chamada para setTimeout (), mas antes que a função anônima seja chamada. Mas é muito complicado e não muito óbvio. Eu descobri uma maneira elegante de fazer praticamente a mesma coisa usando IIFE (expressão de função imediatamente invicada).
No exemplo abaixo, a
currentList
variável é passada para o IIFE, que a salva em seu fechamento, até que a função atrasada seja chamada. Mesmo que a variávelcurrentList
mude imediatamente após o código mostrado,setInterval()
ela fará a coisa certa.Sem essa técnica IIFE, a
setTimeout()
função será definitivamente chamada para cadah2
elemento no DOM, mas todas essas chamadas verão apenas o valor de texto do últimoh2
elemento.fonte
Em geral, se você precisar passar uma função como retorno de chamada com parâmetros específicos, poderá usar funções de ordem superior. Isso é bastante elegante com o ES6:
Ou se
someFunction
é de primeira ordem:fonte
Observe que o motivo topicId foi "não definido" pela mensagem de erro é que ele existia como uma variável local quando o setTimeout foi executado, mas não quando a chamada atrasada para o postinsql ocorreu. A vida útil variável é especialmente importante para prestar atenção, especialmente ao tentar algo como passar "this" como uma referência de objeto.
Ouvi dizer que você pode passar topicId como um terceiro parâmetro para a função setTimeout. Não são fornecidos muitos detalhes, mas eu tenho informações suficientes para fazê-lo funcionar e é bem-sucedido no Safari. Não sei o que eles significam sobre o "erro de milissegundos". Confira aqui:
http://www.howtocreate.co.uk/tutorials/javascript/timers
fonte
Como resolvi esse estágio?
bem desse jeito :
setTimeout espera uma referência a uma função, então eu a criei em um fechamento, que interpreta meus dados e retorna uma função com uma boa instância dos meus dados!
Talvez você possa melhorar esta parte:
Eu testei no chrome, firefox e IE e ele executa bem, não sei sobre desempenho, mas precisava que ele estivesse funcionando.
uma amostra de teste:
Talvez você possa alterar a assinatura para torná-la mais compatível:
E, finalmente, para responder à pergunta original:
Espero que possa ajudar!
ps: desculpe mas inglês não é minha língua materna!
fonte
isso funciona em todos os navegadores (o IE é um problema)
fonte
se você quer passar variável como param vamos tentar isso
se requisito for function e var como parmas, tente isso
se requisito for apenas variáveis como parâmetros, tente isso
Você pode tentar isso com ES5 e ES6
fonte
Você pode tentar a funcionalidade padrão de 'apply ()', algo como isto, pode passar mais número de argumentos conforme sua exigência na matriz
fonte
setTimeout faz parte do DOM definido pelo WHAT WG.
https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html
O método que você deseja é: -
Aparentemente, argumentos extras são suportados no IE10. Como alternativa, você pode usar
setTimeout(postinsql.bind(null, topicId), 4000);
, no entanto, transmitir argumentos extras é mais simples e é preferível.Fato histórico: nos dias de VBScript, no JScript, o terceiro parâmetro do setTimeout era a linguagem, como uma string, padronizada como "JScript", mas com a opção de usar "VBScript". https://docs.microsoft.com/pt-br/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa741500(v%3Dvs.85)
fonte
@Jiri Vetyska, obrigado pelo post, mas há algo errado no seu exemplo. Eu precisava passar o alvo que está passando o mouse (isto) para uma função de tempo limite e tentei sua abordagem. Testado no IE9 - não funciona. Também fiz algumas pesquisas e parece que, como apontado aqui, o terceiro parâmetro é a linguagem de script que está sendo usada. Nenhuma menção sobre parâmetros adicionais.
Então, segui a resposta do @ meder e resolvi meu problema com este código:
Espero que isso seja útil para outra pessoa.
fonte
Como existe um problema com o terceiro parâmetro optonal no IE e o uso de fechamentos nos impede de alterar as variáveis (em um loop, por exemplo) e ainda alcançar o resultado desejado, sugiro a seguinte solução.
Podemos tentar usar a recursão assim:
Precisamos garantir que nada mais mude essas variáveis e que escrevamos uma condição de recursão adequada para evitar recursões infinitas.
fonte
// Estas são três respostas muito simples e concisas:
fonte
Respondendo à pergunta, mas com uma simples função de adição com 2 argumentos.
fonte
Você precisa remover aspas da sua
setTimeOut
chamada de função desta forma:fonte
Eu acho que você quer:
fonte
JSON.stringify
para objetos e matrizes regulares e, em seguida, useJSON.parse
dentro da função. No entanto, todo o comportamento será perdido se o objeto tiver métodos.// Estas são três respostas muito simples e concisas:
fonte