ฉันจะส่งพารามิเตอร์ไปยังการเรียกกลับ setTimeout () ได้อย่างไร


825

ฉันมีรหัสจาวาสคริปต์ที่มีลักษณะดังนี้:

function statechangedPostQuestion()
{
  //alert("statechangedPostQuestion");
  if (xmlhttp.readyState==4)
  {
    var topicId = xmlhttp.responseText;
    setTimeout("postinsql(topicId)",4000);
  }
}

function postinsql(topicId)
{
  //alert(topicId);
}

ฉันได้รับข้อผิดพลาดที่topicIdไม่ได้กำหนดทุกอย่างทำงานก่อนที่ฉันจะใช้setTimeout()ฟังก์ชั่น

ฉันต้องการให้postinsql(topicId)ฟังก์ชันของฉันถูกเรียกหลังจากเวลาผ่านไปครู่หนึ่ง ฉันควรทำอย่างไรดี?


75
มันเจ็บเล็กน้อยแสดงความคิดเห็นในหัวข้อเก่า แต่ฉันแค่ต้องเสนอรุ่นที่สาม (ซึ่งในความคิดของฉันสะอาดมาก): setTimeout (postinsql.bind (null, topicId), 4,000)
# # # ที่

14
@ ฮอบบลิน: ทำไมมันจะเจ็บที่จะตั้งค่าการบันทึกตรง? มันจะไม่ทำร้ายคนอื่นมากขึ้นที่จะลงจอดในคำถามยอดนิยมนี้และดูรูปแบบการโทรที่ไม่น่าไว้วางใจหรือไม่
Dan Dascalescu

2
ทุกอย่างชัดเจนที่นี่: w3schools.com/jsref/met_win_settimeout.asp
Vladislav

@dbliss ข้อเสนอแนะของฉันได้รับการกล่าวถึงอยู่แล้วในหลายคำตอบและเพิ่มเป็นคำตอบที่นี่: stackoverflow.com/a/15620038/287130 แต่ฉันดีใจที่คำแนะนำของฉันเป็นที่ชื่นชม;)
Hobblin

@ ฮอบบลินอ่าขอบคุณมากสำหรับการชี้ให้เห็น ฉันเลื่อนดูคำตอบที่คุณโพสต์และพลาดไป
dbliss

คำตอบ:


1122
setTimeout(function() {
    postinsql(topicId);
}, 4000)

คุณต้องป้อนฟังก์ชันที่ไม่ระบุชื่อเป็นพารามิเตอร์แทนที่จะเป็นสตริงวิธีหลังไม่ควรทำงานตามข้อกำหนดของ ECMAScript แต่เบราว์เซอร์นั้นผ่อนปรน นี่เป็นวิธีการแก้ปัญหาที่เหมาะสมไม่ต้องพึ่งพาการส่งผ่านสตริงเป็น 'ฟังก์ชั่น' เมื่อใช้งานsetTimeout()หรือsetInterval()มันช้ากว่าเพราะจะต้องมีการประเมินและมันไม่ถูกต้อง

UPDATE:

ในฐานะที่เป็น Hobblin เขากล่าวว่าในการแสดงความคิดเห็นต่อคำถามที่ว่าตอนนี้คุณสามารถส่งผ่านอาร์กิวเมนต์ฟังก์ชั่นภายใน setTimeout Function.prototype.bind()ใช้

ตัวอย่าง:

setTimeout(postinsql.bind(null, topicId), 4000);

30
window.setTimeoutเป็นวิธี DOM และเป็นเช่นนี้ไม่ได้ถูกกำหนดโดยข้อกำหนด ECMAScript ผ่านสตริงได้ทำงานเสมอในเบราว์เซอร์และเป็นพฤตินัยมาตรฐานในความเป็นจริงความสามารถในการส่งผ่านวัตถุที่ฟังก์ชั่นถูกเพิ่มเข้ามาในภายหลังด้วย JavaScript 1.2 มันเป็นอย่างชัดเจนส่วนหนึ่งของข้อมูลจำเพาะ HTML5 ร่าง ( whatwg.org/specs/web -apps / current-work / multipage / … ) eval()อย่างไรก็ตามการใช้เชือกแทนของวัตถุฟังก์ชั่นโดยทั่วไปถือว่าเป็นรูปแบบที่น่าสงสารเพราะมันเป็นหลักรูปแบบของการล่าช้า
ไมล์

2
var temp = setTimeout (function () {postinsql (topicId);}, 4000) clearTimeout (ชั่วคราว); ??
Josh Mc

12
จะเกิดอะไรขึ้นหาก topicId ได้รับการเปลี่ยนแปลงหลังจากหมดเวลาที่ตั้งไว้ แต่ก่อนที่จะมีการเรียกใช้ฟังก์ชัน
pilau

22
@pilau เป็นปัญหาของฉันอย่างแน่นอน: หากตัวแปรที่ใช้ในฟังก์ชั่นที่ไม่ระบุชื่อมีการเปลี่ยนแปลงก่อนที่จะหมดเวลา (เช่นในการ for loop) มันจะเปลี่ยนภายในฟังก์ชันด้วย ดังนั้นในตัวอย่างของฉันการตั้งค่าการหมดเวลาที่แตกต่างกัน 5 ครั้งใน for for loop จริง ๆ แล้วสิ้นสุดลงโดยใช้ตัวแปรเดียวกัน ระวังเมื่อใช้คำตอบนี้!
Cristian

