2017-11-09 18 views
13

promiseを使用して関数の同期操作を実行したいとします。私はinsert関数に挿入されるデータを渡すループを持っていますし、1行を挿入した後、いいえをチェックしたいと思います。の行がテーブルに存在するので、私はselectの操作を実行しています。ループ内で約束を使用した順次呼び出し

しかし、3つのレコードがある場合は、3つのレコードがすべて挿入され、その後にselect関数が実行されるという問題があります。 1つのレコード選択関数の挿入が呼び出された後に私が望むものが得られます。ここ

は、コード全体としての私の擬似コードは、これは、非同期のインサートのシリーズを実行する、と仮定することによって引き起こされているなどの操作の多くは

for(var i=0; data.length ; i++){ 

self.executeFeedbackTrack(data); 

} 


executeFeedbackTrack:function(callInfo){ 
    var self=this; 
    return self.insertFeedbackTrack(callInfo).then(function(data){ 

       console.log("insertFeedbackTrack status "+status); 

     return self.getFeedbackTrack(); 

    }); 
}, 

getFeedbackTrack :function(){ 

    return new Promise(function(resolve,reject){ 
     var objDBFeedbackTrack = new DBFeedbackTrack(); 
     objDBFeedbackTrack.selectFeedbackTrack(function(arrayCallRegisters){ 
      if(arrayCallRegisters){ 

      console.log("notification.js no. of feedbacks "+arrayCallRegisters.length); 

      resolve(arrayCallRegisters.length); 

      } 

     }); 
    }); 


}, 
insertFeedbackTrack :function(callInfo){ 

return new Promise(function(resolve,reject){ 
    var objDBFeedbackTrack = new DBFeedbackTrack(); 
    objDBFeedbackTrack.insertFeedbackTrack(callInfo.callNumber,callInfo.callServiceType,function(status){ 

      resolve(status); 
      $('#loader').hide(); 

    }); 
}); 

} 
+0

回答を参照してください。 –

答えて

3

これは非常に便利なJSライブラリRamdaを使用して解決できます。概念は2つの方法を使用することです.1つはR.partialで、もう1つはR.pipePです。

まず、dataアレイから約束のアレイを作成します。次のようにします。

var promises = data.map(function(i) { 
    return R.partial(sample, [i]) 
}); 

それが次々に実行できるように、次にあなたは、R.pipePにこの約束を渡すことができます。以下のように。

var doOperation = R.pipeP.apply(this, promises) 

以下のスニペットを添付してください。

// Sample promise returning function 
 
function sample(d) { 
 
    return new Promise(function(resolve, reject){ 
 
    setTimeout(function() { 
 
     console.log('resolved for:' + d); 
 
     resolve(d); 
 
    }, 1000) 
 
    }) 
 
} 
 

 
// Sample data 
 
var data = [1, 2, 3, 4, 5] 
 

 
// Converting data array to promise array 
 
var promises = data.map(function(i) { 
 
    return R.partial(sample, [i]) 
 
}); 
 

 
var doOperation = R.pipeP.apply(this, promises) 
 
doOperation();
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

だからあなたの場合には、コードがこの

var promises = data.map(function(i) { 
    return R.partial(self.executeFeedbackTrack, [i]) 
}); 
var doOperation = R.pipeP.apply(this, promises) 
doOperation(); 
4

それは私には見える必要であることの内部insert nget.then())は、insert n+1が実行される前に呼び出されます。しかし、私はJavaScriptのような保証は認識していません。私がよく知っていることは、の前に呼び出されるのではなく、insert nの後にthen nが呼び出されるということです。

伝統的なコードとコールバックベースのコードが混在するのを避け、繰り返しのステップをgetFeedbackTrack().thenの内側に置くことをお勧めします。問題のこの理解と仮定すると正しい、次のようなものが動作するはずです:

function iterate(i) { 
    if (i < data.length) { 
     obj.insertFeedbackTrack(data[i]).then(function(insertResult) { 
      self.getFeedbackTrack().then(function(getResult) { 
       // this line is the important one, replacing the `for` loop earlier 
       iterate(i+1); 
      }); 
     }); 
    } 
} 

iterate(0); 

をそうすることによって、あなたは現在のselectが正常に実行されるまで、次の要素のためのinsertが発生しないことを保証します。

当然、ネストされている代わりにチェーン.thenを使用するように再構成することもできます。私はコールバックの順序を強調するためにチェーンではなくネストしていました。

