จะเข้าถึงคุณค่าของสัญญาได้อย่างไร?


146

ฉันกำลังดูตัวอย่างนี้จากเอกสารของ Angular $qแต่ฉันคิดว่านี่อาจใช้กับสัญญาโดยทั่วไป ตัวอย่างด้านล่างนี้ถูกคัดลอกคำต่อคำจากเอกสารโดยมีความคิดเห็นรวมอยู่ด้วย:

promiseB = promiseA.then(function(result) {
  return result + 1;
});

// promiseB will be resolved immediately after promiseA is resolved and its value
// will be the result of promiseA incremented by 1

ฉันไม่ชัดเจนว่ามันใช้งานได้อย่างไร ถ้าผมสามารถเรียก.then()ผลการใช้ครั้งแรก.then(), ผูกมัดพวกเขาซึ่งฉันรู้ว่าฉันสามารถแล้วเป็นวัตถุสัญญาประเภทpromiseB มันไม่ได้เป็นObject Numberดังนั้นสิ่งที่พวกเขาหมายถึงโดย "คุณค่าของมันจะเป็นผลมาจากสัญญาเพิ่มขึ้น 1"?

ฉันควรจะเข้าถึงสิ่งที่เป็นpromiseB.valueหรืออะไรแบบนั้น? การติดต่อกลับสำเร็จจะส่งคืนสัญญาและส่งคืน "ผลลัพธ์ + 1" ได้อย่างไร ฉันคิดถึงบางอย่าง


ฉันถามคำถามที่เกี่ยวข้อง: เหตุใด Promise จึงไม่มีฟังก์ชัน get ()
Roland


คำถามนี้มีอายุ 5 ปีและมีคำตอบที่ยอมรับ ...
Temporary_user_name

@temporary_user_name: ไม่เป็นไรสำหรับคนที่จะปิดการลงคะแนนได้ตลอดเวลาแม้กระทั่งคำถามเก่า ๆ
halfer

คำตอบ:


141

promiseA's thenฟังก์ชันส่งกลับสัญญาใหม่ ( promiseB) ที่ได้รับการแก้ไขในทันทีหลังจากที่ได้รับการแก้ไขค่าของมันคือค่าของสิ่งที่ถูกส่งกลับจากฟังก์ชั่นที่ประสบความสำเร็จภายในpromiseApromiseA

ในกรณีpromiseAนี้แก้ไขด้วยค่า - resultจากนั้นแก้ไขทันทีpromiseBด้วยค่าresult + 1เป็น

การเข้าถึงค่าของที่จะทำในทางเดียวกันเราเข้าถึงผลมาจากการpromiseBpromiseA

promiseB.then(function(result) {
    // here you can use the result of promiseB
});

แก้ไขธันวาคม 2019 : async/ awaitเป็นมาตรฐานใน JS ซึ่งอนุญาตให้ใช้ไวยากรณ์ทางเลือกสำหรับวิธีการที่อธิบายไว้ข้างต้น ตอนนี้คุณสามารถเขียน:

let result = await functionThatReturnsPromiseA();
result = result + 1;

ขณะนี้ไม่มีสัญญา B เนื่องจากเราได้คลายผลลัพธ์จากสัญญา A ที่ใช้awaitและคุณสามารถทำงานกับมันได้โดยตรง

อย่างไรก็ตามawaitสามารถใช้ได้ภายในasyncฟังก์ชันเท่านั้น ดังนั้นหากต้องการขยายออกไปเล็กน้อยข้างต้นจะต้องมีดังนี้:

async function doSomething() {
    let result = await functionThatReturnsPromiseA();
    return result + 1;
}

2
สัญญาเป็นวัตถุในทางทฤษฎีของพวกเขาเอง พวกเขามีผลลัพธ์ที่สามารถเข้าถึงได้ผ่านฟังก์ชั่นความสำเร็จของสัญญา
Nachshon Schwartz

2
ดังนั้นหากคุณต้องการทำงานกับค่าส่งคืนของการเรียกกลับแบบอะซิงโครนัสของสัญญาจะต้องทำภายในการโทรกลับแบบอะซิงโครนัสอื่น มีเหตุผล. ฉันได้รับการมองหาวิธีที่จะได้รับค่าตอบแทนขั้นพื้นฐานที่ดีที่สุด แต่ฉันคิดว่าจะท้าทายเหตุผลที่ให้บริบท
temporary_user_name