10
@pilau โดยใช้การปิดอื่นจะช่วย topicId = 12; ฟังก์ชั่น postinsql (topicId) {console.log (topicId); } ฟังก์ชัน setTimeOutWithClosure (topicId) {setTimeout (ฟังก์ชัน () {postinsql (topicId);}, 1000)} setTimeOutFunction (topicId); topicId = 13;
Halis Yılboğa

727

ในเบราว์เซอร์สมัยใหม่ "setTimeout" ได้รับพารามิเตอร์ตัวที่สามที่ส่งเป็นพารามิเตอร์ไปยังฟังก์ชันภายในเมื่อสิ้นสุดตัวจับเวลา

ตัวอย่าง:

var hello = "Hello World";
setTimeout(alert, 1000, hello);

รายละเอียดเพิ่มเติม:


56
ฉันไม่แน่ใจว่าทำไมคำตอบนี้ไม่ได้รับเลือกให้ดีที่สุด การใช้ฟังก์ชั่นที่ไม่ระบุชื่อใช้งานได้ แต่ถ้าคุณสามารถส่งพารามิเตอร์ที่สามไปยังการเรียกใช้ฟังก์ชั่น setTimeout ดั้งเดิม ... ทำไมไม่
Kris Schouw

54
เพราะมันใช้งานไม่ได้ใน IE เวอร์ชันต่างๆ
แอรอน

4
คำตอบนี้ทำให้ฉันสามารถส่งผ่านวัตถุเหตุการณ์ได้ แต่วิธีอื่นไม่ได้ ฉันมีฟังก์ชั่นไม่ระบุชื่อแล้ว
Glenn Plas

27
โดยคำตอบที่ดีกว่า หากคุณมีรหัสที่ปรับเปลี่ยนพารามิเตอร์ของคุณระหว่างการเรียก "setTimeout" และการใช้งานจริงของฟังก์ชั่นที่ไม่ระบุชื่อ - ฟังก์ชั่นที่ไม่ระบุชื่อจะได้รับค่าที่ปรับเปลี่ยนไม่ใช่สิ่งที่มันเป็นในเวลา เช่น: สำหรับ (var i = 0; i <100; i ++) {setTimeout (function () {console.write (i);}, 0); } สิ่งนี้จะบันทึก "100" 100 ครั้ง (ทดสอบกับ FF) คำตอบปัจจุบันช่วยหลีกเลี่ยงปัญหานี้
รูต

1
ตามที่developer.mozilla.org/es/docs/Web/API/WindowTimers/setTimeout อาร์กิวเมนต์ callback สำหรับ Internet Explorer นั้นรองรับเฉพาะในเวอร์ชัน> = 10 ต้องระวังเหมือนในหลาย ๆ เว็บไซต์เช่น 8 และ ie9 ยังคงได้รับการแบ่งปันที่เกี่ยวข้อง
le0diaz

154

หลังจากทำการวิจัยและทดสอบแล้วการดำเนินการที่ถูกต้องเพียงอย่างเดียวคือ

setTimeout(yourFunctionReference, 4000, param1, param2, paramN);

setTimeout จะส่งพารามิเตอร์พิเศษทั้งหมดไปยังฟังก์ชันของคุณเพื่อให้สามารถประมวลผลได้

ฟังก์ชั่นที่ไม่ระบุชื่อสามารถทำงานกับสิ่งพื้นฐานมาก แต่ภายในอินสแตนซ์ของวัตถุที่คุณต้องใช้ "นี้" ไม่มีวิธีที่จะทำให้มันทำงาน ฟังก์ชั่นไม่ระบุชื่อใด ๆ จะเปลี่ยน "นี้" เพื่อชี้ไปที่หน้าต่างดังนั้นคุณจะสูญเสียการอ้างอิงวัตถุของคุณ


24
มันขึ้นอยู่กับความโศกเศร้าในใจของฉันที่ฉันต้องบอก: มันไม่ทำงานใน internet explorer : / params พิเศษทั้งหมดผ่านมาเป็นไม่ได้กำหนด
Amalgovinus

6
ฉันเพิ่งใช้var that = this; setTimeout( function() { that.foo(); }, 1000);
Ed Williams

2
สิ่งนี้ถูกต้องและถูกระบุใน HTML5 whatwg.org/specs/web-apps/current-work/multipage/ …
Garrett

4
ตรงนี้เป็นคำตอบเดียวกับฟาบิโอของ
Dan Dascalescu

1
ตามที่developer.mozilla.org/es/docs/Web/API/WindowTimers/setTimeout อาร์กิวเมนต์ callback สำหรับ Internet Explorer นั้นรองรับเฉพาะในเวอร์ชัน> = 10 ต้องระวังเหมือนในหลาย ๆ เว็บไซต์เช่น 8 และ ie9 ยังคงได้รับการแบ่งปันที่เกี่ยวข้อง
le0diaz

45

