Có thể hứa hẹn có nhiều đối số để onFulfilling?


127

Tôi đang theo dõi thông số kỹ thuật ở đây và tôi không chắc liệu nó có cho phép onFulfill được gọi với nhiều đối số hay không. Ví dụ:

promise = new Promise(function(onFulfilled, onRejected){
    onFulfilled('arg1', 'arg2');
})

sao cho mã của tôi:

promise.then(function(arg1, arg2){
    // ....
});

sẽ nhận được cả hai arg1arg2?

Tôi không quan tâm đến việc thực hiện bất kỳ lời hứa cụ thể nào, tôi muốn theo dõi thông số w3c để biết các lời hứa chặt chẽ.


Như một gợi ý, tôi thấy rằng việc sử dụng github.com/then/promise (là một triển khai barebones) cho thấy rằng nó thực sự không cung cấp đối số thứ 2
badunk

2
Bạn muốn sử dụng Bluebird với .s lây lan. - Ngoài ra, ngừng quan tâm đến thông số kỹ thuật, thông số kỹ thuật là tất cả về sự xen kẽ giữa các triển khai và là tối thiểu theo thiết kế.
Benjamin Gruenbaum

Câu trả lời:


130

Tôi đang theo dõi thông số kỹ thuật ở đây và tôi không chắc liệu nó có cho phép onFulfill được gọi với nhiều đối số hay không.

Không, chỉ tham số đầu tiên sẽ được coi là giá trị độ phân giải trong hàm tạo hứa hẹn. Bạn có thể giải quyết với một giá trị tổng hợp như một đối tượng hoặc mảng.

Tôi không quan tâm đến việc thực hiện bất kỳ lời hứa cụ thể nào, tôi muốn theo dõi thông số w3c để biết các lời hứa chặt chẽ.

Đó là nơi tôi tin rằng bạn đã sai. Đặc tả được thiết kế tối thiểu và được xây dựng để tương tác giữa các thư viện hứa hẹn. Ý tưởng là có một tập hợp con mà DOM tương lai có thể sử dụng một cách đáng tin cậy và các thư viện có thể tiêu thụ. Hứa hẹn thực hiện những gì bạn yêu cầu .spreadtrong một thời gian bây giờ. Ví dụ:

Promise.try(function(){
    return ["Hello","World","!"];
}).spread(function(a,b,c){
    console.log(a,b+c); // "Hello World!";
});

Với Bluebird . Một giải pháp nếu bạn muốn chức năng này là polyfill nó.

if (!Promise.prototype.spread) {
    Promise.prototype.spread = function (fn) {
        return this.then(function (args) {
            return Promise.all(args); // wait for all
        }).then(function(args){
         //this is always undefined in A+ complaint, but just in case
            return fn.apply(this, args); 
        });
    };
}

Điều này cho phép bạn làm:

Promise.resolve(null).then(function(){
    return ["Hello","World","!"]; 
}).spread(function(a,b,c){
    console.log(a,b+c);    
});

Với lời hứa bản địa dễ dàng fiddle . Hoặc sử dụng mức độ phổ biến hiện nay (2018) trong các trình duyệt:

Promise.resolve(["Hello","World","!"]).then(([a,b,c]) => {
  console.log(a,b+c);    
});

Hoặc đang chờ:

let [a, b, c] = await Promise.resolve(['hello', 'world', '!']);

2
Lưu ý rằng các libaries khác (như Q) cũng hỗ trợ .spreadnhư Bluebird - lý do nó không có trong thông số kỹ thuật là việc giữ thông số tối thiểu thực sự là một vấn đề lớn để cho phép xen kẽ giữa mã và thư viện.
Benjamin Gruenbaum

Lưu ý thứ hai - bạn có thể muốn gọi Promise.alltrên mảng trước khi áp dụng chức năng thay vì chỉ sử dụng .thennó để xử lý một số thư viện đường cung cấp. Nó không bắt buộc, nhưng nó dễ thương.
Benjamin Gruenbaum

