Làm thế nào để truy cập giá trị của một lời hứa?


146

Tôi đang xem ví dụ này từ các tài liệu của Angular $qnhưng tôi nghĩ rằng điều này có thể áp dụng cho các lời hứa nói chung. Ví dụ dưới đây được sao chép nguyên văn từ tài liệu của họ với nhận xét của họ bao gồm:

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

Tôi không rõ làm thế nào điều này hoạt động. Nếu tôi có thể gọi .then()kết quả của lần đầu tiên .then(), xâu chuỗi chúng, mà tôi biết tôi có thể, thì đó promiseBlà một đối tượng hứa hẹn, thuộc loại Object. Nó không phải là một Number. Vậy ý nghĩa của "giá trị của nó sẽ là kết quả của lời hứaA tăng thêm 1"?

Tôi có nên truy cập như vậy promiseB.valuehoặc một cái gì đó như thế? Làm thế nào để gọi lại thành công có thể trả lại một lời hứa VÀ trả về "kết quả + 1"? Tôi đang thiếu một cái gì đó.


Tôi đã hỏi một câu hỏi liên quan: Tại sao Promise không có hàm get ()?
Roland


Câu hỏi này đã được 5 tuổi và có câu trả lời được chấp nhận ...
tạm

@t tạm_user_name: mọi người có thể bỏ phiếu chặt chẽ bất cứ lúc nào, ngay cả đối với các câu hỏi cũ.
halfer

Câu trả lời:


140

promiseA's thenhàm trả về một lời hứa mới ( promiseB) được ngay lập tức giải quyết sau khi promiseAđã được giải quyết, giá trị của nó là giá trị của những gì được trả về từ hàm thành công trong vòng promiseA.

Trong trường hợp promiseAnày được giải quyết bằng một giá trị - resultvà sau đó giải quyết ngay lập tức promiseBvới giá trị của result + 1.

Truy cập giá trị của promiseBđược thực hiện giống như cách chúng ta truy cập kết quả của promiseA.

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

Chỉnh sửa tháng 12 năm 2019 : async/ awaithiện là tiêu chuẩn trong JS, cho phép một cú pháp thay thế cho cách tiếp cận được mô tả ở trên. Bây giờ bạn có thể viết:

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

Bây giờ không có lời hứa, vì chúng tôi đã hủy kết quả từ lời hứa bằng cách sử dụng awaitvà bạn có thể làm việc trực tiếp với nó.

Tuy nhiên, awaitchỉ có thể được sử dụng bên trong một asyncchức năng. Vì vậy, để thu nhỏ một chút, ở trên sẽ phải được chứa như vậy:

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

2
Về mặt lý thuyết là những đối tượng của riêng họ. chúng chứa một kết quả có thể được truy cập thông qua chức năng thành công của lời hứa.
Nachshon Schwartz

2
Vì vậy, nếu bạn muốn làm việc với giá trị trả về của cuộc gọi lại không đồng bộ của một lời hứa, thì nó phải được thực hiện bên trong một cuộc gọi lại không đồng bộ khác. Có ý nghĩa. Tôi đã tìm kiếm một cách để có được giá trị hoàn trả nguyên thủy cuối cùng nhưng tôi cho rằng điều đó sẽ bất chấp lý do đưa ra bối cảnh.
tạm

2
@Aerovistae thực sự, ES6 giới thiệu các trình tạo khả năng này và ES7 giới thiệu các hàm async - cả hai đều cung cấp cho bạn cú pháp đường qua các lời hứa làm cho nó trông giống như mã đồng bộ (bằng cách chạy một máy trạng thái trong nền) - vì vậy hãy giữ chặt :)
Benjamin Gruenbaum

25

Khi một lời hứa được giải quyết / từ chối, nó sẽ gọi trình xử lý thành công / lỗi của nó:

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

Các thenphương pháp cũng trả về một lời hứa: promiseB, mà sẽ được giải quyết / bị từ chối tùy thuộc vào giá trị trả về từ xử lý thành công / lỗi từ promiseA .

Có ba giá trị có thể mà trình xử lý thành công / lỗi của PromA có thể trả về sẽ ảnh hưởng đến kết quả của PromB:

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

Với sự hiểu biết này, bạn có thể hiểu được những điều sau đây:

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

Cuộc gọi sau đó trả về lời hứaB ngay lập tức. Khi lời hứa được giải quyết, nó sẽ chuyển kết quả cho người xử lý thành công của lời hứa. Vì giá trị trả về là kết quả của hứa hẹn + 1, nên trình xử lý thành công sẽ trả về một giá trị (tùy chọn 2 ở trên), do đó, PromB sẽ giải quyết ngay lập tức và trình xử lý thành công của PromB sẽ được thông qua kết quả hứa hẹn + 1.