นี่เป็นคำถามเก่าแก่ที่มีคำตอบ "ถูกต้อง" อยู่แล้ว แต่ฉันคิดว่าฉันจะพูดถึงวิธีการอื่นที่ไม่มีใครพูดถึงที่นี่ สิ่งนี้ถูกคัดลอกและวางจากไลบรารีขีดล่างที่ยอดเยี่ยม:

_.delay = function(func, wait) {
  var args = slice.call(arguments, 2);
  return setTimeout(function(){ return func.apply(null, args); }, wait);
};

คุณสามารถส่งอาร์กิวเมนต์ได้มากเท่าที่คุณต้องการฟังก์ชั่นที่เรียกใช้โดย setTimeout และเป็นโบนัสที่เพิ่มเข้ามา (ปกติแล้วจะเป็นโบนัส) มูลค่าของอาร์กิวเมนต์ที่ส่งผ่านไปยังฟังก์ชันของคุณจะถูกระงับเมื่อคุณเรียกใช้ setTimeout ดังนั้นหากพวกเขาเปลี่ยนค่า เมื่อถึงจุดหนึ่งระหว่างที่ setTimeout () ถูกเรียกและเมื่อหมดเวลาดี ... ที่ไม่น่าหงุดหงิดอีกแล้ว :)

นี่คือซอที่คุณสามารถเห็นสิ่งที่ฉันหมายถึง


7
คำตอบนั้นใช้งานได้จริง แต่คุณดูเหมือนจะมีห้องสมุดที่ฉันไม่มี นี่คือการแก้ไขเล็กน้อยเพื่อให้ใช้งานได้: แทน slice.call ให้ใช้ Array.prototype.slice.call (อาร์กิวเมนต์ 2)
เมลานี

7
@Melanie "ห้องสมุดบางส่วน"? ที่ผมกล่าวในคำตอบว่ามันเป็นห้องสมุดขีด - underscorejs.org แต่ใช่ Array.prototype.slice มีนามแฝงว่าจะเชือดในห้องสมุดนั้นดังนั้นคุณต้องทำด้วยตัวเองถ้าคุณไม่ได้ใช้มันจุดดี :)
David Meister

38

ฉันเพิ่งมาในสถานการณ์ที่เป็นเอกลักษณ์ของที่จำเป็นต้องใช้setTimeoutในวง setTimeoutทำความเข้าใจเกี่ยวกับความช่วยเหลือสามารถนี้คุณเข้าใจวิธีการส่งผ่านพารามิเตอร์ไป

วิธีที่ 1

ใช้forEachและObject.keysตามคำแนะนำของ Sukima :

var testObject = {
    prop1: 'test1',
    prop2: 'test2',
    prop3: 'test3'
};

Object.keys(testObject).forEach(function(propertyName, i) {
    setTimeout(function() {
        console.log(testObject[propertyName]);
    }, i * 1000);
});

ฉันแนะนำวิธีนี้

วิธีที่ 2

ใช้bind:

var i = 0;
for (var propertyName in testObject) {
    setTimeout(function(propertyName) {
        console.log(testObject[propertyName]);
    }.bind(this, propertyName), i++ * 1000);
}

JSFiddle: http://jsfiddle.net/MsBkW/

วิธีที่ 3

หรือถ้าคุณไม่สามารถใช้forEachหรือbindใช้IIFE :

var i = 0;
for (var propertyName in testObject) {
    setTimeout((function(propertyName) {
        return function() {
            console.log(testObject[propertyName]);
        };
    })(propertyName), i++ * 1000);
}

วิธีที่ 4

แต่ถ้าคุณไม่สนใจ IE <10 คุณสามารถใช้คำแนะนำของ Fabio :

var i = 0;
for (var propertyName in testObject) {
    setTimeout(function(propertyName) {
        console.log(testObject[propertyName]);
    }, i++ * 1000, propertyName);
}

วิธีที่ 5 (ES6)

ใช้ตัวแปรที่กำหนดขอบเขตของบล็อก:

let i = 0;
for (let propertyName in testObject) {
    setTimeout(() => console.log(testObject[propertyName]), i++ * 1000);
}

แม้ว่าฉันจะยังคงแนะนำให้ใช้Object.keysกับforEachใน ES6


2
หมายเหตุ: .bindจะใช้ไม่ได้กับ IE8 และต่ำกว่า [อ้างอิง: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ ...... ] ฉันสิ้นสุดการใช้โซลูชันของ Schien: stackoverflow.com/a/21213723/1876899
cjspurgeon

1
ถ้าคุณอยู่ในสภาพแวดล้อมที่ใช้bindแล้วของคุณยังอยู่ในสภาพแวดล้อมที่ข้อเสนอและObject.keys forEachคุณสามารถปล่อยลูป for for และรับขอบเขตการทำงาน "ฟรี" (เช่นเดียวกับนกสองตัวที่ไม่มีทรัพยากรหนึ่งก้อน) ในกระบวนการ
Sukima

@ David Sherret ในกรณีที่คุณไม่เคยใช้มาก่อนลองใช้ไลบรารี่async( github.com/caolan/async ) เราใช้มันอย่างกว้างขวางใน Sails และได้ผลลัพธ์ที่ยอดเยี่ยมสำหรับ 2 ปีที่ผ่านมา มันมีวิธีการทั้งในแบบขนานและในซีรีส์สำหรับตรงกันforEach, map, reduceฯลฯ
mikermcneil