1
Promies.all là bắt buộc với việc triển khai của bạn, mặc dù bạn chỉ có thể thay đổi việc triển khai thànhreturn Promise.all(args).then(function(args){return fn.apply(this, args);})
Esailija

14
spreadlà một điểm dừng chân. ES6 giới thiệu việc phá hủy và toán tử nghỉ / trải, loại bỏ sự cần thiết phải spreadhoàn toàn. .then(([a, b, c]) => {})
Kris Kowal

3
@KrisKowal Lưu ý rằng .s lây lan () hoàn toàn không .all () nhưng cú pháp phá hủy ES6 không -> bluebirdjs.com/docs/api/s
lan.html

66

Bạn có thể sử dụng phá hủy E6:

Phá hủy đối tượng:

promise = new Promise(function(onFulfilled, onRejected){
    onFulfilled({arg1: value1, arg2: value2});
})

promise.then(({arg1, arg2}) => {
    // ....
});

Phá hủy mảng:

promise = new Promise(function(onFulfilled, onRejected){
    onFulfilled([value1, value2]);
})

promise.then(([arg1, arg2]) => {
    // ....
});

3
Một ví dụ sẽ rất hay và hữu ích với câu trả lời này!
Rahul Verma

19

Giá trị thực hiện của một lời hứa tương đương với giá trị trả về của hàm và lý do từ chối của một lời hứa tương đương với ngoại lệ được ném của hàm. Các hàm không thể trả về nhiều giá trị, vì vậy các lời hứa không được có nhiều hơn 1 giá trị thực hiện.


4

Theo như tôi có thể nói là đọc đặc tả Promise ES6đặc tả lời hứa tiêu chuẩn không có điều khoản nào ngăn cản việc triển khai xử lý trường hợp này - tuy nhiên nó không được triển khai trong các thư viện sau:

Tôi giả sử lý do khiến họ bỏ qua nhiều đối số phân giải là để làm cho việc thay đổi thứ tự ngắn gọn hơn (nghĩa là bạn chỉ có thể trả về một giá trị trong hàm, điều đó sẽ làm cho luồng điều khiển trở nên ít trực quan hơn) Ví dụ:

new Promise(function(resolve, reject) {
   return resolve(5, 4);
})
.then(function(x,y) {
   console.log(y);
   return x; //we can only return 1 value here so the next then will only have 1 argument
})
.then(function(x,y) {
    console.log(y);
});

8
Q không hỗ trợ độ phân giải đa giá trị vì các lời hứa đóng vai trò là proxy cho kết quả của một cuộc gọi chức năng nhưng cũng có thể ủy quyền cho các đối tượng từ xa. Trong cả hai trường hợp này, một mảng là đại diện hợp lý duy nhất của giá trị ghép. Với việc bổ sung các đối số phá hủy và lan truyền trên ES6 trong ES6, cú pháp trở nên rất hay. Phương pháp lan truyền trên mạng là một điểm dừng.
Kris Kowal

Chà, bạn luôn có thể return Promise.of(x, y)thay vì giá trị vô hướng từ cuộc thengọi lại.
Bergi

2

Đây là một giải pháp CoffeeScript.

Tôi đang tìm kiếm giải pháp tương tự và thấy có gì đó rất thú vị từ câu trả lời này: Từ chối lời hứa với nhiều đối số (như $ http) trong AngularJS

câu trả lời của anh chàng này Florian

promise = deferred.promise

promise.success = (fn) ->
  promise.then (data) ->
   fn(data.payload, data.status, {additional: 42})
  return promise

promise.error = (fn) ->
  promise.then null, (err) ->
    fn(err)
  return promise

return promise 

Và để sử dụng nó:

service.get().success (arg1, arg2, arg3) ->
    # => arg1 is data.payload, arg2 is data.status, arg3 is the additional object
service.get().error (err) ->
    # => err

Nên ->được =>?
SherylHohman