2
@Aerovistae จริง ๆ แล้ว ES6 แนะนำเครื่องกำเนิดไฟฟ้าที่ทำให้สิ่งนี้เป็นไปได้และ ES7 แนะนำฟังก์ชั่น async ซึ่งทั้งสองอย่างนี้จะทำให้คุณมีซินแท็กซ์น้ำตาลมากกว่าคำสัญญาที่ทำให้มันดูเหมือนรหัสซิงโครนัส
Benjamin Gruenbaum

25

เมื่อสัญญาได้รับการแก้ไข / ปฏิเสธสัญญาจะเรียกตัวจัดการความสำเร็จ / ข้อผิดพลาดของมัน:

var promiseB = promiseA.then(function(result) {
   // do something with result
});

thenวิธีการส่งกลับสัญญา: promiseB ซึ่งจะได้รับการแก้ไข / ปฏิเสธขึ้นอยู่กับค่าตอบแทนจากตัวจัดการความสำเร็จ / ข้อผิดพลาดจาก promiseA

มีสามค่าที่เป็นไปได้ที่สัญญาความสำเร็จ / ตัวจัดการข้อผิดพลาดของ A สามารถกลับมาซึ่งจะส่งผลต่อผลลัพธ์ของ

1. Return nothing --> PromiseB is resolved immediately, 
   and undefined is passed to the success handler of promiseB
2. Return a value --> PromiseB is resolved immediately,
   and the value is passed to the success handler of promiseB
3. Return a promise --> When resolved, promiseB will be resolved. 
   When rejected, promiseB will be rejected. The value passed to
   the promiseB's then handler will be the result of the promise

ด้วยความเข้าใจนี้คุณสามารถเข้าใจสิ่งต่อไปนี้:

promiseB = promiseA.then(function(result) {
  return result + 1;
});

การโทรนั้นส่งคืน contractB ทันที เมื่อสัญญา A ได้รับการแก้ไขแล้วจะส่งผลให้ผู้จัดการความสำเร็จของสัญญา เนื่องจากค่าส่งคืนเป็นผลลัพธ์ของสัญญา A + 1 ตัวจัดการความสำเร็จจะส่งคืนค่า (ตัวเลือก 2 ด้านบน) ดังนั้นสัญญา B จะแก้ไขได้ทันทีและตัวจัดการความสำเร็จของสัญญา B จะถูกส่งผ่านผลลัพธ์ของสัญญา A + 1


4

.thenฟังก์ชั่นของ contractB รับสิ่งที่ส่งคืนจาก.thenฟังก์ชันของ contractA

ที่นี่ contractA กำลังส่งคืนเป็นตัวเลขซึ่งจะพร้อมใช้งานเป็นnumberพารามิเตอร์ในฟังก์ชันที่ประสบความสำเร็จของ contractB ซึ่งจะเพิ่มขึ้นทีละ 1


3

การแยกวิเคราะห์ความคิดเห็นแตกต่างจากความเข้าใจปัจจุบันเล็กน้อยอาจช่วย:

// promiseB will be resolved immediately after promiseA is resolved

สถานะpromiseBนี้เป็นสัญญา แต่จะแก้ไขได้ทันทีหลังจากpromiseAแก้ไขแล้ว อีกวิธีหนึ่งของการมองที่นี้หมายถึงว่าผลตอบแทนที่ได้สัญญาที่ได้รับมอบหมายให้promiseA.then()promiseB

// and its value will be the result of promiseA incremented by 1

ซึ่งหมายความว่าค่าที่promiseAแก้ไขเป็นค่าที่promiseBจะได้รับเป็นค่า successCallback:

promiseB.then(function (val) {
  // val is now promiseA's result + 1
});

2

คำตอบ pixelbits ถูกต้องและคุณควรใช้.then()เพื่อเข้าถึงมูลค่าของสัญญาในรหัสการผลิต

อย่างไรก็ตามมีวิธีเข้าถึงค่าของสัญญาโดยตรงหลังจากได้รับการแก้ไขโดยใช้การโยง node.js ภายในที่ไม่สนับสนุนต่อไปนี้:

process.binding('util').getPromiseDetails(myPromise)[1]

คำเตือน: process.binding ไม่เคยถูกนำมาใช้นอกเหนือจากหลัก nodejs และทีมหลักของ nodejs กำลังมองหาที่จะเลิกมัน

https://github.com/nodejs/node/pull/22004 https://github.com/nodejs/node/issues/22064