25

Hobblin แสดงความคิดเห็นกับคำถามนี้แล้ว แต่ควรเป็นคำตอบจริงๆ!

การใช้Function.prototype.bind()เป็นวิธีที่สะอาดและยืดหยุ่นที่สุดในการทำสิ่งนี้ (ด้วยโบนัสเพิ่มเติมของความสามารถในการตั้งค่าthisบริบท):

setTimeout(postinsql.bind(null, topicId), 4000);

สำหรับข้อมูลเพิ่มเติมโปรดดูลิงก์ MDN เหล่านี้:
https://developer.mozilla.org/en/docs/DOM/window.setTimeout#highlighter_547041 https://developer.mozilla.org/en/docs/JavaScript/Reference/Global_Objects/Function / ผูก # With_setTimeout


บริบทนี้สามารถส่งผ่านกับอาร์กิวเมนต์แรกของการผูกsetTimeout(postinsql.bind(this, topicId), 4000);
Giuseppe Galano

@GiuseppeGalano ทั้งหมดที่ผมกล่าวว่าในคำตอบของฉัน แต่มันไม่จำเป็นสำหรับตัวอย่างนี้ :)
Dain

bindที่น่าสนใจหลายวิธีปัดสวะการใช้งานบางส่วนใช้ มันทำให้รหัสที่อ่านได้อย่างแท้จริง
Sukima

bind () ได้รับการสนับสนุนจาก IE9 + เท่านั้นดังนั้นวิธีนี้จะใช้ไม่ได้กับ <IE9
Sanjeev

@Sanjeev ใช้ ES5 shim เพื่อให้ทำงานได้ใน IE รุ่นเก่า: github.com/es-shims/es5-shim
gregers

17

บางคำตอบนั้นถูกต้อง แต่มีความซับซ้อน

ฉันตอบคำถามนี้อีกครั้งในอีก 4 ปีต่อมาเพราะฉันยังพบรหัสที่ซับซ้อนมากเกินไปเพื่อแก้ปัญหานี้ มีทางออกที่สง่างาม

ก่อนอื่นอย่าส่งผ่านสตริงเป็นพารามิเตอร์แรกเมื่อเรียกใช้ setTimeout เพราะจะเรียกใช้ฟังก์ชัน "eval" ที่ช้า

ดังนั้นเราจะส่งผ่านพารามิเตอร์ไปยังฟังก์ชันการหมดเวลาได้อย่างไร โดยใช้การปิด:

settopic=function(topicid){
  setTimeout(function(){
    //thanks to closure, topicid is visible here
    postinsql(topicid);
  },4000);
}

...
if (xhr.readyState==4){
  settopic(xhr.responseText);
}

บางคนแนะนำให้ใช้ฟังก์ชั่นที่ไม่ระบุชื่อเมื่อเรียกใช้ฟังก์ชันหมดเวลา:

if (xhr.readyState==4){
  setTimeout(function(){
    settopic(xhr.responseText);
  },4000);
}

ไวยากรณ์ใช้งานได้ดี แต่เมื่อถึงเวลา settopic ถูกเรียกเช่น 4 วินาทีต่อมาวัตถุ XHR อาจไม่เหมือนกัน ดังนั้นสิ่งสำคัญคือการผูกตัวแปรไว้ล่วงหน้า


1
+1 สำหรับโซลูชันที่อ่านได้แตกต่างจากของฉันเล็กน้อย ในขณะที่คุณมี setTimeout ภายในฟังก์ชั่น settopic ฉันมีฟังก์ชั่น fDelayed (settopic) ภายในฟังก์ชั่น setTimeout
Dominic

11

คำตอบของฉัน:

setTimeout((function(topicId) {
  return function() {
    postinsql(topicId);
  };
})(topicId), 4000);

คำอธิบาย:

ฟังก์ชั่นที่ไม่ระบุชื่อที่สร้างขึ้นจะส่งคืนฟังก์ชันที่ไม่ระบุชื่ออื่น ฟังก์ชั่นนี้มีการเข้าถึงการส่งผ่านเดิมtopicIdดังนั้นมันจะไม่ทำให้เกิดข้อผิดพลาด ฟังก์ชั่นที่ไม่ระบุชื่อแรกจะถูกเรียกใช้ทันทีผ่านเข้าtopicIdมาดังนั้นฟังก์ชันที่ลงทะเบียนที่มีความล่าช้าจะสามารถเข้าถึงได้topicIdในเวลาที่โทรผ่านผ่านการปิด

หรือ

สิ่งนี้จะแปลงเป็น:

setTimeout(function() {
  postinsql(topicId); // topicId inside higher scope (passed to returning function)
}, 4000);

แก้ไข: ฉันเห็นคำตอบเดียวกันดังนั้นดูเขา แต่ฉันไม่ได้ขโมยคำตอบของเขา! ฉันลืมที่จะมอง อ่านคำอธิบายและดูว่าช่วยให้เข้าใจรหัสได้หรือไม่