1
@SherylHohman Trở lại những ngày trong năm 2015, điều này đã được viết bằng CoffeeScript ( coffeescript.org/#int sinhtion ) chứ không phải cú pháp ES6. Mũi tên đơn giản là các chức năng đơn giản và mũi tên béo gần giống với ES6 (Tôi đoán mũi tên béo ES6 đã được mượn ít nhiều từ CoffeScript).
Val Entin

@SherylHohman Hãy thoải mái chỉnh sửa bài đăng trong ECMA nếu bạn muốn.
Val Entin

Cám ơn phản hồi của bạn. Tôi sẽ chỉ chỉnh sửa để làm rõ rằng đây là một giải pháp kịch bản cà phê. Cùng với đó, câu trả lời của bạn là & có thể hữu ích cho các cơ sở mã CoffeeScript. Tuy nhiên, cảm ơn lời đề nghị chỉnh sửa của bạn: 1) Tôi không đủ quen thuộc với CoffeeScript để mạo hiểm chỉnh sửa / phá vỡ giải pháp của bạn ;-). 2) Dịch mã của bạn sang JS hiện đại nên được coi là sai lệch so với "mục đích ban đầu của Câu trả lời của bạn", do đó không nên vượt qua Đánh giá 'chỉnh sửa'. Thay vào đó, ai đó có thể đăng Câu trả lời mới, nếu nghiêng, dịch mã của bạn. Lý tưởng nhất là họ sẽ liên kết lại với câu trả lời của bạn như nguồn cảm hứng của họ :-)
SherylHohman

0

Câu hỏi tuyệt vời, và câu trả lời tuyệt vời của Benjamin, Kris, et al - cảm ơn rất nhiều!

Tôi đang sử dụng điều này trong một dự án và đã tạo ra một mô-đun dựa trên mã của Benjamin Gruenwald . Nó có sẵn trên npmjs:

npm i -S promise-spread

Sau đó, trong mã của bạn, làm

require('promise-spread');

Nếu bạn đang sử dụng một thư viện như any-promise

var Promise = require('any-promise');
require('promise-spread')(Promise);

Có lẽ những người khác cũng thấy điều này hữu ích!


0

Phân công lại cấu trúc trong ES6 sẽ giúp ở đây. Ví dụ:

let [arg1, arg2] = new Promise((resolve, reject) => {
    resolve([argument1, argument2]);
});

0

Vì các hàm trong Javascript có thể được gọi với bất kỳ số lượng đối số nào và tài liệu không đặt ra bất kỳ hạn chế nào đối với các onFulfilled()đối số của phương thức bên cạnh mệnh đề dưới đây, tôi nghĩ rằng bạn có thể truyền nhiều đối số cho onFulfilled()phương thức miễn là giá trị của lời hứa là đối số đầu tiên.

2.2.2.1 nó phải được gọi sau khi lời hứa được thực hiện, với giá trị của lời hứa là đối số đầu tiên.


-1

Để trích dẫn bài viết dưới đây, "" sau đó "lấy hai đối số, gọi lại cho trường hợp thành công và một đối số cho trường hợp thất bại. Cả hai đều là tùy chọn, vì vậy bạn chỉ có thể thêm một cuộc gọi lại cho trường hợp thành công hoặc thất bại."

Tôi thường tìm đến trang này cho bất kỳ câu hỏi hứa hẹn cơ bản nào, cho tôi biết nếu tôi sai

http://www.html5rocks.com/en/tutorials/es6/promises/


1
Đó là không chính xác, new Promisecó cú pháp function(resolve, error)trong khi thencó cú pháp.then(function(arg) {
megawac

2
@megawac thực sự đúng chỉ là đặt sai - sau đó chấp nhận hai (đôi khi 3) đối số - nó khá là không phổ biến
Benjamin Gruenbaum

@BenjaminGruenbaum afaik của nó.then(function(/*resolve args*/){/*resolve handler*/}, function(/*reject args*/){/*reject handler*/})
megawac

2
Có, nếu bạn đọc kỹ, đó là những gì câu trả lời này đang khẳng định - không hữu ích lắm trong bối cảnh của câu hỏi này nhưng không sai.
Benjamin Gruenbaum
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.