4

.thenchức năng của PromB nhận được những gì được trả về từ .thenchức năng của PromA.

Ở đây, PromA trở lại là một số, sẽ có sẵn dưới dạng numbertham số trong hàm thành công của PromB. sau đó sẽ được tăng thêm 1


3

Phân tích nhận xét khác một chút so với hiểu biết hiện tại của bạn có thể giúp:

// promiseB will be resolved immediately after promiseA is resolved

Điều này nói rằng đó promiseBlà một lời hứa nhưng sẽ được giải quyết ngay sau khi promiseAđược giải quyết. Một cách khác để xem xét điều này có nghĩa là promiseA.then()trả lại một lời hứa được chỉ định promiseB.

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

Điều này có nghĩa là giá trị promiseAđược giải quyết là giá trị promiseBsẽ nhận làm giá trị thành công của nó:

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

2

câu trả lời pixelbits là chính xác và bạn nên luôn luôn sử dụng .then()để truy cập giá trị của một lời hứa trong mã sản xuất.

Tuy nhiên, có một cách để truy cập trực tiếp vào giá trị của lời hứa sau khi nó đã được giải quyết bằng cách sử dụng ràng buộc node.js nội bộ không được hỗ trợ sau đây:

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

CẢNH BÁO: process.binding không bao giờ được sử dụng bên ngoài lõi của nodejs và nhóm lõi của nodejs đang tích cực tìm cách loại bỏ nó

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


1

Ví dụ này tôi thấy tự giải thích. Lưu ý cách chờ đợi kết quả và vì vậy bạn bỏ lỡ Lời hứa được trả lại.

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}

Điều này phải có trong một chức năng không đồng bộ.
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
Mặc dù mã này có thể trả lời câu hỏi, việc cung cấp ngữ cảnh bổ sung về cách thứclý do giải quyết vấn đề sẽ cải thiện giá trị lâu dài của câu trả lời.
Alexander

0

Bạn có thể dễ dàng làm điều đó bằng cách sử dụng phương thức chờ async trong javascript.

Dưới đây là một ví dụ lấy giá trị lời hứa WebRTC bằng cách sử dụng thời gian chờ.

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();
};


Điều quan trọng là chạy đoạn mã này không phải ở đây nhưng trong một trình duyệt thực sự, tôi tin rằng điều này là do hộp cát.
OxFEEDFACE

0

Trong REPL của Node, để có được kết nối DB là giá trị của một lời hứa, tôi đã thực hiện theo cách tiếp cận sau:

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

Các dòng với awaitthường sẽ trả lại một lời hứa. Mã này có thể được dán vào Node REPL hoặc nếu được lưu trong index.jsnó có thể được chạy trong Bash với

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

để lại cho bạn trong REPL nút sau khi chạy tập lệnh có quyền truy cập vào biến đã đặt. Để xác nhận rằng hàm không đồng bộ đã trả về, bạn có thể đăng nhập connectionchẳng hạn, và sau đó bạn đã sẵn sàng sử dụng biến. Tất nhiên, một người sẽ không muốn dựa vào chức năng không đồng bộ đang được giải quyết đối với bất kỳ mã nào trong tập lệnh bên ngoài chức năng không đồng bộ.


0

Có một số câu trả lời tốt ở trên và đây là phiên bản chức năng Mũi tên ES6

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

0

Tôi là người học chậm về các lời hứa javascript, theo mặc định, tất cả các hàm async trả lại một lời hứa, bạn có thể gói kết quả của mình dưới dạng:

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

" Biểu thức chờ đợi khiến cho việc thực thi chức năng async tạm dừng cho đến khi một Promise được giải quyết (nghĩa là đã hoàn thành hoặc bị từ chối) và tiếp tục thực hiện chức năng async sau khi hoàn thành. Khi được tiếp tục, giá trị của biểu thức chờ đợi là giá trị của Promise . Nếu Lời hứa bị từ chối, biểu thức chờ đợi sẽ ném giá trị bị từ chối . "

Đọc thêm về chờ đợihứa hẹn tại MDN Web Docs


-5

Có lẽ ví dụ mã typecript nhỏ này sẽ giúp ích.

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

Ở đây repository.get(id)trả về a Promise<Account>. Tôi gán nó cho biến accounttrong thencâu lệnh.


1
Mã của bạn đang trả lại tài khoản trước khi quảng cáo có thể được giải quyết và đây là lý do khiến nó bị bỏ phiếu, mã của bạn luôn trả về Account.empty ();
Felype
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.