นี่คือคำตอบที่ดีที่สุด โซลูชั่นเหล่านี้จำนวนมากจะไม่ได้ให้เกียรติกับการหมดเวลา อย่างไรก็ตามทำไมคุณถึงห่อฟังก์ชั่นแรกที่ไม่ระบุชื่อไว้ในวงเล็บ ฉันไม่คิดว่าพวกเขาจำเป็นต้องทำสิ่งนี้ให้สำเร็จ
Robert Henderson

นี่เป็นคำตอบที่ดีที่สุด👍 แต่ต้องทำโคลนนิ่งเพราะเมื่อค่าเช่นtopicIdได้รับการเปลี่ยนแปลงค่าในการเปลี่ยนแปลงการหมดเวลาเช่นกัน โคลนทำการแก้ไข
pariola

10

แทนที่

 setTimeout("postinsql(topicId)", 4000);

กับ

 setTimeout("postinsql(" + topicId + ")", 4000);

หรือดีกว่านั้นให้แทนที่นิพจน์สตริงด้วยฟังก์ชันที่ไม่ระบุชื่อ

 setTimeout(function () { postinsql(topicId); }, 4000);

แก้ไข:

ความคิดเห็นของ Brownstone ไม่ถูกต้องสิ่งนี้จะทำงานได้ตามที่ตั้งใจไว้ซึ่งแสดงโดยการเรียกใช้สิ่งนี้ในคอนโซล Firebug

(function() {
  function postinsql(id) {
    console.log(id);
  }
  var topicId = 3
  window.setTimeout("postinsql(" + topicId + ")",4000); // outputs 3 after 4 seconds
})();

โปรดทราบว่าฉันเห็นด้วยกับคนอื่น ๆ ที่คุณควรหลีกเลี่ยงการส่งผ่านสตริงsetTimeoutเนื่องจากจะเป็นการเรียกeval()ใช้สตริงและส่งผ่านฟังก์ชันแทน


สิ่งนี้จะไม่ทำงานเนื่องจากผลลัพธ์ของ postinsql (topicId) จะถูกดำเนินการโดย setTimeout คุณต้องห่อมันในฟังก์ชั่นเช่นเดียวกับคำตอบแรกหรือใช้ผู้ช่วยเช่น. curry () ของต้นแบบ - setTimeout (postinsql.curry (topidId), 4000);
shuckster

2
@brownstone: ไม่ถูกต้อง สตริงจะถูกประเมินเมื่อหมดเวลาใช้งาน
ไมล์

9

คุณสามารถส่งพารามิเตอร์ไปยังฟังก์ชันการเรียกกลับ setTimeout เป็น:

setTimeout (ฟังก์ชั่น, มิลลิวินาที, param1, param2, ... )

เช่น.

function myFunction() {
  setTimeout(alertMsg, 3000, "Hello");
}

function alertMsg(message) {
    alert(message)
}

1
ใครสามารถบอกฉันได้ว่าทำไมคำตอบนี้ไม่ใช่คำตอบที่ต้องการ นี่เป็นวิธีที่ง่ายที่สุดในความคิดของฉัน! ง่ายเหมือนsetTimeout( (p) => { console.log(p); }, 1000, "hi" );
Mazhar Zandsalimi

1
ใช่ นี่ควรเป็นคำตอบที่ยอมรับได้ จาก MDN: developer.mozilla.org/en-US/docs/Web/API/…
ฮัน

7

cross cross solution ที่ง่ายที่สุดสำหรับการรองรับพารามิเตอร์ใน setTimeout:

setTimeout(function() {
    postinsql(topicId);
}, 4000)

หากคุณไม่รังเกียจที่จะไม่รองรับ IE 9 หรือต่ำกว่า:

setTimeout(postinsql, 4000, topicId);

ความเข้ากันได้เบราว์เซอร์เดสก์ทอป setTimeout

ความเข้ากันได้เบราว์เซอร์ setTimeout มือถือ

https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout


5

ฉันรู้ว่าเป็นเวลา 10 ปีแล้วตั้งแต่มีการถามคำถามนี้ แต่ถึงกระนั้นถ้าคุณเลื่อนไปจนถึงที่นี่ฉันถือว่าคุณยังคงประสบปัญหาอยู่ การแก้ปัญหาโดย Meder Omuraliev เป็นวิธีที่ง่ายที่สุดและอาจช่วยเราได้ส่วนใหญ่ แต่สำหรับผู้ที่ไม่ต้องการมีส่วนร่วมนี่คือ:

  1. ใช้ Param สำหรับ setTimeout
setTimeout(function(p){
//p == param1
},3000,param1);
  1. ใช้การแสดงออกของฟังก์ชันที่เรียกใช้ทันที (IIFE)
let param1 = 'demon';
setTimeout(function(p){
    // p == 'demon'
},2000,(function(){
    return param1;
})()
);
  1. คำตอบสำหรับคำถาม
function statechangedPostQuestion()
{
  //alert("statechangedPostQuestion");
  if (xmlhttp.readyState==4)
  {
    setTimeout(postinsql,4000,(function(){
        return xmlhttp.responseText;
    })());
  }
}

function postinsql(topicId)
{
  //alert(topicId);
}

4

