วิธีตรวจสอบว่ามีการแก้ไขสัญญา Angular $ q หรือไม่


84

ฉันเข้าใจว่าโดยทั่วไปแล้วเราจะแนบรหัสความต่อเนื่องที่มีลักษณะการthen()โทรและลูกโซ่เมื่อใช้คำสัญญา

อย่างไรก็ตามฉันต้องการเริ่มต้นการโทรแบบอะซิงโครนัสที่ผูกมัดตามสัญญาแล้วเริ่มต้น 3 วินาที$timeout()เพื่อให้ฉันสามารถดำเนินการ UI ได้เฉพาะในกรณีที่สัญญาเดิมยังไม่เสร็จสมบูรณ์ (ฉันคาดว่าสิ่งนี้จะเกิดขึ้นเฉพาะกับการเชื่อมต่อที่ช้าอุปกรณ์มือถือบน 3G ฯลฯ )

เมื่อได้รับสัญญาฉันสามารถตรวจสอบได้ว่าเสร็จสมบูรณ์หรือไม่โดยไม่ปิดกั้นหรือรอ?


2
ฉันเปิดปัญหาเกี่ยวกับเรื่องนี้ในเชิงมุมและได้รับคำตอบที่เป็นประโยชน์github.com/angular/angular.js/issues/8307#issuecomment-49903373
derekdreery

เป็นไปได้ที่จะซ้ำกันของstackoverflow.com/questions/27039771/…
mvermand

คำตอบ:


46

ฉันเดาว่าสิ่งนี้ถูกเพิ่มเข้ามาใน Angular เวอร์ชันล่าสุด แต่ดูเหมือนว่าตอนนี้จะมีวัตถุสถานะ $$ ตามสัญญา:

 var deferred = $q.defer();
 console.log(deferred.promise.$$state.status); // 0
 deferred.resolve();
 console.log(deferred.promise.$$state.status); //1 

ตามที่ระบุไว้ในความคิดเห็นนี้ไม่แนะนำให้ทำเช่นนี้เนื่องจากอาจพังเมื่ออัปเกรดเวอร์ชัน Angular ของคุณ


25
เอกสารเชิงมุมบอกว่า$$...ไม่ควรใช้คุณสมบัติ อาจมีความเสี่ยงเมื่ออัปเกรดเป็น Angular เวอร์ชันใหม่กว่า ...
hgoebl

7
Angular น่าเสียดายที่มีตัวแปรส่วนตัวบนแผ่นเสียงสีเงิน :(
Jackson

2
ดูสิ่งนี้ด้วย: stackoverflow.com/questions/27039771/…
mvermand

2
แต่ ... Angular ไม่ได้ใช้inspectฟังก์ชันนี้ ดังนั้นจึงไม่มีน้ำผลไม้สำหรับเรา Angular devs สัญญาต้นแบบไม่มีมัน
Robert Koritnik

36

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

สิ่งนี้:

var promiseCompleted = false;
promise.then(function(){promiseCompleted=true;})
$timeout(...).then(function(){if(!promiseCompleted)doStuff()})

การใช้งานของ Kris Kowal รวมถึงวิธีการอื่น ๆ ในการตรวจสอบสถานะของสัญญา แต่ดูเหมือนว่าการใช้งาน Angular $qจะไม่รวมถึงสิ่งเหล่านี้


9
มันจะดีกว่าถ้าใช้. สุดท้าย () ที่นี่ โค้ดที่ให้ไว้ด้านบนจะทำเครื่องหมายแฟล็ก PromiseCompleted เป็น true เท่านั้นหากได้รับการแก้ไขสำเร็จ
Karanvir Kang

8

ดูเหมือนจะเป็นไปไม่ได้อย่างที่ @shaunhusain ได้กล่าวไว้แล้ว แต่อาจไม่จำเป็น:

// shows stuff from 3s ahead to promise completetion, 
// or does and undoes it in one step if promise completes before
$q.all(promise, $timeout(doStuff, 3000)).then(undoStuff);

หรืออาจจะดีกว่า:

var tooSlow = $timeout(doStuff, 3000);
promise.always(tooSlow.cancel);

1

ฉันมีปัญหาคล้าย ๆ กันที่ฉันต้องตรวจสอบว่าสัญญากลับมาหรือไม่ เนื่องจาก$watchฟังก์ชันของ AngularJS จะลงทะเบียนการเปลี่ยนแปลงในขณะที่แสดงผลหน้าแม้ว่าจะไม่ได้กำหนดทั้งค่าใหม่และค่าเก่าฉันต้องตรวจสอบดูว่ามีข้อมูลใดที่ควรค่าแก่การจัดเก็บในโมเดลภายนอกของฉันหรือไม่

มันเป็นการแฮ็กแน่นอน แต่ฉันทำสิ่งนี้:

$scope.$watch('userSelection', function() {
  if(promiseObject.hasOwnProperty("$$v"){
    userExportableState.selection = $scope.userSelection;
  }
};

ฉันรู้ว่านั่น$$vเป็นตัวแปรภายในที่ AngularJS ใช้ แต่มันค่อนข้างน่าเชื่อถือในฐานะตัวบ่งชี้คำสัญญาที่ได้รับการแก้ไขสำหรับเรา ใครจะรู้ว่าจะเกิดอะไรขึ้นเมื่อเราอัปเกรดเป็น AngularJS 1.2: - / ฉันไม่เห็นการปรับปรุงใด ๆ$qในเอกสาร 1.2 แต่อาจมีบางคนเขียนบริการทดแทนด้วยคุณสมบัติที่ดีกว่าซึ่งตั้งไว้ใกล้กับ Q


ขอบคุณ แต่มีตัวเลือกที่ดีกว่าการใช้สมาชิกแบบ "ส่วนตัว"
Jackson

0

ฉันไม่ทราบสถานการณ์ที่แน่นอนของคุณ แต่เป็นเรื่องปกติมากกว่าที่จะกำหนดระยะหมดเวลาทันทีหลังจากทำการโทรแบบอะซิงโครนัส (และสร้างคำสัญญา)

การsetTimeout()ระบุคำสั่งอยู่ในเธรดเหตุการณ์เดียวกันกับการโทรแบบอะซิงโครนัสคุณไม่จำเป็นต้องกังวลเกี่ยวกับความเป็นไปได้ของเอฟเฟกต์การแข่งขัน เนื่องจากจาวาสคริปต์เป็นเธรดเดียวอย่างเคร่งครัดการ.then()เรียกกลับของสัญญาจึงรับประกันได้ว่าจะเริ่มทำงานในเธรดเหตุการณ์ในภายหลัง

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