สัญญาส่งพารามิเตอร์เพิ่มเติมไปที่โซ่แล้ว


101

คำสัญญาตัวอย่างเช่น:

var P = new Promise(function (resolve, reject) {
  var a = 5;
  if (a) {
    setTimeout(function(){
      resolve(a);
    }, 3000);
  } else {
    reject(a);
  }
});

หลังจากที่เราเรียก.then()วิธีการตามสัญญา:

P.then(doWork('text'));

จากนั้นdoWorkฟังก์ชันจะมีลักษณะดังนี้:

function doWork(data) {
  return function(text) {
    // sample function to console log
    consoleToLog(data);
    consoleToLog(b);
  }
}

ฉันจะหลีกเลี่ยงการส่งคืนฟังก์ชันภายในใน doWork เพื่อเข้าถึงข้อมูลจากพารามิเตอร์สัญญาและข้อความได้อย่างไร มีเทคนิคในการหลีกเลี่ยงฟังก์ชันด้านในหรือไม่?


1
ทำไมใคร ๆ ก็ละทิ้งแกงกะหรี่โดยเจตนา? เพื่อที่จะใช้bindวิธีน่าเกลียด? - ซึ่งช้ามากเช่นกัน

@ ถ้าฉันไม่เข้าใจคุณโปรดระบุรหัสเพื่อชี้แจงได้หรือไม่?
Roland

คำตอบ:


87

คุณสามารถใช้Function.prototype.bindเพื่อสร้างฟังก์ชันใหม่โดยส่งค่าไปยังอาร์กิวเมนต์แรกเช่นนี้

P.then(doWork.bind(null, 'text'))

และคุณสามารถเปลี่ยนdoWorkเป็น

function doWork(text, data) {
  consoleToLog(data);
}

ตอนนี้textจะเป็นจริง'text'ในdoWorkและdataจะได้รับค่าการแก้ไขโดยสัญญา

หมายเหตุ:โปรดตรวจสอบให้แน่ใจว่าคุณได้แนบเครื่องจัดการการปฏิเสธเข้ากับห่วงโซ่สัญญา


โปรแกรมการทำงาน: สำเนาสดใน REPL ของ Babel

function doWork(text, data) {
  console.log(text + data + text);
}

new Promise(function (resolve, reject) {
    var a = 5;
    if (a) {
      setTimeout(function () {
        resolve(a);
      }, 3000);
    } else {
      reject(a);
    }
  })
  .then(doWork.bind(null, 'text'))
  .catch(console.error);

ขอบคุณที่ช่วยก่อนหน้านี้ฉันลอง doWork.call (นี่คือ 'text') แต่ข้อมูลถูกแทนที่ด้วย 'text'
user3110667

2
callเรียกใช้ฟังก์ชันในสถานที่bindสร้างฟังก์ชันใหม่อย่างไรก็ตามทั้งสองยอมรับบริบทการดำเนินการเป็นอาร์กิวเมนต์แรก
sdgluck

103

บางทีคำตอบที่ตรงไปตรงมาที่สุดคือ:

P.then(function(data) { return doWork('text', data); });

หรือเนื่องจากสิ่งนี้ถูกแท็กecmascript-6โดยใช้ฟังก์ชันลูกศร:

P.then(data => doWork('text', data));

ฉันพบว่าสิ่งนี้อ่านง่ายที่สุดและไม่มากเกินไปที่จะเขียน


5

ใช้แกง.

var P = new Promise(function (resolve, reject) {
    var a = 5;
    if (a) {
        setTimeout(function(){
            resolve(a);
        }, 3000);
    } else {
        reject(a);
    }
});

var curriedDoWork = function(text) {
    return function(data) {
        console.log(data + text);
    }
};

P.then(curriedDoWork('text'))
.catch(
    //some error handling
);

ระวังสิ่งนี้ด้วยหากคุณสร้างcurriedDoWorkคำสัญญาโดยทำreturn new Promise()ในบรรทัดแรกของฟังก์ชันนี้คำสัญญาจะถูกดำเนินการทันทีที่คุณโทรcurriedDoWork()(เหมือนที่คุณทำใน..then(curriedDoWork('text'))
Flame

@ เปลวไฟ: คำตอบสั้น ๆ เพื่อความสะดวกของคุณคุณสามารถรวมคำสัญญาไว้ในฟังก์ชันได้หากต้องการทำเช่นนั้น
งอก

@yks คุณสามารถระบุไวยากรณ์นี้ได้ซึ่งค่อนข้างน่าสนใจ const curriedWork = text => data => console.log (data + text)
Germain

1
@germain อาใช่ฉันเคยเห็นแบบฟอร์มนี้มาก่อนต้องรักการเขียนโปรแกรมเชิงฟังก์ชัน อย่างไรก็ตามฉันพบว่าฟังก์ชันลูกศรพังในบางเบราว์เซอร์ดังนั้นฉันจึงมักจะหลีกเลี่ยงตอนนี้
yks

@yks มีเพียง Internet Explorer เท่านั้นที่ไม่รองรับและจะไม่มีเลยเนื่องจาก Edge ทำให้ Internet Explorer รุ่นล่าสุดคือวันที่ 9 ธันวาคม 2015 ไปต่อกัน ~
Germain

0

Lodash เสนอทางเลือกที่ดีสำหรับสิ่งที่แน่นอนนี้

 P.then(_.bind(doWork, 'myArgString', _));

 //Say the promise was fulfilled with the string 'promiseResults'

 function doWork(text, data) {
     console.log(text + " foo " + data);
     //myArgString foo promiseResults
 }

หรือหากคุณต้องการให้ฟังก์ชันความสำเร็จของคุณมีเพียงพารามิเตอร์เดียว (ผลลัพธ์ของคำสัญญาที่เป็นจริง) คุณสามารถใช้วิธีนี้:

P.then(_.bind(doWork, {text: 'myArgString'}));

function doWork(data) {
    console.log(data + " foo " + this.text);
    //promiseResults foo myArgString
}

สิ่งนี้จะแนบtext: 'myArgString'ไปกับthisบริบทภายในฟังก์ชัน


0

คำตอบใหม่สำหรับคำถามนี้คือการใช้ลูกศรฟังก์ชั่น(ซึ่งโดยอัตโนมัติผูกthisและอ่านได้มากขึ้น) Google สำหรับลิงค์ต่างๆเช่น https://2ality.com/2016/02/arrow-functions-vs-bind.html

คุณสามารถตั้งค่าข้อความเช่น:

this.text = 'text';
P.then(data => doWork(data));

หมายเหตุ: this.textภายในdoWorkจะประเมินเป็น "ข้อความ"

สิ่งนี้แนะนำโดย jib ด้านบนและ (หรือนี่!) ควรเป็นคำตอบที่ยอมรับได้ในขณะนี้

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