ฉันรู้ว่ามันเก่า แต่ฉันต้องการที่จะเพิ่มรสชาติ (ที่ต้องการ) ของฉันไปที่นี้

ฉันคิดว่าวิธีที่ง่ายต่อการอ่านเพื่อบรรลุเป้าหมายนี้คือการส่งผ่านtopicIdไปยังฟังก์ชันซึ่งใช้อาร์กิวเมนต์เพื่ออ้างอิง ID ของหัวข้อภายใน ค่านี้จะไม่เปลี่ยนแปลงแม้ว่าtopicIdภายนอกจะมีการเปลี่ยนแปลงหลังจากนั้นไม่นาน

var topicId = xmlhttp.responseText;
var fDelayed = function(tid) {
  return function() {
    postinsql(tid);
  };
}
setTimeout(fDelayed(topicId),4000);

หรือสั้น:

var topicId = xmlhttp.responseText;
setTimeout(function(tid) {
  return function() { postinsql(tid); };
}(topicId), 4000);

4

คำตอบของ David Meister ดูเหมือนว่าจะดูแลพารามิเตอร์ที่อาจเปลี่ยนแปลงได้ทันทีหลังจากการเรียกไปยัง setTimeout () แต่ก่อนที่จะเรียกใช้ฟังก์ชันที่ไม่ระบุชื่อ แต่มันยุ่งยากเกินไปและไม่ค่อยชัดเจน ฉันค้นพบวิธีที่สง่างามในการทำสิ่งเดียวกันโดยใช้ IIFE

ในตัวอย่างด้านล่างcurrentListตัวแปรจะถูกส่งผ่านไปยัง IIFE ซึ่งจะบันทึกไว้ในการปิดจนกว่าจะมีการเรียกใช้ฟังก์ชันที่ล่าช้า แม้ว่าตัวแปรcurrentListจะเปลี่ยนแปลงทันทีหลังจากที่แสดงรหัสsetInterval()จะทำในสิ่งที่ถูกต้อง

หากไม่มีเทคนิค IIFE นี้setTimeout()ฟังก์ชั่นจะถูกเรียกใช้สำหรับแต่ละh2องค์ประกอบใน DOM แต่การโทรเหล่านั้นจะเห็นเฉพาะค่าข้อความขององค์ประกอบสุดท้าย h2เท่านั้น