+0

forループを再帰関数に置き換えようとしていますか? – Hunt

+0

もちろん、イベント/コールバックの特定の順序付けを強制するために、forループを 'then'コールバックの再帰的チェーンで置き換えてください。 –

+0

よくforループを変更するだけで多くの変更が必要ですが、回避策があります – Hunt

6

以前の回答は良いですが、nodejs、またはbabelを使用している場合、または最新のブラウザのみを使用している場合。あなたはasync-awaitペアを使うことができます。それはes8ものです。

let insertFeedbackTrack = function(){ return new Promise(/***/)}; 
let getFeedbackTrack = function(){ return new Promise(/***/)}; 
let processResult = async function(data){ 
    let feedbacks = []; 
    for(let i=0;i<data.length;i++){ 
     let insertedResult = await insertFeedbackTrack(data[i]);//perhaps you will return an id; 
     let feedbackTrack = await getFeedbackTrack(insertedResult.id); 
     feedbacks.push(feedbackTrack); 
    } 
    return feedbacks; 
} 

processResult(data).then(/** do stuff */) 
0

のようになります。ここで私は(私はES7を使用しています)ループのコール約束を順次しまう方法です。 まず、のは、いくつかの基本的なデータを定義してみましょう:いくつかの長い実行中のプロセスをシミュレートしてみましょう、そして、

const data = [0,1,2,3]; 

を、ので、あなたがシミュレートされたネットワーク要求と考えることができます(約束を返す関数を作成してみましょうか、どんなスーツあなたのニーズ)

const promiseExample = (item) => 
    new Promise((res) => { 
    setTimeout(() => { 
     console.log('resolved ', item); 
    res(item); 
    }, 1000); 
}); 

ここで、約束の配列を作成しましょう。次のコード行は、配列データ内のすべての項目に対して、約束のファクトリを返します。プロミスファクトリーは、それを実行せずにある約束をラップする関数です。

const funcs = data.map(item => async() => await promiseExample(item)); 

ここから実際のコードが始まります。実際のシリアライゼーションを行う関数が必要です。 promiseFactoryの配列を処理する必要があるため、私は1つの約束をシリアライズするための関数とpromiseFactoriesの配列を処理する関数の2つの関数に分割します。今

const serializePromise = promiseFactoryList => 
    promiseFactoryList.reduce(serialize, Promise.resolve([])); 

const serialize = async (promise, promiseFactory) => { 
    const promiseResult = await promise; 
    const res = await promiseFactory(); 
    return [...promiseResult, res]; 
}; 

、あなたは、単にこのようにそれを呼び出すことができます。

serializePromise(funcs).then(res => { 
    console.log('res', res); 
}); 

あなたが見ることができるように、コードはかなり、シンプルでエレガントな、機能的であり、かつ任意の外部依存関係を必要としません。私はこれがあなたの質問に答えることを願って、あなたを助けますジェネレータ機能を使用する場合、私は、このような場合の収量を使用

const serializePromise = promiseFactoryList => 
 
    promiseFactoryList.reduce(serialize, Promise.resolve([])); 
 

 
const serialize = async (promise, promiseFactory) => { 
 
    const promiseResult = await promise; 
 
    const res = await promiseFactory(); 
 
    return [...promiseResult, res]; 
 
}; 
 

 
const data = [0,1,2,3]; 
 

 
const promiseExample = (item) => 
 
    new Promise((res) => { 
 
\t setTimeout(() => { 
 
\t console.log('resolved ', item); 
 
\t res(item); 
 
    }, 1000); 
 
    }); 
 

 
const funcs = data.map(item => async() => await promiseExample(item)) 
 

 
serializePromise(funcs).then(res => { 
 
    console.log('res', res); 
 
});

+0

@Huntこれをチェックしてください:) –

1

for(var i = 0; i < order.tasks.length; i++){ 
     if(order.tasks[i].customer_id === 0){ 
      var name = order.tasks[i].customer_name.split(" ") 
      const customers = yield db.queryAsync(
      `INSERT INTO customers(
       business_id) 
      VALUES(?) 
      `,[order.business_id]) 
     } 
     } 

または、コールバックの場合は自己呼び出し機能を使用します。

var i = 0; 
(function loop() { 
    if (i < data.length) { 
     task_ids1.push([order.tasks[i].task_id]) 
     i++; 
     loop(); 
    } 
}()); 
関連する問題