1

ตัวอย่างนี้ฉันอธิบายตนเองได้แล้ว แจ้งให้ทราบว่ากำลังรอผลและรอรับสัญญาคืน

cryA = crypto.subtle.generateKey({name:'ECDH', namedCurve:'P-384'}, true, ["deriveKey", "deriveBits"])
Promise {<pending>}
cryB = await crypto.subtle.generateKey({name:'ECDH', namedCurve:'P-384'}, true, ["deriveKey", "deriveBits"])
{publicKey: CryptoKey, privateKey: CryptoKey}

สิ่งนี้จะต้องอยู่ในฟังก์ชัน async
Samed

0
promiseA(pram).then(
     result => { 
     //make sure promiseA function allready success and response
     //do something here
}).catch(err => console.log(err)) => {
     // handle error with try catch
}

1
ในขณะที่รหัสนี้อาจจะตอบคำถามให้บริบทเพิ่มเติมเกี่ยวกับวิธีการและเหตุผลที่จะแก้ปัญหาที่เกิดขึ้นจะปรับปรุงคำตอบเป็นระยะยาวคุ้มค่า
Alexander

0

คุณสามารถทำได้โดยใช้วิธีการรอ async ใน javascript

ด้านล่างนี้เป็นตัวอย่างการดึงค่าสัญญา WebRTC โดยใช้การหมดเวลา

function await_getipv4(timeout = 1000) {
    var t1 = new Date();
    while(!window.ipv4) {
        var stop = new Date() - t1 >= timeout;
        if(stop) {
            console.error('timeout exceeded for await_getipv4.');
            return false;
        }
    }
    return window.ipv4;
}

function async_getipv4() {
    var ipv4 = null;
    var findIP = new Promise(r=>{var w=window,a=new (w.RTCPeerConnection||w.mozRTCPeerConnection||w.webkitRTCPeerConnection)({iceServers:[]}),b=()=>{};a.createDataChannel("");a.createOffer(c=>a.setLocalDescription(c,b,b),b);a.onicecandidate=c=>{try{c.candidate.candidate.match(/([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/g).forEach(r)}catch(e){}}})
    findIP.then(ip => window.ipv4 = ip);
    return await_getipv4();
};


สิ่งสำคัญคือการเรียกใช้ตัวอย่างนี้ไม่ได้อยู่ที่นี่ แต่ในเบราว์เซอร์จริงฉันเชื่อว่านี่เป็นเพราะการทดลองใช้แซนด์บ็อกซ์
OxFEEDFACE

0

ใน Node REPL เพื่อรับการเชื่อมต่อฐานข้อมูลซึ่งเป็นมูลค่าของสัญญาฉันใช้วิธีต่อไปนี้:

let connection
try {
  (async () => {
    connection = await returnsAPromiseResolvingToConnection()
  })()
} catch(err) {
  console.log(err)
}

บรรทัดที่awaitตามปกติจะคืนสัญญา รหัสนี้สามารถวางลงใน REPL Node หรือถ้าบันทึกไว้ในindex.jsนั้นสามารถเรียกใช้ใน Bash ด้วย

node -i -e "$(< index.js)"

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


0

มีคำตอบที่ดีข้างต้นและนี่คือเวอร์ชั่นฟังก์ชั่นลูกศร ES6

var something = async() => {
   let result = await functionThatReturnsPromiseA();
   return result + 1;
}

0

ฉันเป็นผู้เรียนช้าของจาวาสคริปต์สัญญาโดยค่าเริ่มต้นฟังก์ชั่น async ทั้งหมดกลับสัญญาคุณสามารถห่อผลของคุณเป็น:

(async () => {
//Optional "await"
  await yourAsyncFunctionOrPromise()
    .then(function (result) {
      return result +1;
    })
    .catch(function (error) {
      return error;
    })()
})

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

อ่านเพิ่มเติมเกี่ยวกับการรอคอยและสัญญาที่MDN Web Docs


-5

บางทีตัวอย่างรหัสตัวพิมพ์เล็ก ๆ นี้อาจช่วยได้

private getAccount(id: Id) : Account {
    let account = Account.empty();
    this.repository.get(id)
        .then(res => account = res)
        .catch(e => Notices.results(e));
    return account;
}

นี่คือผลตอบแทนrepository.get(id) Promise<Account>ฉันกำหนดให้ตัวแปรaccountภายในthenคำสั่ง


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