<script>
  // Wait for the document to load.
  $(document).ready(function() {
  $("h2").each(function (index) {

    currentList = $(this).text();

    (function (param1, param2) {
        setTimeout(function() {
            $("span").text(param1 + ' : ' + param2 );
        }, param1 * 1000);

    })(index, currentList);
  });
</script>

4

โดยทั่วไปหากคุณต้องการส่งผ่านฟังก์ชั่นเป็นการโทรกลับพร้อมพารามิเตอร์เฉพาะคุณสามารถใช้ฟังก์ชันลำดับที่สูงขึ้นได้ นี่มันสวยหรูด้วย ES6:

const someFunction = (params) => () => {
  //do whatever
};

setTimeout(someFunction(params), 1000);

หรือถ้าsomeFunctionเป็นคำสั่งแรก:

setTimeout(() => someFunction(params), 1000); 

สิ่งนี้ขัดกันมาก
user151496

สง่างามแน่นอน! ขอบคุณ
Velojet

3

โปรดทราบว่าเหตุผล topicId คือ "ไม่ได้กำหนด" ต่อข้อความแสดงข้อผิดพลาดคือมันมีอยู่เป็นตัวแปรท้องถิ่นเมื่อ setTimeout ถูกดำเนินการ แต่ไม่เมื่อเกิดการเรียกที่ล่าช้าไปยัง postinsql อายุการใช้งานผันแปรเป็นสิ่งสำคัญอย่างยิ่งที่จะต้องใส่ใจโดยเฉพาะอย่างยิ่งเมื่อพยายามทำบางสิ่งเช่นส่งผ่าน "สิ่งนี้" เพื่อเป็นข้อมูลอ้างอิงวัตถุ

ฉันได้ยินมาว่าคุณสามารถส่ง topicId เป็นพารามิเตอร์ตัวที่สามไปยังฟังก์ชัน setTimeout มีรายละเอียดไม่มากนัก แต่ฉันได้รับข้อมูลเพียงพอที่จะใช้งานได้และประสบความสำเร็จใน Safari ฉันไม่รู้ว่าพวกเขาหมายถึงอะไรเกี่ยวกับ "ข้อผิดพลาดมิลลิวินาที" ตรวจสอบที่นี่:

http://www.howtocreate.co.uk/tutorials/javascript/timers


3

ฉันจะแก้ไขสเตจนี้ได้อย่างไร?

เป็นแบบนั้น :

setTimeout((function(_deepFunction ,_deepData){
    var _deepResultFunction = function _deepResultFunction(){
          _deepFunction(_deepData);
    };
    return _deepResultFunction;
})(fromOuterFunction, fromOuterData ) , 1000  );

setTimeout รอการอ้างอิงไปยังฟังก์ชั่นดังนั้นฉันจึงสร้างมันขึ้นมาในช่วงปิดซึ่ง interprete ข้อมูลของฉันและส่งคืนฟังก์ชั่นที่มีอินสแตนซ์ที่ดีของข้อมูลของฉัน!

บางทีคุณสามารถปรับปรุงส่วนนี้:

_deepFunction(_deepData);

// change to something like :
_deepFunction.apply(contextFromParams , args); 

ฉันทดสอบด้วย chrome, firefox และ IE และทำงานได้ดีฉันไม่รู้เกี่ยวกับประสิทธิภาพ แต่ฉันต้องการให้ทำงานได้

การทดสอบตัวอย่าง:

myDelay_function = function(fn , params , ctxt , _time){
setTimeout((function(_deepFunction ,_deepData, _deepCtxt){
            var _deepResultFunction = function _deepResultFunction(){
                //_deepFunction(_deepData);
                _deepFunction.call(  _deepCtxt , _deepData);
            };
        return _deepResultFunction;
    })(fn , params , ctxt)
, _time) 
};

// the function to be used :
myFunc = function(param){ console.log(param + this.name) }
// note that we call this.name

// a context object :
myObjet = {
    id : "myId" , 
    name : "myName"
}

// setting a parmeter
myParamter = "I am the outer parameter : ";

//and now let's make the call :
myDelay_function(myFunc , myParamter  , myObjet , 1000)

// this will produce this result on the console line :
// I am the outer parameter : myName

บางทีคุณสามารถเปลี่ยนลายเซ็นเพื่อให้มันน่าพึงพอใจมากขึ้น:

myNass_setTimeOut = function (fn , _time , params , ctxt ){
return setTimeout((function(_deepFunction ,_deepData, _deepCtxt){
            var _deepResultFunction = function _deepResultFunction(){
                //_deepFunction(_deepData);
                _deepFunction.apply(  _deepCtxt , _deepData);
            };
        return _deepResultFunction;
    })(fn , params , ctxt)
, _time) 
};

// and try again :
for(var i=0; i<10; i++){
   myNass_setTimeOut(console.log ,1000 , [i] , console)
}

และสุดท้ายที่จะตอบคำถามเดิม:

 myNass_setTimeOut( postinsql, 4000, topicId );

หวังว่ามันจะช่วยได้!

ps: ขอโทษ แต่ภาษาอังกฤษไม่ใช่ภาษาแม่ของฉัน!


นี่มันซับซ้อนเกินไปเมื่อเทียบกับคำตอบอื่น ๆ
Dan Dascalescu

3

สามารถใช้ได้กับทุกเบราว์เซอร์ (IE เป็นเลขคี่บอล)

setTimeout( (function(x) {
return function() {
        postinsql(x);
    };
})(topicId) , 4000);

3

ถ้าคุณต้องการส่งตัวแปรเป็นพารามิเตอร์ให้ลองทำสิ่งนี้

ถ้าความต้องการเป็นฟังก์ชั่นและ var เป็น parmas ให้ลองสิ่งนี้

setTimeout((param1,param2) => { 
     alert(param1 + param2);
     postinsql(topicId);
},2000,'msg1', 'msg2')

ถ้าต้องการเป็นเพียงตัวแปรเป็นพารามิเตอร์แล้วลองนี้

setTimeout((param1,param2) => { alert(param1 + param2) },2000,'msg1', 'msg2')

คุณสามารถลองกับ ES5 และ ES6


2

คุณสามารถลองฟังก์ชั่นเริ่มต้นของ 'Apply ()' บางอย่างเช่นนี้คุณสามารถส่งอาร์กิวเมนต์จำนวนมากขึ้นตามความต้องการของคุณในอาร์เรย์

function postinsql(topicId)
{
  //alert(topicId);
}
setTimeout(
       postinsql.apply(window,["mytopic"])
,500);

1

setTimeout เป็นส่วนหนึ่งของ DOM ที่กำหนดโดย WHAT WG

https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html

วิธีที่คุณต้องการคือ: -

handle = self.setTimeout( handler [, timeout [, arguments... ] ] )

กำหนดเวลาการหมดเวลาเพื่อเรียกใช้ตัวจัดการหลังจากหมดเวลาเป็นมิลลิวินาที อาร์กิวเมนต์ใด ๆ จะถูกส่งผ่านไปยังตัวจัดการโดยตรง

setTimeout(postinsql, 4000, topicId);

เห็นได้ชัดว่าข้อโต้แย้งพิเศษได้รับการสนับสนุนใน IE10 หรือคุณสามารถใช้setTimeout(postinsql.bind(null, topicId), 4000);อย่างไรก็ตามการส่งอาร์กิวเมนต์พิเศษนั้นง่ายกว่าและดีกว่า

Historical factoid: ในวันที่ VBScript ใน JScript พารามิเตอร์ที่สามของ setTimeout เป็นภาษาซึ่งเป็นสตริงเริ่มต้นที่ "JScript" แต่มีตัวเลือกให้ใช้ "VBScript" https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa741500(v%3Dvs.85)


0

@Jiri Vetyska ขอบคุณสำหรับการโพสต์ แต่มีบางอย่างผิดปกติในตัวอย่างของคุณ ฉันต้องผ่านเป้าหมายที่มีการโฮเวอร์ (นี่) ไปยังฟังก์ชันไทม์เอาต์และฉันลองใช้แนวทางของคุณ ทดสอบใน IE9 - ไม่ทำงาน ฉันยังทำการวิจัยและปรากฏว่าตามที่ชี้ไว้ที่นี่พารามิเตอร์ที่สามคือภาษาสคริปต์ที่ใช้ ไม่พูดถึงพารามิเตอร์เพิ่มเติม

ดังนั้นฉันจึงปฏิบัติตามคำตอบของ @ meder และแก้ไขปัญหาของฉันด้วยรหัสนี้:

$('.targetItemClass').hover(ItemHoverIn, ItemHoverOut);

function ItemHoverIn() {
 //some code here
}

function ItemHoverOut() {
    var THIS = this;
    setTimeout(
        function () { ItemHoverOut_timeout(THIS); },
        100
    );
}
function ItemHoverOut_timeout(target) {
    //do something with target which is hovered out
}

หวังว่านี่จะเป็นประโยชน์สำหรับคนอื่น


0

เนื่องจากมีปัญหากับพารามิเตอร์ optonal ตัวที่สามใน IE และการใช้ closures ทำให้เราไม่สามารถเปลี่ยนตัวแปร (ในลูปเป็นต้น) และยังคงได้ผลลัพธ์ตามที่ต้องการผมแนะนำวิธีแก้ไขต่อไปนี้

เราสามารถลองใช้การสอบถามซ้ำดังนี้:

var i = 0;
var hellos = ["Hello World1!", "Hello World2!", "Hello World3!", "Hello World4!", "Hello World5!"];

if(hellos.length > 0) timeout();

function timeout() {                
    document.write('<p>' + hellos[i] + '<p>');
    i++;
    if (i < hellos.length)
        setTimeout(timeout, 500);
}

เราต้องแน่ใจว่าไม่มีสิ่งใดเปลี่ยนแปลงตัวแปรเหล่านี้และเราเขียนเงื่อนไขการเรียกซ้ำที่เหมาะสมเพื่อหลีกเลี่ยงการเรียกซ้ำที่ไม่สิ้นสุด


0

// สามคำตอบที่ง่ายและกระชับ:

function fun() {
    console.log(this.prop1, this.prop2, this.prop3);
}

let obj = { prop1: 'one', prop2: 'two', prop3: 'three' };

let bound = fun.bind(obj);

setTimeout(bound, 3000);

 // or

function funOut(par1, par2, par3) {

  return function() { 

    console.log(par1, par2, par3);

  }
};

setTimeout(funOut('one', 'two', 'three'), 5000);

 // or

let funny = function(a, b, c) { console.log(a, b, c); };

setTimeout(funny, 2000, 'hello', 'worldly', 'people');

0

ตอบคำถาม แต่ด้วยฟังก์ชั่นการบวกอย่างง่ายที่มี 2 ข้อโต้แย้ง

var x = 3, y = 4;

setTimeout(function(arg1, arg2) { 
      delayedSum(arg1, arg2);
}(x, y), 1000);

function delayedSum(param1, param2) {
     alert(param1 + param2); // 7
}

0

คุณต้องลบเครื่องหมายคำพูดออกจากsetTimeOutการเรียกฟังก์ชันของคุณดังนี้:

setTimeout(postinsql(topicId),4000);

-1

ฉันคิดว่าคุณต้องการ:

setTimeout("postinsql(" + topicId + ")", 4000);

1
ฉันใช้งานอินสแตนซ์ที่ไม่สามารถใช้งานได้ (ส่งผลให้เกิดข้อผิดพลาด 'ฟังก์ชั่นที่ไม่ได้กำหนด' เสมอไป) แต่การใช้ฟังก์ชั่นที่ไม่ระบุชื่อใช้งานได้ ซึ่งน่าผิดหวังเนื่องจากทุกคนดูเหมือนว่าไวยากรณ์ข้างต้นควรทำงาน (เป็นไปได้ไหมว่า jQuery ได้รับวิธีการ 'quote as string')
DA

6
สมมติว่า topicId เป็นฟังก์ชัน ... หรือวัตถุ สิ่งนี้ใช้ไม่ได้!
Serafeim

หากคุณต้องการดำเนินการตามวิธีนี้จริงๆให้ใช้JSON.stringifyสำหรับวัตถุและอาร์เรย์ปกติจากนั้นใช้JSON.parseภายในฟังก์ชัน อย่างไรก็ตามพฤติกรรมทั้งหมดจะหายไปหากวัตถุนั้นมีวิธีการ
DarthCadeus

-2

// สามคำตอบที่ง่ายและกระชับ:

function fun() {
    console.log(this.prop1, this.prop2, this.prop3);
}

let obj = { prop1: 'one', prop2: 'two', prop3: 'three' };

let bound = fun.bind(obj);

setTimeout(bound, 3000);

 // or

function funOut(par1, par2, par3) {

  return function() { 

    console.log(par1, par2, par3);

  }
};

setTimeout(funOut('one', 'two', 'three'), 5000);

 // or

let funny = function(a, b, c) { console.log(a, b, c); };

setTimeout(funny, 2000, 'hello', 'worldly', 'people');
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.